if_bwn.c revision 300292
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 300292 2016-05-20 08:58:06Z avos $");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37299985Sadrian#include "opt_bwn.h"
38299985Sadrian#include "opt_wlan.h"
39299985Sadrian
40203945Sweongyo#include <sys/param.h>
41203945Sweongyo#include <sys/systm.h>
42295126Sglebius#include <sys/kernel.h>
43295126Sglebius#include <sys/malloc.h>
44203945Sweongyo#include <sys/module.h>
45203945Sweongyo#include <sys/endian.h>
46203945Sweongyo#include <sys/errno.h>
47203945Sweongyo#include <sys/firmware.h>
48203945Sweongyo#include <sys/lock.h>
49203945Sweongyo#include <sys/mutex.h>
50203945Sweongyo#include <machine/bus.h>
51203945Sweongyo#include <machine/resource.h>
52203945Sweongyo#include <sys/bus.h>
53203945Sweongyo#include <sys/rman.h>
54203945Sweongyo#include <sys/socket.h>
55203945Sweongyo#include <sys/sockio.h>
56203945Sweongyo
57203945Sweongyo#include <net/ethernet.h>
58203945Sweongyo#include <net/if.h>
59257176Sglebius#include <net/if_var.h>
60203945Sweongyo#include <net/if_arp.h>
61203945Sweongyo#include <net/if_dl.h>
62203945Sweongyo#include <net/if_llc.h>
63203945Sweongyo#include <net/if_media.h>
64203945Sweongyo#include <net/if_types.h>
65203945Sweongyo
66203945Sweongyo#include <dev/pci/pcivar.h>
67203945Sweongyo#include <dev/pci/pcireg.h>
68203945Sweongyo#include <dev/siba/siba_ids.h>
69203945Sweongyo#include <dev/siba/sibareg.h>
70203945Sweongyo#include <dev/siba/sibavar.h>
71203945Sweongyo
72203945Sweongyo#include <net80211/ieee80211_var.h>
73203945Sweongyo#include <net80211/ieee80211_radiotap.h>
74203945Sweongyo#include <net80211/ieee80211_regdomain.h>
75203945Sweongyo#include <net80211/ieee80211_phy.h>
76206358Srpaulo#include <net80211/ieee80211_ratectl.h>
77203945Sweongyo
78203945Sweongyo#include <dev/bwn/if_bwnreg.h>
79203945Sweongyo#include <dev/bwn/if_bwnvar.h>
80203945Sweongyo
81298948Sadrian#include <dev/bwn/if_bwn_debug.h>
82298944Sadrian#include <dev/bwn/if_bwn_misc.h>
83299776Sadrian#include <dev/bwn/if_bwn_util.h>
84299776Sadrian#include <dev/bwn/if_bwn_phy_common.h>
85298948Sadrian#include <dev/bwn/if_bwn_phy_g.h>
86298944Sadrian#include <dev/bwn/if_bwn_phy_lp.h>
87300019Sadrian#include <dev/bwn/if_bwn_phy_n.h>
88298944Sadrian
89227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0,
90227309Sed    "Broadcom driver parameters");
91203945Sweongyo
92203945Sweongyo/*
93203945Sweongyo * Tunable & sysctl variables.
94203945Sweongyo */
95203945Sweongyo
96203945Sweongyo#ifdef BWN_DEBUG
97203945Sweongyostatic	int bwn_debug = 0;
98267992ShselaskySYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0,
99203945Sweongyo    "Broadcom debugging printfs");
100203945Sweongyo#endif
101203945Sweongyo
102203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
103203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
104203945Sweongyo    "uses Bad Frames Preemption");
105203945Sweongyostatic int	bwn_bluetooth = 1;
106203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
107203945Sweongyo    "turns on Bluetooth Coexistence");
108203945Sweongyostatic int	bwn_hwpctl = 0;
109203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
110203945Sweongyo    "uses H/W power control");
111203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
112203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
113203945Sweongyostatic int	bwn_usedma = 1;
114203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
115203945Sweongyo    "uses DMA");
116203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
117203945Sweongyostatic int	bwn_wme = 1;
118203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
119203945Sweongyo    "uses WME support");
120203945Sweongyo
121287197Sglebiusstatic void	bwn_attach_pre(struct bwn_softc *);
122203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
123204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
124287197Sglebiusstatic int	bwn_init(struct bwn_softc *);
125287197Sglebiusstatic void	bwn_parent(struct ieee80211com *);
126287197Sglebiusstatic void	bwn_start(struct bwn_softc *);
127287197Sglebiusstatic int	bwn_transmit(struct ieee80211com *, struct mbuf *);
128203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
129203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
130203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
131203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
132203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
133203945Sweongyo		    uint16_t);
134203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
135299982Sadrian		    const struct bwn_channelinfo *, const uint8_t []);
136203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
137203945Sweongyo		    const struct ieee80211_bpf_params *);
138283540Sglebiusstatic void	bwn_updateslot(struct ieee80211com *);
139283540Sglebiusstatic void	bwn_update_promisc(struct ieee80211com *);
140203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
141203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
142203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
143203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
144203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
145203945Sweongyo		    const struct wmeParams *, uint16_t);
146203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
147203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
148203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
149203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
150228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
151228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
152203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
153203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
154287197Sglebiusstatic void	bwn_stop(struct bwn_softc *);
155203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
156203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
157203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
158203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
159203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
160203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
161203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
162203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
163203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
164203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
165203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
166203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
167203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
168203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
169203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
170203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
171203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
172203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
173203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
174203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
175203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
176203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
177203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
178203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
179203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
180203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
181203945Sweongyo		    int);
182203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
183203945Sweongyo		    struct bwn_pio_rxqueue *, int);
184203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
185203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
186203945Sweongyo		    uint16_t);
187203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
188203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
189203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
190203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
191203945Sweongyo		    const struct bwn_txstatus *);
192203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
193203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
194203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
195203945Sweongyo		    uint16_t);
196203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
197203945Sweongyo		    uint32_t);
198203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
199203945Sweongyo		    struct mbuf *);
200203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
201203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
202203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
203203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
204203945Sweongyo		    uint16_t, uint32_t);
205203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
206203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
207203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
208203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
209203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
210203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
211203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
212203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
213203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
214203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
215203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
216203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
217203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
218203945Sweongyo		    int, struct bwn_dmadesc_generic **,
219203945Sweongyo		    struct bwn_dmadesc_meta **);
220203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
221203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
222203945Sweongyo		    int, int);
223203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
224203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
225203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
226203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
227203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
228203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
229203945Sweongyo		    int, struct bwn_dmadesc_generic **,
230203945Sweongyo		    struct bwn_dmadesc_meta **);
231203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
232203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
233203945Sweongyo		    int, int);
234203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
235203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
236203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
237203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
238203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
239203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
240203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
241203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
242203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
243203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
244203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
245203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
246203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
247203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
248203945Sweongyo		    struct bwn_dmadesc_meta *);
249203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
250203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
251203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
252203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
253203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
254203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
255203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
256203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
257203945Sweongyo		    int);
258203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
259203945Sweongyo		    bus_size_t, int);
260203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
261203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
262203945Sweongyo		    const struct bwn_txstatus *);
263203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
264203945Sweongyo		    struct mbuf *);
265203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
266203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
267203945Sweongyo		    uint8_t);
268203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
269203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
270203945Sweongyo		    int, int, int);
271203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
272203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
273203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
274203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
275203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
276203945Sweongyo		    const char *, struct bwn_fwfile *);
277203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
278203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
279203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
280203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
281203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
282203945Sweongyostatic uint16_t	bwn_ant2phy(int);
283203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
284203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
285203945Sweongyo		    const uint8_t *);
286203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
287203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
288203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
289203945Sweongyo		    const uint8_t *);
290203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
291203945Sweongyo		    const uint8_t *);
292203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
293203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
294203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
295203945Sweongyo		    struct ieee80211_channel *);
296203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
297203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
298203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
299203945Sweongyostatic int	bwn_intr(void *);
300203945Sweongyostatic void	bwn_intrtask(void *, int);
301203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
302203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
303203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
304203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
305203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
306203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
307203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
308203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
309203945Sweongyostatic void	bwn_hwreset(void *, int);
310203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
311203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
312203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
313203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
314203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
315203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
316203945Sweongyo		    const struct bwn_txstatus *);
317203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
318203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
319203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
320203945Sweongyo		    struct mbuf *);
321203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
322203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
323203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
324203945Sweongyo		    uint16_t);
325203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
326203945Sweongyo		    const uint8_t);
327203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
328203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
329203945Sweongyostatic void	bwn_txpwr(void *, int);
330203945Sweongyostatic void	bwn_tasks(void *);
331203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
332203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
333203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
334203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
335203945Sweongyo		    uint8_t);
336203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
337203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
338203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
339203945Sweongyo		    int, int);
340203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
341203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
342203945Sweongyostatic void	bwn_watchdog(void *);
343203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
344203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
345203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
346203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
347203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
348203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
349203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
350203945Sweongyostatic void	bwn_led_blink_next(void *);
351203945Sweongyostatic void	bwn_led_blink_end(void *);
352203945Sweongyostatic void	bwn_rfswitch(void *);
353203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
354203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
355204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
356203945Sweongyo
357203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
358203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
359203945Sweongyo	{ -1,			0,		0 }
360203945Sweongyo};
361203945Sweongyo
362203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
363203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
364203945Sweongyo	{ -1,			0,		0 }
365203945Sweongyo};
366203945Sweongyo
367203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
368203945Sweongyo	.channels = {
369203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
370203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
371203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
372203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
373203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
374203945Sweongyo	.nchannels = 14
375203945Sweongyo};
376203945Sweongyo
377203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
378203945Sweongyo	.channels = {
379203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
380203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
381203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
382203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
383203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
384203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
385203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
386203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
387203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
388203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
389203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
390203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
391203945Sweongyo		{ 6080, 216, 30 } },
392203945Sweongyo	.nchannels = 37
393203945Sweongyo};
394203945Sweongyo
395299800Sadrian#if 0
396203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
397203945Sweongyo	.channels = {
398203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
399203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
400203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
401203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
402203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
403203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
404203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
405203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
406203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
407203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
408203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
409203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
410203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
411203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
412203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
413203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
414203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
415203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
416203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
417203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
418203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
419203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
420203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
421203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
422203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
423203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
424203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
425203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
426203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
427203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
428203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
429203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
430203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
431203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
432203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
433203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
434203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
435203945Sweongyo	.nchannels = 110
436203945Sweongyo};
437299800Sadrian#endif
438203945Sweongyo
439203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
440203945Sweongyo{							\
441203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
442203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
443203945Sweongyo}
444203945Sweongyo
445203945Sweongyostatic const struct {
446203945Sweongyo	uint16_t	vid;
447203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
448203945Sweongyo} bwn_vendor_led_act[] = {
449203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
450203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
451203945Sweongyo};
452203945Sweongyo
453203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
454203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
455203945Sweongyo
456203945Sweongyo#undef VENDOR_LED_ACT
457203945Sweongyo
458203945Sweongyostatic const struct {
459203945Sweongyo	int		on_dur;
460203945Sweongyo	int		off_dur;
461203945Sweongyo} bwn_led_duration[109] = {
462203945Sweongyo	[0]	= { 400, 100 },
463203945Sweongyo	[2]	= { 150, 75 },
464203945Sweongyo	[4]	= { 90, 45 },
465203945Sweongyo	[11]	= { 66, 34 },
466203945Sweongyo	[12]	= { 53, 26 },
467203945Sweongyo	[18]	= { 42, 21 },
468203945Sweongyo	[22]	= { 35, 17 },
469203945Sweongyo	[24]	= { 32, 16 },
470203945Sweongyo	[36]	= { 21, 10 },
471203945Sweongyo	[48]	= { 16, 8 },
472203945Sweongyo	[72]	= { 11, 5 },
473203945Sweongyo	[96]	= { 9, 4 },
474203945Sweongyo	[108]	= { 7, 3 }
475203945Sweongyo};
476203945Sweongyo
477203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
478203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
479203945Sweongyo	[1] = BWN_WME_BACKGROUND,
480203945Sweongyo	[2] = BWN_WME_VOICE,
481203945Sweongyo	[3] = BWN_WME_VIDEO,
482203945Sweongyo};
483203945Sweongyo
484203945Sweongyostatic const struct siba_devid bwn_devs[] = {
485203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
486203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
487203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
488203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
489203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
490203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
491299801Sadrian	SIBA_DEV(BROADCOM, 80211, 12, "Revision 12"),
492203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
493203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
494203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
495203945Sweongyo};
496203945Sweongyo
497203945Sweongyostatic int
498203945Sweongyobwn_probe(device_t dev)
499203945Sweongyo{
500203945Sweongyo	int i;
501203945Sweongyo
502298307Spfg	for (i = 0; i < nitems(bwn_devs); i++) {
503204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
504204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
505204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
506203945Sweongyo			return (BUS_PROBE_DEFAULT);
507203945Sweongyo	}
508203945Sweongyo
509203945Sweongyo	return (ENXIO);
510203945Sweongyo}
511203945Sweongyo
512203945Sweongyostatic int
513203945Sweongyobwn_attach(device_t dev)
514203945Sweongyo{
515203945Sweongyo	struct bwn_mac *mac;
516203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
517203945Sweongyo	int error, i, msic, reg;
518203945Sweongyo
519203945Sweongyo	sc->sc_dev = dev;
520203945Sweongyo#ifdef BWN_DEBUG
521203945Sweongyo	sc->sc_debug = bwn_debug;
522203945Sweongyo#endif
523203945Sweongyo
524203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
525287197Sglebius		bwn_attach_pre(sc);
526204922Sweongyo		bwn_sprom_bugfixes(dev);
527203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
528203945Sweongyo	}
529203945Sweongyo
530203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
531204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
532204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
533204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
534203945Sweongyo			device_printf(sc->sc_dev,
535203945Sweongyo			    "skip 802.11 cores\n");
536203945Sweongyo			return (ENODEV);
537203945Sweongyo		}
538203945Sweongyo	}
539203945Sweongyo
540287197Sglebius	mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO);
541203945Sweongyo	mac->mac_sc = sc;
542203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
543203945Sweongyo	if (bwn_bfp != 0)
544203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
545203945Sweongyo
546203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
547203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
548203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
549203945Sweongyo
550203945Sweongyo	error = bwn_attach_core(mac);
551203945Sweongyo	if (error)
552203945Sweongyo		goto fail0;
553203945Sweongyo	bwn_led_attach(mac);
554203945Sweongyo
555203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
556203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
557204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
558203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
559203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
560203945Sweongyo	    mac->mac_phy.rf_rev);
561203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
562203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
563203945Sweongyo		    mac->mac_method.dma.dmatype);
564203945Sweongyo	else
565203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
566203945Sweongyo
567300076Sadrian#ifdef	BWN_GPL_PHY
568300076Sadrian	device_printf(sc->sc_dev,
569300076Sadrian	    "Note: compiled with BWN_GPL_PHY; includes GPLv2 code\n");
570300076Sadrian#endif
571300076Sadrian
572203945Sweongyo	/*
573203945Sweongyo	 * setup PCI resources and interrupt.
574203945Sweongyo	 */
575219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
576203945Sweongyo		msic = pci_msi_count(dev);
577203945Sweongyo		if (bootverbose)
578203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
579203945Sweongyo	} else
580203945Sweongyo		msic = 0;
581203945Sweongyo
582203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
583203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
584203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
585203945Sweongyo			device_printf(sc->sc_dev,
586203945Sweongyo			    "Using %d MSI messages\n", msic);
587203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
588203945Sweongyo			mac->mac_msi = 1;
589203945Sweongyo		}
590203945Sweongyo	}
591203945Sweongyo
592203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
593203945Sweongyo	    mac->mac_res_irq);
594203945Sweongyo	if (error) {
595203945Sweongyo		device_printf(sc->sc_dev,
596203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
597203945Sweongyo		goto fail1;
598203945Sweongyo	}
599203945Sweongyo
600203945Sweongyo	if (mac->mac_msi == 0)
601203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
602203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
603203945Sweongyo		    &mac->mac_intrhand[0]);
604203945Sweongyo	else {
605203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
606203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
607203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
608203945Sweongyo			    &mac->mac_intrhand[i]);
609203945Sweongyo			if (error != 0) {
610203945Sweongyo				device_printf(sc->sc_dev,
611203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
612203945Sweongyo				break;
613203945Sweongyo			}
614203945Sweongyo		}
615203945Sweongyo	}
616203945Sweongyo
617203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
618203945Sweongyo
619203945Sweongyo	/*
620203945Sweongyo	 * calls attach-post routine
621203945Sweongyo	 */
622203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
623203945Sweongyo		bwn_attach_post(sc);
624203945Sweongyo
625203945Sweongyo	return (0);
626203945Sweongyofail1:
627203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
628203945Sweongyo		pci_release_msi(dev);
629203945Sweongyofail0:
630203945Sweongyo	free(mac, M_DEVBUF);
631203945Sweongyo	return (error);
632203945Sweongyo}
633203945Sweongyo
634203945Sweongyostatic int
635203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
636203945Sweongyo{
637203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
638203945Sweongyo
639203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
640203945Sweongyo		return (FALSE);
641203945Sweongyo
642203945Sweongyo	return (TRUE);
643203945Sweongyo}
644203945Sweongyo
645203945Sweongyostatic int
646203945Sweongyobwn_attach_post(struct bwn_softc *sc)
647203945Sweongyo{
648287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
649203945Sweongyo
650283537Sglebius	ic->ic_softc = sc;
651283527Sglebius	ic->ic_name = device_get_nameunit(sc->sc_dev);
652203945Sweongyo	/* XXX not right but it's not used anywhere important */
653203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
654203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
655203945Sweongyo	ic->ic_caps =
656203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
657203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
658204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
659203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
660203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
661203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
662203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
663299773Sadrian#if 0
664203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
665299773Sadrian#endif
666203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
667203945Sweongyo		;
668203945Sweongyo
669205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
670205141Sweongyo
671287197Sglebius	IEEE80211_ADDR_COPY(ic->ic_macaddr,
672204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
673204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
674204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
675203945Sweongyo
676287197Sglebius	/* call MI attach routine. */
677287197Sglebius	ieee80211_ifattach(ic);
678287197Sglebius
679203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
680203945Sweongyo
681203945Sweongyo	/* override default methods */
682203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
683203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
684203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
685203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
686203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
687203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
688203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
689203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
690203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
691287197Sglebius	ic->ic_transmit = bwn_transmit;
692287197Sglebius	ic->ic_parent = bwn_parent;
693203945Sweongyo
694203945Sweongyo	ieee80211_radiotap_attach(ic,
695203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
696203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
697203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
698203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
699203945Sweongyo
700204257Sweongyo	bwn_sysctl_node(sc);
701203945Sweongyo
702203945Sweongyo	if (bootverbose)
703203945Sweongyo		ieee80211_announce(ic);
704203945Sweongyo	return (0);
705203945Sweongyo}
706203945Sweongyo
707203945Sweongyostatic void
708203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
709203945Sweongyo{
710203945Sweongyo
711203945Sweongyo	if (mac->mac_phy.detach != NULL)
712203945Sweongyo		mac->mac_phy.detach(mac);
713203945Sweongyo}
714203945Sweongyo
715203945Sweongyostatic int
716203945Sweongyobwn_detach(device_t dev)
717203945Sweongyo{
718203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
719203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
720287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
721203945Sweongyo	int i;
722203945Sweongyo
723203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
724203945Sweongyo
725203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
726287197Sglebius		BWN_LOCK(sc);
727287197Sglebius		bwn_stop(sc);
728287197Sglebius		BWN_UNLOCK(sc);
729203945Sweongyo		bwn_dma_free(mac);
730203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
731203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
732203945Sweongyo		callout_drain(&sc->sc_task_ch);
733203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
734203945Sweongyo		bwn_phy_detach(mac);
735287197Sglebius		ieee80211_draintask(ic, &mac->mac_hwreset);
736287197Sglebius		ieee80211_draintask(ic, &mac->mac_txpower);
737287197Sglebius		ieee80211_ifdetach(ic);
738203945Sweongyo	}
739203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
740203945Sweongyo	taskqueue_free(sc->sc_tq);
741203945Sweongyo
742203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
743203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
744203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
745203945Sweongyo			    mac->mac_intrhand[i]);
746203945Sweongyo			mac->mac_intrhand[i] = NULL;
747203945Sweongyo		}
748203945Sweongyo	}
749203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
750203945Sweongyo	if (mac->mac_msi != 0)
751203945Sweongyo		pci_release_msi(dev);
752287197Sglebius	mbufq_drain(&sc->sc_snd);
753203945Sweongyo	BWN_LOCK_DESTROY(sc);
754203945Sweongyo	return (0);
755203945Sweongyo}
756203945Sweongyo
757287197Sglebiusstatic void
758203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
759203945Sweongyo{
760203945Sweongyo
761203945Sweongyo	BWN_LOCK_INIT(sc);
762203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
763203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
764203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
765203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
766287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
767203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
768203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
769203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
770203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
771203945Sweongyo}
772203945Sweongyo
773203945Sweongyostatic void
774204922Sweongyobwn_sprom_bugfixes(device_t dev)
775203945Sweongyo{
776203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
777204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
778204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
779204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
780204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
781203945Sweongyo
782204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
783204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
784204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
785204922Sweongyo		siba_sprom_set_bf_lo(dev,
786204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
787204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
788204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
789204922Sweongyo		siba_sprom_set_bf_lo(dev,
790204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
791204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
792203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
793203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
794203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
795203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
796203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
797203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
798203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
799204922Sweongyo			siba_sprom_set_bf_lo(dev,
800204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
801203945Sweongyo	}
802203945Sweongyo#undef	BWN_ISDEV
803203945Sweongyo}
804203945Sweongyo
805287197Sglebiusstatic void
806287197Sglebiusbwn_parent(struct ieee80211com *ic)
807203945Sweongyo{
808287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
809287197Sglebius	int startall = 0;
810203945Sweongyo
811287197Sglebius	BWN_LOCK(sc);
812287197Sglebius	if (ic->ic_nrunning > 0) {
813287197Sglebius		if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
814287197Sglebius			bwn_init(sc);
815287197Sglebius			startall = 1;
816287197Sglebius		} else
817286437Sadrian			bwn_update_promisc(ic);
818287197Sglebius	} else if (sc->sc_flags & BWN_FLAG_RUNNING)
819287197Sglebius		bwn_stop(sc);
820287197Sglebius	BWN_UNLOCK(sc);
821287197Sglebius
822287197Sglebius	if (startall)
823287197Sglebius		ieee80211_start_all(ic);
824203945Sweongyo}
825203945Sweongyo
826287197Sglebiusstatic int
827287197Sglebiusbwn_transmit(struct ieee80211com *ic, struct mbuf *m)
828203945Sweongyo{
829287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
830287197Sglebius	int error;
831203945Sweongyo
832203945Sweongyo	BWN_LOCK(sc);
833287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
834287197Sglebius		BWN_UNLOCK(sc);
835287197Sglebius		return (ENXIO);
836287197Sglebius	}
837287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
838287197Sglebius	if (error) {
839287197Sglebius		BWN_UNLOCK(sc);
840287197Sglebius		return (error);
841287197Sglebius	}
842287197Sglebius	bwn_start(sc);
843203945Sweongyo	BWN_UNLOCK(sc);
844287197Sglebius	return (0);
845203945Sweongyo}
846203945Sweongyo
847203945Sweongyostatic void
848287197Sglebiusbwn_start(struct bwn_softc *sc)
849203945Sweongyo{
850203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
851203945Sweongyo	struct ieee80211_frame *wh;
852203945Sweongyo	struct ieee80211_node *ni;
853203945Sweongyo	struct ieee80211_key *k;
854203945Sweongyo	struct mbuf *m;
855203945Sweongyo
856203945Sweongyo	BWN_ASSERT_LOCKED(sc);
857203945Sweongyo
858287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 || mac == NULL ||
859203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
860203945Sweongyo		return;
861203945Sweongyo
862287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
863203945Sweongyo		if (bwn_tx_isfull(sc, m))
864203945Sweongyo			break;
865203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
866203945Sweongyo		if (ni == NULL) {
867203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
868203945Sweongyo			m_freem(m);
869287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
870203945Sweongyo			continue;
871203945Sweongyo		}
872203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
873260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
874203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
875203945Sweongyo			if (k == NULL) {
876287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
877287197Sglebius				    IFCOUNTER_OERRORS, 1);
878203945Sweongyo				ieee80211_free_node(ni);
879203945Sweongyo				m_freem(m);
880203945Sweongyo				continue;
881203945Sweongyo			}
882203945Sweongyo		}
883203945Sweongyo		wh = NULL;	/* Catch any invalid use */
884203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
885287197Sglebius			if (ni != NULL) {
886287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
887287197Sglebius				    IFCOUNTER_OERRORS, 1);
888203945Sweongyo				ieee80211_free_node(ni);
889287197Sglebius			}
890203945Sweongyo			continue;
891203945Sweongyo		}
892203945Sweongyo		sc->sc_watchdog_timer = 5;
893203945Sweongyo	}
894203945Sweongyo}
895203945Sweongyo
896203945Sweongyostatic int
897203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
898203945Sweongyo{
899203945Sweongyo	struct bwn_dma_ring *dr;
900203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
901203945Sweongyo	struct bwn_pio_txqueue *tq;
902203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
903203945Sweongyo
904203945Sweongyo	BWN_ASSERT_LOCKED(sc);
905203945Sweongyo
906203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
907203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
908203945Sweongyo		if (dr->dr_stop == 1 ||
909203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
910203945Sweongyo			dr->dr_stop = 1;
911203945Sweongyo			goto full;
912203945Sweongyo		}
913203945Sweongyo	} else {
914203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
915203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
916287197Sglebius		    pktlen > (tq->tq_size - tq->tq_used))
917203945Sweongyo			goto full;
918203945Sweongyo	}
919203945Sweongyo	return (0);
920203945Sweongyofull:
921287197Sglebius	mbufq_prepend(&sc->sc_snd, m);
922203945Sweongyo	return (1);
923203945Sweongyo}
924203945Sweongyo
925203945Sweongyostatic int
926203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
927203945Sweongyo{
928203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
929203945Sweongyo	int error;
930203945Sweongyo
931203945Sweongyo	BWN_ASSERT_LOCKED(sc);
932203945Sweongyo
933203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
934203945Sweongyo		m_freem(m);
935203945Sweongyo		return (ENXIO);
936203945Sweongyo	}
937203945Sweongyo
938203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
939203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
940203945Sweongyo	if (error) {
941203945Sweongyo		m_freem(m);
942203945Sweongyo		return (error);
943203945Sweongyo	}
944203945Sweongyo	return (0);
945203945Sweongyo}
946203945Sweongyo
947203945Sweongyostatic int
948203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
949203945Sweongyo{
950203945Sweongyo	struct bwn_pio_txpkt *tp;
951203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
952203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
953203945Sweongyo	struct bwn_txhdr txhdr;
954203945Sweongyo	struct mbuf *m_new;
955203945Sweongyo	uint32_t ctl32;
956203945Sweongyo	int error;
957203945Sweongyo	uint16_t ctl16;
958203945Sweongyo
959203945Sweongyo	BWN_ASSERT_LOCKED(sc);
960203945Sweongyo
961203945Sweongyo	/* XXX TODO send packets after DTIM */
962203945Sweongyo
963203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
964203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
965203945Sweongyo	tp->tp_ni = ni;
966203945Sweongyo	tp->tp_m = m;
967203945Sweongyo
968203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
969203945Sweongyo	if (error) {
970203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
971203945Sweongyo		return (error);
972203945Sweongyo	}
973203945Sweongyo
974203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
975203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
976203945Sweongyo	tq->tq_free--;
977203945Sweongyo
978204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
979203945Sweongyo		/*
980203945Sweongyo		 * XXX please removes m_defrag(9)
981203945Sweongyo		 */
982243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
983203945Sweongyo		if (m_new == NULL) {
984203945Sweongyo			device_printf(sc->sc_dev,
985203945Sweongyo			    "%s: can't defrag TX buffer\n",
986203945Sweongyo			    __func__);
987203945Sweongyo			return (ENOBUFS);
988203945Sweongyo		}
989203945Sweongyo		if (m_new->m_next != NULL)
990203945Sweongyo			device_printf(sc->sc_dev,
991203945Sweongyo			    "TODO: fragmented packets for PIO\n");
992203945Sweongyo		tp->tp_m = m_new;
993203945Sweongyo
994203945Sweongyo		/* send HEADER */
995203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
996203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
997203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
998203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
999203945Sweongyo		/* send BODY */
1000203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1001203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1002203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1003203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1004203945Sweongyo	} else {
1005203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1006203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1007203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1008203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1009203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1010203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1011203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1012203945Sweongyo	}
1013203945Sweongyo
1014203945Sweongyo	return (0);
1015203945Sweongyo}
1016203945Sweongyo
1017203945Sweongyostatic struct bwn_pio_txqueue *
1018203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1019203945Sweongyo{
1020203945Sweongyo
1021203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1022203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1023203945Sweongyo
1024203945Sweongyo	switch (prio) {
1025203945Sweongyo	case 0:
1026203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1027203945Sweongyo	case 1:
1028203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1029203945Sweongyo	case 2:
1030203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1031203945Sweongyo	case 3:
1032203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1033203945Sweongyo	}
1034203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1035204242Simp	return (NULL);
1036203945Sweongyo}
1037203945Sweongyo
1038203945Sweongyostatic int
1039203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1040203945Sweongyo{
1041203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1042203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1043203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1044203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1045203945Sweongyo	struct bwn_dmadesc_generic *desc;
1046203945Sweongyo	struct bwn_dmadesc_meta *mt;
1047203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1048203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1049203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1050203945Sweongyo
1051203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1052203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1053203945Sweongyo
1054203945Sweongyo	/* XXX send after DTIM */
1055203945Sweongyo
1056203945Sweongyo	slot = bwn_dma_getslot(dr);
1057203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1058203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1059203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1060203945Sweongyo
1061203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1062203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1063203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1064203945Sweongyo	if (error)
1065203945Sweongyo		goto fail;
1066203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1067203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1068203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1069203945Sweongyo	if (error) {
1070287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1071203945Sweongyo		    __func__, error);
1072203945Sweongyo		goto fail;
1073203945Sweongyo	}
1074203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1075203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1076203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1077203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1078203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1079203945Sweongyo
1080203945Sweongyo	slot = bwn_dma_getslot(dr);
1081203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1082203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1083203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1084203945Sweongyo	mt->mt_m = m;
1085203945Sweongyo	mt->mt_ni = ni;
1086203945Sweongyo
1087203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1088203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1089203945Sweongyo	if (error && error != EFBIG) {
1090287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1091203945Sweongyo		    __func__, error);
1092203945Sweongyo		goto fail;
1093203945Sweongyo	}
1094203945Sweongyo	if (error) {    /* error == EFBIG */
1095203945Sweongyo		struct mbuf *m_new;
1096203945Sweongyo
1097243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1098203945Sweongyo		if (m_new == NULL) {
1099287197Sglebius			device_printf(sc->sc_dev,
1100287197Sglebius			    "%s: can't defrag TX buffer\n",
1101203945Sweongyo			    __func__);
1102203945Sweongyo			error = ENOBUFS;
1103203945Sweongyo			goto fail;
1104203945Sweongyo		} else {
1105203945Sweongyo			m = m_new;
1106203945Sweongyo		}
1107203945Sweongyo
1108203945Sweongyo		mt->mt_m = m;
1109203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1110203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1111203945Sweongyo		if (error) {
1112287197Sglebius			device_printf(sc->sc_dev,
1113287197Sglebius			    "%s: can't load TX buffer (2) %d\n",
1114203945Sweongyo			    __func__, error);
1115203945Sweongyo			goto fail;
1116203945Sweongyo		}
1117203945Sweongyo	}
1118203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1119203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1120203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1121203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1122203945Sweongyo
1123203945Sweongyo	/* XXX send after DTIM */
1124203945Sweongyo
1125203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1126203945Sweongyo	return (0);
1127203945Sweongyofail:
1128203945Sweongyo	dr->dr_curslot = backup[0];
1129203945Sweongyo	dr->dr_usedslot = backup[1];
1130203945Sweongyo	return (error);
1131203945Sweongyo#undef BWN_GET_TXHDRCACHE
1132203945Sweongyo}
1133203945Sweongyo
1134203945Sweongyostatic void
1135203945Sweongyobwn_watchdog(void *arg)
1136203945Sweongyo{
1137203945Sweongyo	struct bwn_softc *sc = arg;
1138203945Sweongyo
1139203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1140287197Sglebius		device_printf(sc->sc_dev, "device timeout\n");
1141287197Sglebius		counter_u64_add(sc->sc_ic.ic_oerrors, 1);
1142203945Sweongyo	}
1143203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1144203945Sweongyo}
1145203945Sweongyo
1146203945Sweongyostatic int
1147203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1148203945Sweongyo{
1149203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1150203945Sweongyo	int error, have_bg = 0, have_a = 0;
1151203945Sweongyo	uint32_t high;
1152203945Sweongyo
1153204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1154204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1155203945Sweongyo
1156204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1157203945Sweongyo
1158204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1159299976Sadrian
1160299976Sadrian	/*
1161299976Sadrian	 * Guess at whether it has A-PHY or G-PHY.
1162299976Sadrian	 * This is just used for resetting the core to probe things;
1163299976Sadrian	 * we will re-guess once it's all up and working.
1164299976Sadrian	 *
1165299976Sadrian	 * XXX TODO: there's the TGSHIGH DUALPHY flag based on
1166299976Sadrian	 * the PHY revision.
1167299976Sadrian	 */
1168299776Sadrian	bwn_reset_core(mac, !!(high & BWN_TGSHIGH_HAVE_2GHZ));
1169299976Sadrian
1170299976Sadrian	/*
1171299976Sadrian	 * Get the PHY version.
1172299976Sadrian	 */
1173203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1174203945Sweongyo	if (error)
1175203945Sweongyo		goto fail;
1176203945Sweongyo
1177299976Sadrian	/* XXX TODO need bhnd */
1178299792Sadrian	if (bwn_is_bus_siba(mac)) {
1179299792Sadrian		have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1180299792Sadrian		have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1181299976Sadrian		if (high & BWN_TGSHIGH_DUALPHY) {
1182299976Sadrian			have_bg = 1;
1183299976Sadrian			have_a = 1;
1184299976Sadrian		}
1185299792Sadrian	} else {
1186299792Sadrian		device_printf(sc->sc_dev, "%s: not siba; bailing\n", __func__);
1187299792Sadrian		error = ENXIO;
1188299792Sadrian		goto fail;
1189299792Sadrian	}
1190299792Sadrian
1191299792Sadrian#if 0
1192299792Sadrian	device_printf(sc->sc_dev, "%s: high=0x%08x, have_a=%d, have_bg=%d,"
1193299792Sadrian	    " deviceid=0x%04x, siba_deviceid=0x%04x\n",
1194299792Sadrian	    __func__,
1195299792Sadrian	    high,
1196299792Sadrian	    have_a,
1197299792Sadrian	    have_bg,
1198299792Sadrian	    siba_get_pci_device(sc->sc_dev),
1199299792Sadrian	    siba_get_chipid(sc->sc_dev));
1200299792Sadrian#endif
1201299792Sadrian
1202204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1203204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1204299976Sadrian	    siba_get_pci_device(sc->sc_dev) != 0x4324 &&
1205300187Sadrian	    siba_get_pci_device(sc->sc_dev) != 0x4328 &&
1206300187Sadrian	    siba_get_pci_device(sc->sc_dev) != 0x432b) {
1207203945Sweongyo		have_a = have_bg = 0;
1208203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1209203945Sweongyo			have_a = 1;
1210203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1211203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1212203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1213203945Sweongyo			have_bg = 1;
1214203945Sweongyo		else
1215203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1216203945Sweongyo			    mac->mac_phy.type));
1217203945Sweongyo	}
1218299976Sadrian
1219299976Sadrian	/*
1220300114Sadrian	 * XXX The PHY-G support doesn't do 5GHz operation.
1221299976Sadrian	 */
1222203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1223203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1224299976Sadrian		device_printf(sc->sc_dev,
1225300114Sadrian		    "%s: forcing 2GHz only; no dual-band support for PHY\n",
1226299976Sadrian		    __func__);
1227203945Sweongyo		have_a = 0;
1228203945Sweongyo		have_bg = 1;
1229203945Sweongyo	}
1230203945Sweongyo
1231300019Sadrian	mac->mac_phy.phy_n = NULL;
1232300019Sadrian
1233203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1234203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1235203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1236203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1237203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1238203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1239203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1240203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1241203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1242203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1243203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1244203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1245203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1246203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1247203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1248203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1249203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1250203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1251203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1252203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1253203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1254203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1255203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1256203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1257203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1258203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1259203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1260203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1261203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1262203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1263203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1264203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1265203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1266203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1267203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1268203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1269300019Sadrian	} else if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1270300019Sadrian		mac->mac_phy.attach = bwn_phy_n_attach;
1271300019Sadrian		mac->mac_phy.detach = bwn_phy_n_detach;
1272300019Sadrian		mac->mac_phy.prepare_hw = bwn_phy_n_prepare_hw;
1273300019Sadrian		mac->mac_phy.init_pre = bwn_phy_n_init_pre;
1274300019Sadrian		mac->mac_phy.init = bwn_phy_n_init;
1275300019Sadrian		mac->mac_phy.exit = bwn_phy_n_exit;
1276300019Sadrian		mac->mac_phy.phy_read = bwn_phy_n_read;
1277300019Sadrian		mac->mac_phy.phy_write = bwn_phy_n_write;
1278300019Sadrian		mac->mac_phy.rf_read = bwn_phy_n_rf_read;
1279300019Sadrian		mac->mac_phy.rf_write = bwn_phy_n_rf_write;
1280300019Sadrian		mac->mac_phy.use_hwpctl = bwn_phy_n_hwpctl;
1281300019Sadrian		mac->mac_phy.rf_onoff = bwn_phy_n_rf_onoff;
1282300019Sadrian		mac->mac_phy.switch_analog = bwn_phy_n_switch_analog;
1283300019Sadrian		mac->mac_phy.switch_channel = bwn_phy_n_switch_channel;
1284300019Sadrian		mac->mac_phy.get_default_chan = bwn_phy_n_get_default_chan;
1285300019Sadrian		mac->mac_phy.set_antenna = bwn_phy_n_set_antenna;
1286300019Sadrian		mac->mac_phy.set_im = bwn_phy_n_im;
1287300019Sadrian		mac->mac_phy.recalc_txpwr = bwn_phy_n_recalc_txpwr;
1288300019Sadrian		mac->mac_phy.set_txpwr = bwn_phy_n_set_txpwr;
1289300019Sadrian		mac->mac_phy.task_15s = bwn_phy_n_task_15s;
1290300019Sadrian		mac->mac_phy.task_60s = bwn_phy_n_task_60s;
1291203945Sweongyo	} else {
1292203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1293203945Sweongyo		    mac->mac_phy.type);
1294203945Sweongyo		error = ENXIO;
1295203945Sweongyo		goto fail;
1296203945Sweongyo	}
1297203945Sweongyo
1298203945Sweongyo	mac->mac_phy.gmode = have_bg;
1299203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1300203945Sweongyo		error = mac->mac_phy.attach(mac);
1301203945Sweongyo		if (error) {
1302203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1303203945Sweongyo			goto fail;
1304203945Sweongyo		}
1305203945Sweongyo	}
1306203945Sweongyo
1307299776Sadrian	bwn_reset_core(mac, have_bg);
1308203945Sweongyo
1309203945Sweongyo	error = bwn_chiptest(mac);
1310203945Sweongyo	if (error)
1311203945Sweongyo		goto fail;
1312203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1313203945Sweongyo	if (error) {
1314203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1315203945Sweongyo		goto fail;
1316203945Sweongyo	}
1317203945Sweongyo
1318203945Sweongyo	if (sc->sc_curmac == NULL)
1319203945Sweongyo		sc->sc_curmac = mac;
1320203945Sweongyo
1321203945Sweongyo	error = bwn_dma_attach(mac);
1322203945Sweongyo	if (error != 0) {
1323203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1324203945Sweongyo		goto fail;
1325203945Sweongyo	}
1326203945Sweongyo
1327203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1328203945Sweongyo
1329204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1330203945Sweongyofail:
1331204922Sweongyo	siba_powerdown(sc->sc_dev);
1332203945Sweongyo	return (error);
1333203945Sweongyo}
1334203945Sweongyo
1335299776Sadrian/*
1336299776Sadrian * Reset - SIBA.
1337299776Sadrian *
1338299776Sadrian * XXX TODO: implement BCMA version!
1339299776Sadrian */
1340298948Sadrianvoid
1341299776Sadrianbwn_reset_core(struct bwn_mac *mac, int g_mode)
1342203945Sweongyo{
1343204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1344203945Sweongyo	uint32_t low, ctl;
1345299776Sadrian	uint32_t flags = 0;
1346203945Sweongyo
1347299776Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: g_mode=%d\n", __func__, g_mode);
1348299776Sadrian
1349203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1350299776Sadrian	if (g_mode)
1351299776Sadrian		flags |= BWN_TGSLOW_SUPPORT_G;
1352203945Sweongyo
1353299776Sadrian	/* XXX N-PHY only; and hard-code to 20MHz for now */
1354299776Sadrian	if (mac->mac_phy.type == BWN_PHYTYPE_N)
1355299776Sadrian		flags |= BWN_TGSLOW_PHY_BANDWIDTH_20MHZ;
1356299776Sadrian
1357204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1358203945Sweongyo	DELAY(2000);
1359203945Sweongyo
1360299776Sadrian	/* Take PHY out of reset */
1361204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1362300188Sadrian	    ~(BWN_TGSLOW_PHYRESET | BWN_TGSLOW_PHYCLOCK_ENABLE);
1363204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1364204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1365300188Sadrian	DELAY(2000);
1366300188Sadrian	low &= ~SIBA_TGSLOW_FGC;
1367300188Sadrian	low |= BWN_TGSLOW_PHYCLOCK_ENABLE;
1368300188Sadrian	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1369204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1370300188Sadrian	DELAY(2000);
1371203945Sweongyo
1372203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1373203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1374203945Sweongyo
1375203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1376299776Sadrian	if (g_mode)
1377203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1378203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1379203945Sweongyo}
1380203945Sweongyo
1381203945Sweongyostatic int
1382203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1383203945Sweongyo{
1384203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1385203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1386203945Sweongyo	uint32_t tmp;
1387203945Sweongyo
1388203945Sweongyo	/* PHY */
1389203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1390299776Sadrian	phy->gmode = !! (tgshigh & BWN_TGSHIGH_HAVE_2GHZ);
1391203945Sweongyo	phy->rf_on = 1;
1392203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1393203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1394203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1395203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1396203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1397203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1398203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1399203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1400203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1401203945Sweongyo		goto unsupphy;
1402203945Sweongyo
1403203945Sweongyo	/* RADIO */
1404204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1405204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1406203945Sweongyo			tmp = 0x3205017f;
1407204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1408203945Sweongyo			tmp = 0x4205017f;
1409203945Sweongyo		else
1410203945Sweongyo			tmp = 0x5205017f;
1411203945Sweongyo	} else {
1412203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1413203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1414203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1415203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1416203945Sweongyo	}
1417203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1418203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1419203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1420299792Sadrian
1421299792Sadrian	/*
1422299792Sadrian	 * For now, just always do full init (ie, what bwn has traditionally
1423299792Sadrian	 * done)
1424299792Sadrian	 */
1425299792Sadrian	phy->phy_do_full_init = 1;
1426299792Sadrian
1427203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1428203945Sweongyo		goto unsupradio;
1429203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1430203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1431203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1432203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1433203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1434203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1435203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1436203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1437203945Sweongyo		goto unsupradio;
1438203945Sweongyo
1439203945Sweongyo	return (0);
1440203945Sweongyounsupphy:
1441203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1442203945Sweongyo	    "analog %#x)\n",
1443203945Sweongyo	    phy->type, phy->rev, phy->analog);
1444203945Sweongyo	return (ENXIO);
1445203945Sweongyounsupradio:
1446203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1447203945Sweongyo	    "rev %#x)\n",
1448203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1449203945Sweongyo	return (ENXIO);
1450203945Sweongyo}
1451203945Sweongyo
1452203945Sweongyostatic int
1453203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1454203945Sweongyo{
1455203945Sweongyo#define	TESTVAL0	0x55aaaa55
1456203945Sweongyo#define	TESTVAL1	0xaa5555aa
1457203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1458203945Sweongyo	uint32_t v, backup;
1459203945Sweongyo
1460203945Sweongyo	BWN_LOCK(sc);
1461203945Sweongyo
1462203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1463203945Sweongyo
1464203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1465203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1466203945Sweongyo		goto error;
1467203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1468203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1469203945Sweongyo		goto error;
1470203945Sweongyo
1471203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1472203945Sweongyo
1473204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1474204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1475203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1476203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1477203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1478203945Sweongyo			goto error;
1479203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1480203945Sweongyo			goto error;
1481203945Sweongyo	}
1482203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1483203945Sweongyo
1484203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1485203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1486203945Sweongyo		goto error;
1487203945Sweongyo
1488203945Sweongyo	BWN_UNLOCK(sc);
1489203945Sweongyo	return (0);
1490203945Sweongyoerror:
1491203945Sweongyo	BWN_UNLOCK(sc);
1492203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1493203945Sweongyo	return (ENODEV);
1494203945Sweongyo}
1495203945Sweongyo
1496203945Sweongyostatic int
1497203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1498203945Sweongyo{
1499203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1500287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1501300292Savos	uint8_t bands[IEEE80211_MODE_BYTES];
1502203945Sweongyo
1503203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1504203945Sweongyo	ic->ic_nchans = 0;
1505203945Sweongyo
1506299792Sadrian	DPRINTF(sc, BWN_DEBUG_EEPROM, "%s: called; bg=%d, a=%d\n",
1507299792Sadrian	    __func__,
1508299792Sadrian	    have_bg,
1509299792Sadrian	    have_a);
1510299792Sadrian
1511299982Sadrian	if (have_bg) {
1512299982Sadrian		memset(bands, 0, sizeof(bands));
1513299982Sadrian		setbit(bands, IEEE80211_MODE_11B);
1514299982Sadrian		setbit(bands, IEEE80211_MODE_11G);
1515203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1516299982Sadrian		    &ic->ic_nchans, &bwn_chantable_bg, bands);
1517203945Sweongyo	}
1518299982Sadrian
1519299982Sadrian	if (have_a) {
1520299982Sadrian		memset(bands, 0, sizeof(bands));
1521299982Sadrian		setbit(bands, IEEE80211_MODE_11A);
1522299800Sadrian		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1523299982Sadrian		    &ic->ic_nchans, &bwn_chantable_a, bands);
1524299982Sadrian	}
1525203945Sweongyo
1526203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1527203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1528203945Sweongyo
1529203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1530203945Sweongyo}
1531203945Sweongyo
1532298948Sadrianuint32_t
1533203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1534203945Sweongyo{
1535203945Sweongyo	uint32_t ret;
1536203945Sweongyo
1537204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1538203945Sweongyo
1539203945Sweongyo	if (way == BWN_SHARED) {
1540203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1541203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1542203945Sweongyo		if (offset & 0x0003) {
1543203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1544203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1545203945Sweongyo			ret <<= 16;
1546203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1547203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1548203945Sweongyo			goto out;
1549203945Sweongyo		}
1550203945Sweongyo		offset >>= 2;
1551203945Sweongyo	}
1552203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1553203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1554203945Sweongyoout:
1555203945Sweongyo	return (ret);
1556203945Sweongyo}
1557203945Sweongyo
1558298948Sadrianuint16_t
1559203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1560203945Sweongyo{
1561203945Sweongyo	uint16_t ret;
1562203945Sweongyo
1563204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1564203945Sweongyo
1565203945Sweongyo	if (way == BWN_SHARED) {
1566203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1567203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1568203945Sweongyo		if (offset & 0x0003) {
1569203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1570203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1571203945Sweongyo			goto out;
1572203945Sweongyo		}
1573203945Sweongyo		offset >>= 2;
1574203945Sweongyo	}
1575203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1576203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1577203945Sweongyoout:
1578203945Sweongyo
1579203945Sweongyo	return (ret);
1580203945Sweongyo}
1581203945Sweongyo
1582203945Sweongyostatic void
1583203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1584203945Sweongyo    uint16_t offset)
1585203945Sweongyo{
1586203945Sweongyo	uint32_t control;
1587203945Sweongyo
1588203945Sweongyo	control = way;
1589203945Sweongyo	control <<= 16;
1590203945Sweongyo	control |= offset;
1591203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1592203945Sweongyo}
1593203945Sweongyo
1594298948Sadrianvoid
1595203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1596203945Sweongyo    uint32_t value)
1597203945Sweongyo{
1598204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1599203945Sweongyo
1600203945Sweongyo	if (way == BWN_SHARED) {
1601203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1602203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1603203945Sweongyo		if (offset & 0x0003) {
1604203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1605203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1606203945Sweongyo				    (value >> 16) & 0xffff);
1607203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1608203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1609203945Sweongyo			return;
1610203945Sweongyo		}
1611203945Sweongyo		offset >>= 2;
1612203945Sweongyo	}
1613203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1614203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1615203945Sweongyo}
1616203945Sweongyo
1617298948Sadrianvoid
1618203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1619203945Sweongyo    uint16_t value)
1620203945Sweongyo{
1621204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1622203945Sweongyo
1623203945Sweongyo	if (way == BWN_SHARED) {
1624203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1625203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1626203945Sweongyo		if (offset & 0x0003) {
1627203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1628203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1629203945Sweongyo			return;
1630203945Sweongyo		}
1631203945Sweongyo		offset >>= 2;
1632203945Sweongyo	}
1633203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1634203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1635203945Sweongyo}
1636203945Sweongyo
1637203945Sweongyostatic void
1638203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
1639299982Sadrian    const struct bwn_channelinfo *ci, const uint8_t bands[])
1640203945Sweongyo{
1641299982Sadrian	int i, error;
1642203945Sweongyo
1643299982Sadrian	for (i = 0, error = 0; i < ci->nchannels && error == 0; i++) {
1644299982Sadrian		const struct bwn_channel *hc = &ci->channels[i];
1645203945Sweongyo
1646299982Sadrian		error = ieee80211_add_channel(chans, maxchans, nchans,
1647299982Sadrian		    hc->ieee, hc->freq, hc->maxTxPow, 0, bands);
1648203945Sweongyo	}
1649203945Sweongyo}
1650203945Sweongyo
1651203945Sweongyostatic int
1652203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1653203945Sweongyo	const struct ieee80211_bpf_params *params)
1654203945Sweongyo{
1655203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
1656286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1657203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1658289165Sadrian	int error;
1659203945Sweongyo
1660287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 ||
1661203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
1662203945Sweongyo		m_freem(m);
1663203945Sweongyo		return (ENETDOWN);
1664203945Sweongyo	}
1665203945Sweongyo
1666203945Sweongyo	BWN_LOCK(sc);
1667203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
1668203945Sweongyo		m_freem(m);
1669203945Sweongyo		BWN_UNLOCK(sc);
1670203945Sweongyo		return (ENOBUFS);
1671203945Sweongyo	}
1672203945Sweongyo
1673289165Sadrian	error = bwn_tx_start(sc, ni, m);
1674289165Sadrian	if (error == 0)
1675289165Sadrian		sc->sc_watchdog_timer = 5;
1676203945Sweongyo	BWN_UNLOCK(sc);
1677289165Sadrian	return (error);
1678203945Sweongyo}
1679203945Sweongyo
1680203945Sweongyo/*
1681203945Sweongyo * Callback from the 802.11 layer to update the slot time
1682203945Sweongyo * based on the current setting.  We use it to notify the
1683203945Sweongyo * firmware of ERP changes and the f/w takes care of things
1684203945Sweongyo * like slot time and preamble.
1685203945Sweongyo */
1686203945Sweongyostatic void
1687283540Sglebiusbwn_updateslot(struct ieee80211com *ic)
1688203945Sweongyo{
1689283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
1690203945Sweongyo	struct bwn_mac *mac;
1691203945Sweongyo
1692203945Sweongyo	BWN_LOCK(sc);
1693287197Sglebius	if (sc->sc_flags & BWN_FLAG_RUNNING) {
1694203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
1695292165Savos		bwn_set_slot_time(mac, IEEE80211_GET_SLOTTIME(ic));
1696203945Sweongyo	}
1697203945Sweongyo	BWN_UNLOCK(sc);
1698203945Sweongyo}
1699203945Sweongyo
1700203945Sweongyo/*
1701203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
1702203945Sweongyo * Note this interface does not check the operating mode as this
1703203945Sweongyo * is an internal callback and we are expected to honor the current
1704203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
1705203945Sweongyo * mode when operating in hostap mode to do ACS).
1706203945Sweongyo */
1707203945Sweongyostatic void
1708283540Sglebiusbwn_update_promisc(struct ieee80211com *ic)
1709203945Sweongyo{
1710283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
1711203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1712203945Sweongyo
1713203945Sweongyo	BWN_LOCK(sc);
1714203945Sweongyo	mac = sc->sc_curmac;
1715203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1716287197Sglebius		if (ic->ic_promisc > 0)
1717203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
1718203945Sweongyo		else
1719203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
1720203945Sweongyo		bwn_set_opmode(mac);
1721203945Sweongyo	}
1722203945Sweongyo	BWN_UNLOCK(sc);
1723203945Sweongyo}
1724203945Sweongyo
1725203945Sweongyo/*
1726203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
1727203945Sweongyo */
1728203945Sweongyostatic int
1729203945Sweongyobwn_wme_update(struct ieee80211com *ic)
1730203945Sweongyo{
1731286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1732203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1733203945Sweongyo	struct wmeParams *wmep;
1734203945Sweongyo	int i;
1735203945Sweongyo
1736203945Sweongyo	BWN_LOCK(sc);
1737203945Sweongyo	mac = sc->sc_curmac;
1738203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1739203945Sweongyo		bwn_mac_suspend(mac);
1740203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
1741203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
1742203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
1743203945Sweongyo		}
1744203945Sweongyo		bwn_mac_enable(mac);
1745203945Sweongyo	}
1746203945Sweongyo	BWN_UNLOCK(sc);
1747203945Sweongyo	return (0);
1748203945Sweongyo}
1749203945Sweongyo
1750203945Sweongyostatic void
1751203945Sweongyobwn_scan_start(struct ieee80211com *ic)
1752203945Sweongyo{
1753286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1754203945Sweongyo	struct bwn_mac *mac;
1755203945Sweongyo
1756203945Sweongyo	BWN_LOCK(sc);
1757203945Sweongyo	mac = sc->sc_curmac;
1758203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1759203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
1760203945Sweongyo		bwn_set_opmode(mac);
1761203945Sweongyo		/* disable CFP update during scan */
1762203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
1763203945Sweongyo	}
1764203945Sweongyo	BWN_UNLOCK(sc);
1765203945Sweongyo}
1766203945Sweongyo
1767203945Sweongyostatic void
1768203945Sweongyobwn_scan_end(struct ieee80211com *ic)
1769203945Sweongyo{
1770286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1771203945Sweongyo	struct bwn_mac *mac;
1772203945Sweongyo
1773203945Sweongyo	BWN_LOCK(sc);
1774203945Sweongyo	mac = sc->sc_curmac;
1775203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
1776203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
1777203945Sweongyo		bwn_set_opmode(mac);
1778203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
1779203945Sweongyo	}
1780203945Sweongyo	BWN_UNLOCK(sc);
1781203945Sweongyo}
1782203945Sweongyo
1783203945Sweongyostatic void
1784203945Sweongyobwn_set_channel(struct ieee80211com *ic)
1785203945Sweongyo{
1786286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
1787203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1788203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1789203945Sweongyo	int chan, error;
1790203945Sweongyo
1791203945Sweongyo	BWN_LOCK(sc);
1792203945Sweongyo
1793203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
1794203945Sweongyo	if (error)
1795216227Skevlo		goto fail;
1796203945Sweongyo	bwn_mac_suspend(mac);
1797203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
1798203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
1799203945Sweongyo	if (chan != phy->chan)
1800203945Sweongyo		bwn_switch_channel(mac, chan);
1801203945Sweongyo
1802203945Sweongyo	/* TX power level */
1803203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
1804203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
1805203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
1806203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
1807203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
1808203945Sweongyo	}
1809203945Sweongyo
1810203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
1811203945Sweongyo	if (phy->set_antenna)
1812203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
1813203945Sweongyo
1814203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
1815203945Sweongyo		if (sc->sc_rf_enabled) {
1816203945Sweongyo			bwn_rf_turnon(mac);
1817203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
1818203945Sweongyo				device_printf(sc->sc_dev,
1819213719Sjoel				    "please turn on the RF switch\n");
1820203945Sweongyo		} else
1821203945Sweongyo			bwn_rf_turnoff(mac);
1822203945Sweongyo	}
1823203945Sweongyo
1824203945Sweongyo	bwn_mac_enable(mac);
1825203945Sweongyo
1826203945Sweongyofail:
1827203945Sweongyo	/*
1828203945Sweongyo	 * Setup radio tap channel freq and flags
1829203945Sweongyo	 */
1830203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
1831203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
1832203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
1833203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
1834203945Sweongyo
1835203945Sweongyo	BWN_UNLOCK(sc);
1836203945Sweongyo}
1837203945Sweongyo
1838203945Sweongyostatic struct ieee80211vap *
1839228621Sbschmidtbwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
1840228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
1841228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
1842287197Sglebius    const uint8_t mac[IEEE80211_ADDR_LEN])
1843203945Sweongyo{
1844203945Sweongyo	struct ieee80211vap *vap;
1845203945Sweongyo	struct bwn_vap *bvp;
1846203945Sweongyo
1847203945Sweongyo	switch (opmode) {
1848203945Sweongyo	case IEEE80211_M_HOSTAP:
1849203945Sweongyo	case IEEE80211_M_MBSS:
1850203945Sweongyo	case IEEE80211_M_STA:
1851203945Sweongyo	case IEEE80211_M_WDS:
1852203945Sweongyo	case IEEE80211_M_MONITOR:
1853203945Sweongyo	case IEEE80211_M_IBSS:
1854203945Sweongyo	case IEEE80211_M_AHDEMO:
1855203945Sweongyo		break;
1856203945Sweongyo	default:
1857203945Sweongyo		return (NULL);
1858203945Sweongyo	}
1859203945Sweongyo
1860287197Sglebius	bvp = malloc(sizeof(struct bwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
1861203945Sweongyo	vap = &bvp->bv_vap;
1862287197Sglebius	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
1863203945Sweongyo	/* override with driver methods */
1864203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
1865203945Sweongyo	vap->iv_newstate = bwn_newstate;
1866203945Sweongyo
1867203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
1868203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
1869203945Sweongyo
1870206358Srpaulo	ieee80211_ratectl_init(vap);
1871203945Sweongyo
1872203945Sweongyo	/* complete setup */
1873203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
1874287197Sglebius	    ieee80211_media_status, mac);
1875203945Sweongyo	return (vap);
1876203945Sweongyo}
1877203945Sweongyo
1878203945Sweongyostatic void
1879203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
1880203945Sweongyo{
1881203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
1882203945Sweongyo
1883206358Srpaulo	ieee80211_ratectl_deinit(vap);
1884203945Sweongyo	ieee80211_vap_detach(vap);
1885203945Sweongyo	free(bvp, M_80211_VAP);
1886203945Sweongyo}
1887203945Sweongyo
1888203945Sweongyostatic int
1889287197Sglebiusbwn_init(struct bwn_softc *sc)
1890203945Sweongyo{
1891203945Sweongyo	struct bwn_mac *mac;
1892203945Sweongyo	int error;
1893203945Sweongyo
1894203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1895203945Sweongyo
1896299793Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
1897299793Sadrian
1898203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
1899203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
1900203945Sweongyo	sc->sc_filters = 0;
1901203945Sweongyo	bwn_wme_clear(sc);
1902203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
1903203945Sweongyo	sc->sc_rf_enabled = 1;
1904203945Sweongyo
1905203945Sweongyo	mac = sc->sc_curmac;
1906203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
1907203945Sweongyo		error = bwn_core_init(mac);
1908203945Sweongyo		if (error != 0)
1909203945Sweongyo			return (error);
1910203945Sweongyo	}
1911203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
1912203945Sweongyo		bwn_core_start(mac);
1913203945Sweongyo
1914203945Sweongyo	bwn_set_opmode(mac);
1915203945Sweongyo	bwn_set_pretbtt(mac);
1916203945Sweongyo	bwn_spu_setdelay(mac, 0);
1917203945Sweongyo	bwn_set_macaddr(mac);
1918203945Sweongyo
1919287197Sglebius	sc->sc_flags |= BWN_FLAG_RUNNING;
1920203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
1921203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
1922203945Sweongyo
1923203945Sweongyo	return (0);
1924203945Sweongyo}
1925203945Sweongyo
1926203945Sweongyostatic void
1927287197Sglebiusbwn_stop(struct bwn_softc *sc)
1928203945Sweongyo{
1929203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1930203945Sweongyo
1931203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1932203945Sweongyo
1933299793Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
1934299793Sadrian
1935203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
1936203945Sweongyo		/* XXX FIXME opmode not based on VAP */
1937203945Sweongyo		bwn_set_opmode(mac);
1938203945Sweongyo		bwn_set_macaddr(mac);
1939203945Sweongyo	}
1940203945Sweongyo
1941203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
1942203945Sweongyo		bwn_core_stop(mac);
1943203945Sweongyo
1944203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
1945203945Sweongyo	sc->sc_led_blinking = 0;
1946203945Sweongyo
1947203945Sweongyo	bwn_core_exit(mac);
1948203945Sweongyo	sc->sc_rf_enabled = 0;
1949203945Sweongyo
1950287197Sglebius	sc->sc_flags &= ~BWN_FLAG_RUNNING;
1951203945Sweongyo}
1952203945Sweongyo
1953203945Sweongyostatic void
1954203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
1955203945Sweongyo{
1956203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
1957203945Sweongyo	struct wmeParams *p;
1958203945Sweongyo	unsigned int i;
1959203945Sweongyo
1960203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
1961203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1962203945Sweongyo
1963203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
1964203945Sweongyo		p = &(sc->sc_wmeParams[i]);
1965203945Sweongyo
1966203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
1967203945Sweongyo		case BWN_WME_VOICE:
1968203945Sweongyo			p->wmep_txopLimit = 0;
1969203945Sweongyo			p->wmep_aifsn = 2;
1970203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1971203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1972203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
1973203945Sweongyo			break;
1974203945Sweongyo		case BWN_WME_VIDEO:
1975203945Sweongyo			p->wmep_txopLimit = 0;
1976203945Sweongyo			p->wmep_aifsn = 2;
1977203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1978203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1979203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
1980203945Sweongyo			break;
1981203945Sweongyo		case BWN_WME_BESTEFFORT:
1982203945Sweongyo			p->wmep_txopLimit = 0;
1983203945Sweongyo			p->wmep_aifsn = 3;
1984203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1985203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1986203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
1987203945Sweongyo			break;
1988203945Sweongyo		case BWN_WME_BACKGROUND:
1989203945Sweongyo			p->wmep_txopLimit = 0;
1990203945Sweongyo			p->wmep_aifsn = 7;
1991203945Sweongyo			/* XXX FIXME: log2(cwmin) */
1992203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
1993203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
1994203945Sweongyo			break;
1995203945Sweongyo		default:
1996203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1997203945Sweongyo		}
1998203945Sweongyo	}
1999203945Sweongyo}
2000203945Sweongyo
2001203945Sweongyostatic int
2002203945Sweongyobwn_core_init(struct bwn_mac *mac)
2003203945Sweongyo{
2004203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2005203945Sweongyo	uint64_t hf;
2006203945Sweongyo	int error;
2007203945Sweongyo
2008203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
2009203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2010203945Sweongyo
2011300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
2012300189Sadrian
2013204922Sweongyo	siba_powerup(sc->sc_dev, 0);
2014204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
2015299776Sadrian		bwn_reset_core(mac, mac->mac_phy.gmode);
2016203945Sweongyo
2017203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
2018203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
2019203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
2020203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
2021203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
2022203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
2023203945Sweongyo	mac->mac_stats.link_noise = -95;
2024203945Sweongyo	mac->mac_reason_intr = 0;
2025203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
2026203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
2027203945Sweongyo#ifdef BWN_DEBUG
2028203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
2029203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
2030203945Sweongyo#endif
2031203945Sweongyo	mac->mac_suspended = 1;
2032203945Sweongyo	mac->mac_task_state = 0;
2033203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
2034203945Sweongyo
2035203945Sweongyo	mac->mac_phy.init_pre(mac);
2036203945Sweongyo
2037204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
2038203945Sweongyo
2039204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
2040203945Sweongyo	bwn_bt_disable(mac);
2041203945Sweongyo	if (mac->mac_phy.prepare_hw) {
2042203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
2043203945Sweongyo		if (error)
2044203945Sweongyo			goto fail0;
2045203945Sweongyo	}
2046300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: chip_init\n", __func__);
2047203945Sweongyo	error = bwn_chip_init(mac);
2048203945Sweongyo	if (error)
2049203945Sweongyo		goto fail0;
2050203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
2051204922Sweongyo	    siba_get_revid(sc->sc_dev));
2052203945Sweongyo	hf = bwn_hf_read(mac);
2053203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
2054203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
2055204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
2056203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
2057203945Sweongyo		if (mac->mac_phy.rev == 1)
2058203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
2059203945Sweongyo	}
2060203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
2061203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
2062203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
2063203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
2064203945Sweongyo			hf |= BWN_HF_4318_TSSI;
2065203945Sweongyo	}
2066204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
2067203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
2068204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
2069204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
2070203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
2071203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
2072203945Sweongyo	bwn_hf_write(mac, hf);
2073203945Sweongyo
2074300194Sadrian	/* Tell the firmware about the MAC capabilities */
2075300194Sadrian	if (siba_get_revid(sc->sc_dev) >= 13) {
2076300194Sadrian		uint32_t cap;
2077300194Sadrian		cap = BWN_READ_4(mac, BWN_MAC_HW_CAP);
2078300194Sadrian		DPRINTF(sc, BWN_DEBUG_RESET,
2079300194Sadrian		    "%s: hw capabilities: 0x%08x\n",
2080300194Sadrian		    __func__, cap);
2081300194Sadrian		bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_L,
2082300194Sadrian		    cap & 0xffff);
2083300194Sadrian		bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_H,
2084300194Sadrian		    (cap >> 16) & 0xffff);
2085300194Sadrian	}
2086300194Sadrian
2087203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2088203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
2089203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
2090203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
2091203945Sweongyo
2092203945Sweongyo	bwn_rate_init(mac);
2093203945Sweongyo	bwn_set_phytxctl(mac);
2094203945Sweongyo
2095203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
2096203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
2097203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
2098203945Sweongyo
2099204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
2100203945Sweongyo		bwn_pio_init(mac);
2101203945Sweongyo	else
2102203945Sweongyo		bwn_dma_init(mac);
2103203945Sweongyo	bwn_wme_init(mac);
2104203945Sweongyo	bwn_spu_setdelay(mac, 1);
2105203945Sweongyo	bwn_bt_enable(mac);
2106203945Sweongyo
2107300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: powerup\n", __func__);
2108204922Sweongyo	siba_powerup(sc->sc_dev,
2109204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW));
2110203945Sweongyo	bwn_set_macaddr(mac);
2111203945Sweongyo	bwn_crypt_init(mac);
2112203945Sweongyo
2113203945Sweongyo	/* XXX LED initializatin */
2114203945Sweongyo
2115203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
2116203945Sweongyo
2117300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: done\n", __func__);
2118203945Sweongyo	return (error);
2119203945Sweongyo
2120203945Sweongyofail0:
2121204922Sweongyo	siba_powerdown(sc->sc_dev);
2122203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
2123203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2124300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: fail\n", __func__);
2125203945Sweongyo	return (error);
2126203945Sweongyo}
2127203945Sweongyo
2128203945Sweongyostatic void
2129203945Sweongyobwn_core_start(struct bwn_mac *mac)
2130203945Sweongyo{
2131203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2132203945Sweongyo	uint32_t tmp;
2133203945Sweongyo
2134203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
2135203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2136203945Sweongyo
2137204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
2138203945Sweongyo		return;
2139203945Sweongyo
2140203945Sweongyo	while (1) {
2141203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
2142203945Sweongyo		if (!(tmp & 0x00000001))
2143203945Sweongyo			break;
2144203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
2145203945Sweongyo	}
2146203945Sweongyo
2147203945Sweongyo	bwn_mac_enable(mac);
2148203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
2149203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
2150203945Sweongyo
2151203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
2152203945Sweongyo}
2153203945Sweongyo
2154203945Sweongyostatic void
2155203945Sweongyobwn_core_exit(struct bwn_mac *mac)
2156203945Sweongyo{
2157204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2158203945Sweongyo	uint32_t macctl;
2159203945Sweongyo
2160204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
2161203945Sweongyo
2162203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
2163203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2164203945Sweongyo
2165203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
2166203945Sweongyo		return;
2167203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
2168203945Sweongyo
2169203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
2170203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
2171203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
2172203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
2173203945Sweongyo
2174203945Sweongyo	bwn_dma_stop(mac);
2175203945Sweongyo	bwn_pio_stop(mac);
2176203945Sweongyo	bwn_chip_exit(mac);
2177203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
2178204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
2179204922Sweongyo	siba_powerdown(sc->sc_dev);
2180203945Sweongyo}
2181203945Sweongyo
2182203945Sweongyostatic void
2183203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
2184203945Sweongyo{
2185203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2186203945Sweongyo
2187203945Sweongyo	(void)sc;
2188203945Sweongyo	/* XXX do nothing yet */
2189203945Sweongyo}
2190203945Sweongyo
2191203945Sweongyostatic int
2192203945Sweongyobwn_chip_init(struct bwn_mac *mac)
2193203945Sweongyo{
2194204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2195203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2196203945Sweongyo	uint32_t macctl;
2197203945Sweongyo	int error;
2198203945Sweongyo
2199203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
2200203945Sweongyo	if (phy->gmode)
2201203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
2202203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
2203203945Sweongyo
2204203945Sweongyo	error = bwn_fw_fillinfo(mac);
2205203945Sweongyo	if (error)
2206203945Sweongyo		return (error);
2207203945Sweongyo	error = bwn_fw_loaducode(mac);
2208203945Sweongyo	if (error)
2209203945Sweongyo		return (error);
2210203945Sweongyo
2211203945Sweongyo	error = bwn_gpio_init(mac);
2212203945Sweongyo	if (error)
2213203945Sweongyo		return (error);
2214203945Sweongyo
2215203945Sweongyo	error = bwn_fw_loadinitvals(mac);
2216203945Sweongyo	if (error) {
2217204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
2218203945Sweongyo		return (error);
2219203945Sweongyo	}
2220203945Sweongyo	phy->switch_analog(mac, 1);
2221203945Sweongyo	error = bwn_phy_init(mac);
2222203945Sweongyo	if (error) {
2223204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
2224203945Sweongyo		return (error);
2225203945Sweongyo	}
2226203945Sweongyo	if (phy->set_im)
2227203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
2228203945Sweongyo	if (phy->set_antenna)
2229203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2230203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2231203945Sweongyo
2232203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
2233203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
2234203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
2235204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
2236203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
2237203945Sweongyo
2238203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
2239203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
2240203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
2241203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
2242203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
2243203945Sweongyo
2244203945Sweongyo	bwn_set_opmode(mac);
2245204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
2246203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
2247203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
2248203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
2249203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
2250203945Sweongyo	} else {
2251203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
2252203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
2253203945Sweongyo	}
2254203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
2255203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
2256203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
2257203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
2258203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
2259203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
2260203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
2261299776Sadrian
2262299776Sadrian	bwn_mac_phy_clock_set(mac, true);
2263299776Sadrian
2264299776Sadrian	/* SIBA powerup */
2265299776Sadrian	/* XXX TODO: BCMA powerup */
2266204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
2267203945Sweongyo	return (error);
2268203945Sweongyo}
2269203945Sweongyo
2270203945Sweongyo/* read hostflags */
2271298944Sadrianuint64_t
2272203945Sweongyobwn_hf_read(struct bwn_mac *mac)
2273203945Sweongyo{
2274203945Sweongyo	uint64_t ret;
2275203945Sweongyo
2276203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
2277203945Sweongyo	ret <<= 16;
2278203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
2279203945Sweongyo	ret <<= 16;
2280203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
2281203945Sweongyo	return (ret);
2282203945Sweongyo}
2283203945Sweongyo
2284298944Sadrianvoid
2285203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
2286203945Sweongyo{
2287203945Sweongyo
2288203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
2289203945Sweongyo	    (value & 0x00000000ffffull));
2290203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
2291203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
2292203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
2293203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
2294203945Sweongyo}
2295203945Sweongyo
2296203945Sweongyostatic void
2297203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
2298203945Sweongyo{
2299203945Sweongyo
2300203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
2301203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
2302203945Sweongyo}
2303203945Sweongyo
2304203945Sweongyostatic void
2305203945Sweongyobwn_rate_init(struct bwn_mac *mac)
2306203945Sweongyo{
2307203945Sweongyo
2308203945Sweongyo	switch (mac->mac_phy.type) {
2309203945Sweongyo	case BWN_PHYTYPE_A:
2310203945Sweongyo	case BWN_PHYTYPE_G:
2311203945Sweongyo	case BWN_PHYTYPE_LP:
2312203945Sweongyo	case BWN_PHYTYPE_N:
2313203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
2314203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
2315203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
2316203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
2317203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
2318203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
2319203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
2320203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
2321203945Sweongyo			break;
2322203945Sweongyo		/* FALLTHROUGH */
2323203945Sweongyo	case BWN_PHYTYPE_B:
2324203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
2325203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
2326203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
2327203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
2328203945Sweongyo		break;
2329203945Sweongyo	default:
2330203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2331203945Sweongyo	}
2332203945Sweongyo}
2333203945Sweongyo
2334203945Sweongyostatic void
2335203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
2336203945Sweongyo{
2337203945Sweongyo	uint16_t offset;
2338203945Sweongyo
2339203945Sweongyo	if (ofdm) {
2340203945Sweongyo		offset = 0x480;
2341203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
2342203945Sweongyo	} else {
2343203945Sweongyo		offset = 0x4c0;
2344203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
2345203945Sweongyo	}
2346203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
2347203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
2348203945Sweongyo}
2349203945Sweongyo
2350203945Sweongyostatic uint8_t
2351203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
2352203945Sweongyo{
2353203945Sweongyo
2354203945Sweongyo	switch (bitrate) {
2355203945Sweongyo	case BWN_CCK_RATE_1MB:
2356203945Sweongyo		return (0x0a);
2357203945Sweongyo	case BWN_CCK_RATE_2MB:
2358203945Sweongyo		return (0x14);
2359203945Sweongyo	case BWN_CCK_RATE_5MB:
2360203945Sweongyo		return (0x37);
2361203945Sweongyo	case BWN_CCK_RATE_11MB:
2362203945Sweongyo		return (0x6e);
2363203945Sweongyo	}
2364203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2365203945Sweongyo	return (0);
2366203945Sweongyo}
2367203945Sweongyo
2368203945Sweongyostatic uint8_t
2369203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
2370203945Sweongyo{
2371203945Sweongyo
2372203945Sweongyo	switch (bitrate) {
2373203945Sweongyo	case BWN_OFDM_RATE_6MB:
2374203945Sweongyo		return (0xb);
2375203945Sweongyo	case BWN_OFDM_RATE_9MB:
2376203945Sweongyo		return (0xf);
2377203945Sweongyo	case BWN_OFDM_RATE_12MB:
2378203945Sweongyo		return (0xa);
2379203945Sweongyo	case BWN_OFDM_RATE_18MB:
2380203945Sweongyo		return (0xe);
2381203945Sweongyo	case BWN_OFDM_RATE_24MB:
2382203945Sweongyo		return (0x9);
2383203945Sweongyo	case BWN_OFDM_RATE_36MB:
2384203945Sweongyo		return (0xd);
2385203945Sweongyo	case BWN_OFDM_RATE_48MB:
2386203945Sweongyo		return (0x8);
2387203945Sweongyo	case BWN_OFDM_RATE_54MB:
2388203945Sweongyo		return (0xc);
2389203945Sweongyo	}
2390203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2391203945Sweongyo	return (0);
2392203945Sweongyo}
2393203945Sweongyo
2394203945Sweongyostatic void
2395203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
2396203945Sweongyo{
2397203945Sweongyo	uint16_t ctl;
2398203945Sweongyo
2399203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
2400203945Sweongyo	    BWN_TX_PHY_TXPWR);
2401203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
2402203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
2403203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
2404203945Sweongyo}
2405203945Sweongyo
2406203945Sweongyostatic void
2407203945Sweongyobwn_pio_init(struct bwn_mac *mac)
2408203945Sweongyo{
2409203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
2410203945Sweongyo
2411203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
2412203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
2413203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
2414203945Sweongyo
2415203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
2416203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
2417203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
2418203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
2419203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
2420203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
2421203945Sweongyo}
2422203945Sweongyo
2423203945Sweongyostatic void
2424203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
2425203945Sweongyo    int index)
2426203945Sweongyo{
2427203945Sweongyo	struct bwn_pio_txpkt *tp;
2428204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2429203945Sweongyo	unsigned int i;
2430203945Sweongyo
2431203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
2432203945Sweongyo	tq->tq_index = index;
2433203945Sweongyo
2434203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
2435204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
2436203945Sweongyo		tq->tq_size = 1920;
2437203945Sweongyo	else {
2438203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
2439203945Sweongyo		tq->tq_size -= 80;
2440203945Sweongyo	}
2441203945Sweongyo
2442203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
2443203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
2444203945Sweongyo		tp = &(tq->tq_pkts[i]);
2445203945Sweongyo		tp->tp_index = i;
2446203945Sweongyo		tp->tp_queue = tq;
2447203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
2448203945Sweongyo	}
2449203945Sweongyo}
2450203945Sweongyo
2451203945Sweongyostatic uint16_t
2452203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
2453203945Sweongyo{
2454203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2455203945Sweongyo	static const uint16_t bases[] = {
2456203945Sweongyo		BWN_PIO_BASE0,
2457203945Sweongyo		BWN_PIO_BASE1,
2458203945Sweongyo		BWN_PIO_BASE2,
2459203945Sweongyo		BWN_PIO_BASE3,
2460203945Sweongyo		BWN_PIO_BASE4,
2461203945Sweongyo		BWN_PIO_BASE5,
2462203945Sweongyo		BWN_PIO_BASE6,
2463203945Sweongyo		BWN_PIO_BASE7,
2464203945Sweongyo	};
2465203945Sweongyo	static const uint16_t bases_rev11[] = {
2466203945Sweongyo		BWN_PIO11_BASE0,
2467203945Sweongyo		BWN_PIO11_BASE1,
2468203945Sweongyo		BWN_PIO11_BASE2,
2469203945Sweongyo		BWN_PIO11_BASE3,
2470203945Sweongyo		BWN_PIO11_BASE4,
2471203945Sweongyo		BWN_PIO11_BASE5,
2472203945Sweongyo	};
2473203945Sweongyo
2474204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
2475203945Sweongyo		if (index >= N(bases_rev11))
2476203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
2477203945Sweongyo		return (bases_rev11[index]);
2478203945Sweongyo	}
2479203945Sweongyo	if (index >= N(bases))
2480203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
2481203945Sweongyo	return (bases[index]);
2482203945Sweongyo}
2483203945Sweongyo
2484203945Sweongyostatic void
2485203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
2486203945Sweongyo    int index)
2487203945Sweongyo{
2488204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2489203945Sweongyo
2490203945Sweongyo	prq->prq_mac = mac;
2491204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
2492203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
2493203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
2494203945Sweongyo}
2495203945Sweongyo
2496203945Sweongyostatic void
2497203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
2498203945Sweongyo{
2499203945Sweongyo	if (tq == NULL)
2500203945Sweongyo		return;
2501203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
2502203945Sweongyo}
2503203945Sweongyo
2504203945Sweongyostatic void
2505203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
2506203945Sweongyo{
2507203945Sweongyo
2508203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
2509203945Sweongyo}
2510203945Sweongyo
2511203945Sweongyostatic uint16_t
2512203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
2513203945Sweongyo    uint16_t offset)
2514203945Sweongyo{
2515203945Sweongyo
2516203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
2517203945Sweongyo}
2518203945Sweongyo
2519203945Sweongyostatic void
2520203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
2521203945Sweongyo{
2522203945Sweongyo	uint32_t ctl;
2523203945Sweongyo	int type;
2524203945Sweongyo	uint16_t base;
2525203945Sweongyo
2526203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
2527203945Sweongyo	base = bwn_dma_base(type, idx);
2528203945Sweongyo	if (type == BWN_DMA_64BIT) {
2529203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
2530203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
2531203945Sweongyo		if (enable)
2532203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
2533203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
2534203945Sweongyo	} else {
2535203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
2536203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
2537203945Sweongyo		if (enable)
2538203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
2539203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
2540203945Sweongyo	}
2541203945Sweongyo}
2542203945Sweongyo
2543203945Sweongyostatic uint64_t
2544203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
2545203945Sweongyo{
2546203945Sweongyo	uint32_t tmp;
2547203945Sweongyo	uint16_t base;
2548203945Sweongyo
2549203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
2550203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
2551203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
2552203945Sweongyo	base = bwn_dma_base(0, 0);
2553203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
2554203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
2555203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
2556203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
2557203945Sweongyo
2558203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
2559203945Sweongyo}
2560203945Sweongyo
2561203945Sweongyostatic int
2562203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
2563203945Sweongyo{
2564203945Sweongyo
2565203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
2566203945Sweongyo		return (BWN_DMA_30BIT);
2567203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
2568203945Sweongyo		return (BWN_DMA_32BIT);
2569203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
2570203945Sweongyo		return (BWN_DMA_64BIT);
2571203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2572203945Sweongyo	return (BWN_DMA_30BIT);
2573203945Sweongyo}
2574203945Sweongyo
2575203945Sweongyostatic void
2576203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
2577203945Sweongyo{
2578203945Sweongyo	struct bwn_pio_txpkt *tp;
2579203945Sweongyo	unsigned int i;
2580203945Sweongyo
2581203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
2582203945Sweongyo		tp = &(tq->tq_pkts[i]);
2583203945Sweongyo		if (tp->tp_m) {
2584203945Sweongyo			m_freem(tp->tp_m);
2585203945Sweongyo			tp->tp_m = NULL;
2586203945Sweongyo		}
2587203945Sweongyo	}
2588203945Sweongyo}
2589203945Sweongyo
2590203945Sweongyostatic uint16_t
2591203945Sweongyobwn_dma_base(int type, int controller_idx)
2592203945Sweongyo{
2593203945Sweongyo	static const uint16_t map64[] = {
2594203945Sweongyo		BWN_DMA64_BASE0,
2595203945Sweongyo		BWN_DMA64_BASE1,
2596203945Sweongyo		BWN_DMA64_BASE2,
2597203945Sweongyo		BWN_DMA64_BASE3,
2598203945Sweongyo		BWN_DMA64_BASE4,
2599203945Sweongyo		BWN_DMA64_BASE5,
2600203945Sweongyo	};
2601203945Sweongyo	static const uint16_t map32[] = {
2602203945Sweongyo		BWN_DMA32_BASE0,
2603203945Sweongyo		BWN_DMA32_BASE1,
2604203945Sweongyo		BWN_DMA32_BASE2,
2605203945Sweongyo		BWN_DMA32_BASE3,
2606203945Sweongyo		BWN_DMA32_BASE4,
2607203945Sweongyo		BWN_DMA32_BASE5,
2608203945Sweongyo	};
2609203945Sweongyo
2610203945Sweongyo	if (type == BWN_DMA_64BIT) {
2611203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
2612203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2613203945Sweongyo		return (map64[controller_idx]);
2614203945Sweongyo	}
2615203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
2616203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2617203945Sweongyo	return (map32[controller_idx]);
2618203945Sweongyo}
2619203945Sweongyo
2620203945Sweongyostatic void
2621203945Sweongyobwn_dma_init(struct bwn_mac *mac)
2622203945Sweongyo{
2623203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2624203945Sweongyo
2625203945Sweongyo	/* setup TX DMA channels. */
2626203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
2627203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
2628203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
2629203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
2630203945Sweongyo	bwn_dma_setup(dma->mcast);
2631203945Sweongyo	/* setup RX DMA channel. */
2632203945Sweongyo	bwn_dma_setup(dma->rx);
2633203945Sweongyo}
2634203945Sweongyo
2635203945Sweongyostatic struct bwn_dma_ring *
2636203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
2637203945Sweongyo    int for_tx, int type)
2638203945Sweongyo{
2639203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
2640203945Sweongyo	struct bwn_dma_ring *dr;
2641203945Sweongyo	struct bwn_dmadesc_generic *desc;
2642203945Sweongyo	struct bwn_dmadesc_meta *mt;
2643203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2644203945Sweongyo	int error, i;
2645203945Sweongyo
2646203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
2647203945Sweongyo	if (dr == NULL)
2648203945Sweongyo		goto out;
2649203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
2650203945Sweongyo	if (for_tx)
2651203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
2652203945Sweongyo
2653203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
2654203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
2655203945Sweongyo	if (dr->dr_meta == NULL)
2656203945Sweongyo		goto fail0;
2657203945Sweongyo
2658203945Sweongyo	dr->dr_type = type;
2659203945Sweongyo	dr->dr_mac = mac;
2660203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
2661203945Sweongyo	dr->dr_index = controller_index;
2662203945Sweongyo	if (type == BWN_DMA_64BIT) {
2663203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
2664203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
2665203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
2666203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
2667203945Sweongyo		dr->resume = bwn_dma_64_resume;
2668203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
2669203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
2670203945Sweongyo	} else {
2671203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
2672203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
2673203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
2674203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
2675203945Sweongyo		dr->resume = bwn_dma_32_resume;
2676203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
2677203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
2678203945Sweongyo	}
2679203945Sweongyo	if (for_tx) {
2680203945Sweongyo		dr->dr_tx = 1;
2681203945Sweongyo		dr->dr_curslot = -1;
2682203945Sweongyo	} else {
2683203945Sweongyo		if (dr->dr_index == 0) {
2684300075Sadrian			switch (mac->mac_fw.fw_hdr_format) {
2685300075Sadrian			case BWN_FW_HDR_351:
2686300075Sadrian			case BWN_FW_HDR_410:
2687300075Sadrian				dr->dr_rx_bufsize =
2688300075Sadrian				    BWN_DMA0_RX_BUFFERSIZE_FW351;
2689300075Sadrian				dr->dr_frameoffset =
2690300075Sadrian				    BWN_DMA0_RX_FRAMEOFFSET_FW351;
2691300075Sadrian				break;
2692300075Sadrian			case BWN_FW_HDR_598:
2693300075Sadrian				dr->dr_rx_bufsize =
2694300075Sadrian				    BWN_DMA0_RX_BUFFERSIZE_FW598;
2695300075Sadrian				dr->dr_frameoffset =
2696300075Sadrian				    BWN_DMA0_RX_FRAMEOFFSET_FW598;
2697300075Sadrian				break;
2698300075Sadrian			}
2699203945Sweongyo		} else
2700203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
2701203945Sweongyo	}
2702203945Sweongyo
2703203945Sweongyo	error = bwn_dma_allocringmemory(dr);
2704203945Sweongyo	if (error)
2705203945Sweongyo		goto fail2;
2706203945Sweongyo
2707203945Sweongyo	if (for_tx) {
2708203945Sweongyo		/*
2709203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
2710203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
2711203945Sweongyo		 */
2712203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
2713203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
2714203945Sweongyo
2715299891Sadrian		dr->dr_txhdr_cache = contigmalloc(
2716299891Sadrian		    (dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
2717300075Sadrian		    BWN_MAXTXHDRSIZE, M_DEVBUF, M_ZERO,
2718299891Sadrian		    0, BUS_SPACE_MAXADDR, 8, 0);
2719299891Sadrian		if (dr->dr_txhdr_cache == NULL) {
2720299891Sadrian			device_printf(sc->sc_dev,
2721299891Sadrian			    "can't allocate TX header DMA memory\n");
2722299891Sadrian			goto fail1;
2723299891Sadrian		}
2724203945Sweongyo
2725203945Sweongyo		/*
2726203945Sweongyo		 * Create TX ring DMA stuffs
2727203945Sweongyo		 */
2728203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
2729203945Sweongyo				    BWN_ALIGN, 0,
2730203945Sweongyo				    BUS_SPACE_MAXADDR,
2731203945Sweongyo				    BUS_SPACE_MAXADDR,
2732203945Sweongyo				    NULL, NULL,
2733203945Sweongyo				    BWN_HDRSIZE(mac),
2734203945Sweongyo				    1,
2735203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
2736203945Sweongyo				    0,
2737203945Sweongyo				    NULL, NULL,
2738203945Sweongyo				    &dr->dr_txring_dtag);
2739203945Sweongyo		if (error) {
2740203945Sweongyo			device_printf(sc->sc_dev,
2741203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
2742299891Sadrian			goto fail2;
2743203945Sweongyo		}
2744203945Sweongyo
2745203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
2746203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
2747203945Sweongyo
2748203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
2749203945Sweongyo			mt->mt_m = NULL;
2750203945Sweongyo			mt->mt_ni = NULL;
2751203945Sweongyo			mt->mt_islast = 0;
2752203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
2753203945Sweongyo			    &mt->mt_dmap);
2754203945Sweongyo			if (error) {
2755203945Sweongyo				device_printf(sc->sc_dev,
2756203945Sweongyo				     "can't create RX buf DMA map\n");
2757299891Sadrian				goto fail2;
2758203945Sweongyo			}
2759203945Sweongyo
2760203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
2761203945Sweongyo
2762203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
2763203945Sweongyo			mt->mt_m = NULL;
2764203945Sweongyo			mt->mt_ni = NULL;
2765203945Sweongyo			mt->mt_islast = 1;
2766203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
2767203945Sweongyo			    &mt->mt_dmap);
2768203945Sweongyo			if (error) {
2769203945Sweongyo				device_printf(sc->sc_dev,
2770203945Sweongyo				     "can't create RX buf DMA map\n");
2771299891Sadrian				goto fail2;
2772203945Sweongyo			}
2773203945Sweongyo		}
2774203945Sweongyo	} else {
2775203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
2776203945Sweongyo		    &dr->dr_spare_dmap);
2777203945Sweongyo		if (error) {
2778203945Sweongyo			device_printf(sc->sc_dev,
2779203945Sweongyo			    "can't create RX buf DMA map\n");
2780203945Sweongyo			goto out;		/* XXX wrong! */
2781203945Sweongyo		}
2782203945Sweongyo
2783203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
2784203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
2785203945Sweongyo
2786203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
2787203945Sweongyo			    &mt->mt_dmap);
2788203945Sweongyo			if (error) {
2789203945Sweongyo				device_printf(sc->sc_dev,
2790203945Sweongyo				    "can't create RX buf DMA map\n");
2791203945Sweongyo				goto out;	/* XXX wrong! */
2792203945Sweongyo			}
2793203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
2794203945Sweongyo			if (error) {
2795203945Sweongyo				device_printf(sc->sc_dev,
2796203945Sweongyo				    "failed to allocate RX buf\n");
2797203945Sweongyo				goto out;	/* XXX wrong! */
2798203945Sweongyo			}
2799203945Sweongyo		}
2800203945Sweongyo
2801203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
2802203945Sweongyo		    BUS_DMASYNC_PREWRITE);
2803203945Sweongyo
2804203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
2805203945Sweongyo	}
2806203945Sweongyo
2807203945Sweongyo      out:
2808203945Sweongyo	return (dr);
2809203945Sweongyo
2810203945Sweongyofail2:
2811299891Sadrian	if (dr->dr_txhdr_cache != NULL) {
2812299891Sadrian		contigfree(dr->dr_txhdr_cache,
2813299891Sadrian		    (dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
2814300075Sadrian		    BWN_MAXTXHDRSIZE, M_DEVBUF);
2815299891Sadrian	}
2816203945Sweongyofail1:
2817203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
2818203945Sweongyofail0:
2819203945Sweongyo	free(dr, M_DEVBUF);
2820203945Sweongyo	return (NULL);
2821203945Sweongyo}
2822203945Sweongyo
2823203945Sweongyostatic void
2824203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
2825203945Sweongyo{
2826203945Sweongyo
2827203945Sweongyo	if (dr == NULL)
2828203945Sweongyo		return;
2829203945Sweongyo
2830203945Sweongyo	bwn_dma_free_descbufs(*dr);
2831203945Sweongyo	bwn_dma_free_ringmemory(*dr);
2832203945Sweongyo
2833299891Sadrian	if ((*dr)->dr_txhdr_cache != NULL) {
2834299891Sadrian		contigfree((*dr)->dr_txhdr_cache,
2835299891Sadrian		    ((*dr)->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
2836300075Sadrian		    BWN_MAXTXHDRSIZE, M_DEVBUF);
2837299891Sadrian	}
2838203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
2839203945Sweongyo	free(*dr, M_DEVBUF);
2840203945Sweongyo
2841203945Sweongyo	*dr = NULL;
2842203945Sweongyo}
2843203945Sweongyo
2844203945Sweongyostatic void
2845203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
2846203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
2847203945Sweongyo{
2848203945Sweongyo	struct bwn_dmadesc32 *desc;
2849203945Sweongyo
2850203945Sweongyo	*meta = &(dr->dr_meta[slot]);
2851203945Sweongyo	desc = dr->dr_ring_descbase;
2852203945Sweongyo	desc = &(desc[slot]);
2853203945Sweongyo
2854203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
2855203945Sweongyo}
2856203945Sweongyo
2857203945Sweongyostatic void
2858203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
2859203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
2860203945Sweongyo    int start, int end, int irq)
2861203945Sweongyo{
2862203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
2863204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2864203945Sweongyo	uint32_t addr, addrext, ctl;
2865203945Sweongyo	int slot;
2866203945Sweongyo
2867203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
2868203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
2869203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2870203945Sweongyo
2871203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
2872203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
2873204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
2874203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
2875203945Sweongyo	if (slot == dr->dr_numslots - 1)
2876203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
2877203945Sweongyo	if (start)
2878203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
2879203945Sweongyo	if (end)
2880203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
2881203945Sweongyo	if (irq)
2882203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
2883203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
2884203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
2885203945Sweongyo
2886203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
2887203945Sweongyo	desc->dma.dma32.address = htole32(addr);
2888203945Sweongyo}
2889203945Sweongyo
2890203945Sweongyostatic void
2891203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
2892203945Sweongyo{
2893203945Sweongyo
2894203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
2895203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
2896203945Sweongyo}
2897203945Sweongyo
2898203945Sweongyostatic void
2899203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
2900203945Sweongyo{
2901203945Sweongyo
2902203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
2903203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
2904203945Sweongyo}
2905203945Sweongyo
2906203945Sweongyostatic void
2907203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
2908203945Sweongyo{
2909203945Sweongyo
2910203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
2911203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
2912203945Sweongyo}
2913203945Sweongyo
2914203945Sweongyostatic int
2915203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
2916203945Sweongyo{
2917203945Sweongyo	uint32_t val;
2918203945Sweongyo
2919203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
2920203945Sweongyo	val &= BWN_DMA32_RXDPTR;
2921203945Sweongyo
2922203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
2923203945Sweongyo}
2924203945Sweongyo
2925203945Sweongyostatic void
2926203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
2927203945Sweongyo{
2928203945Sweongyo
2929203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
2930203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
2931203945Sweongyo}
2932203945Sweongyo
2933203945Sweongyostatic void
2934203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
2935203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
2936203945Sweongyo{
2937203945Sweongyo	struct bwn_dmadesc64 *desc;
2938203945Sweongyo
2939203945Sweongyo	*meta = &(dr->dr_meta[slot]);
2940203945Sweongyo	desc = dr->dr_ring_descbase;
2941203945Sweongyo	desc = &(desc[slot]);
2942203945Sweongyo
2943203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
2944203945Sweongyo}
2945203945Sweongyo
2946203945Sweongyostatic void
2947203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
2948203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
2949203945Sweongyo    int start, int end, int irq)
2950203945Sweongyo{
2951203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
2952204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
2953203945Sweongyo	int slot;
2954203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
2955203945Sweongyo	uint32_t addrlo, addrhi;
2956203945Sweongyo	uint32_t addrext;
2957203945Sweongyo
2958203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
2959203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
2960203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2961203945Sweongyo
2962203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
2963203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
2964203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
2965203945Sweongyo	    30;
2966204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
2967203945Sweongyo	if (slot == dr->dr_numslots - 1)
2968203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
2969203945Sweongyo	if (start)
2970203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
2971203945Sweongyo	if (end)
2972203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
2973203945Sweongyo	if (irq)
2974203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
2975203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
2976203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
2977203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
2978203945Sweongyo
2979203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
2980203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
2981203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
2982203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
2983203945Sweongyo}
2984203945Sweongyo
2985203945Sweongyostatic void
2986203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
2987203945Sweongyo{
2988203945Sweongyo
2989203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
2990203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
2991203945Sweongyo}
2992203945Sweongyo
2993203945Sweongyostatic void
2994203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
2995203945Sweongyo{
2996203945Sweongyo
2997203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
2998203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
2999203945Sweongyo}
3000203945Sweongyo
3001203945Sweongyostatic void
3002203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
3003203945Sweongyo{
3004203945Sweongyo
3005203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
3006203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
3007203945Sweongyo}
3008203945Sweongyo
3009203945Sweongyostatic int
3010203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
3011203945Sweongyo{
3012203945Sweongyo	uint32_t val;
3013203945Sweongyo
3014203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
3015203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
3016203945Sweongyo
3017203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
3018203945Sweongyo}
3019203945Sweongyo
3020203945Sweongyostatic void
3021203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
3022203945Sweongyo{
3023203945Sweongyo
3024203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
3025203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
3026203945Sweongyo}
3027203945Sweongyo
3028203945Sweongyostatic int
3029203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
3030203945Sweongyo{
3031203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
3032203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3033203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3034203945Sweongyo	int error;
3035203945Sweongyo
3036203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
3037203945Sweongyo			    BWN_ALIGN, 0,
3038203945Sweongyo			    BUS_SPACE_MAXADDR,
3039203945Sweongyo			    BUS_SPACE_MAXADDR,
3040203945Sweongyo			    NULL, NULL,
3041203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
3042203945Sweongyo			    1,
3043203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
3044203945Sweongyo			    0,
3045203945Sweongyo			    NULL, NULL,
3046203945Sweongyo			    &dr->dr_ring_dtag);
3047203945Sweongyo	if (error) {
3048203945Sweongyo		device_printf(sc->sc_dev,
3049203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
3050203945Sweongyo		return (-1);
3051203945Sweongyo	}
3052203945Sweongyo
3053203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
3054203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
3055203945Sweongyo	    &dr->dr_ring_dmap);
3056203945Sweongyo	if (error) {
3057203945Sweongyo		device_printf(sc->sc_dev,
3058203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
3059203945Sweongyo		return (-1);
3060203945Sweongyo	}
3061203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
3062203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
3063203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
3064203945Sweongyo	if (error) {
3065203945Sweongyo		device_printf(sc->sc_dev,
3066203945Sweongyo		    "can't load DMA mem: TODO free\n");
3067203945Sweongyo		return (-1);
3068203945Sweongyo	}
3069203945Sweongyo
3070203945Sweongyo	return (0);
3071203945Sweongyo}
3072203945Sweongyo
3073203945Sweongyostatic void
3074203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
3075203945Sweongyo{
3076204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3077203945Sweongyo	uint64_t ring64;
3078203945Sweongyo	uint32_t addrext, ring32, value;
3079204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
3080203945Sweongyo
3081203945Sweongyo	if (dr->dr_tx) {
3082203945Sweongyo		dr->dr_curslot = -1;
3083203945Sweongyo
3084203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3085203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
3086203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
3087203945Sweongyo			    >> 30;
3088203945Sweongyo			value = BWN_DMA64_TXENABLE;
3089203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
3090203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
3091203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
3092203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
3093203945Sweongyo			    (ring64 & 0xffffffff));
3094203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
3095203945Sweongyo			    ((ring64 >> 32) &
3096203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
3097203945Sweongyo		} else {
3098203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
3099203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
3100203945Sweongyo			value = BWN_DMA32_TXENABLE;
3101203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
3102203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
3103203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
3104203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
3105203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
3106203945Sweongyo		}
3107203945Sweongyo		return;
3108203945Sweongyo	}
3109203945Sweongyo
3110203945Sweongyo	/*
3111203945Sweongyo	 * set for RX
3112203945Sweongyo	 */
3113203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
3114203945Sweongyo
3115203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
3116203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
3117203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
3118203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
3119203945Sweongyo		value |= BWN_DMA64_RXENABLE;
3120203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
3121203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
3122203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
3123203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
3124203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
3125203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
3126203945Sweongyo		    | (trans << 1));
3127203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
3128203945Sweongyo		    sizeof(struct bwn_dmadesc64));
3129203945Sweongyo	} else {
3130203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
3131203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
3132203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
3133203945Sweongyo		value |= BWN_DMA32_RXENABLE;
3134203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
3135203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
3136203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
3137203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
3138203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
3139203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
3140203945Sweongyo		    sizeof(struct bwn_dmadesc32));
3141203945Sweongyo	}
3142203945Sweongyo}
3143203945Sweongyo
3144203945Sweongyostatic void
3145203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
3146203945Sweongyo{
3147203945Sweongyo
3148203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
3149203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
3150203945Sweongyo	    dr->dr_ring_dmap);
3151203945Sweongyo}
3152203945Sweongyo
3153203945Sweongyostatic void
3154203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
3155203945Sweongyo{
3156203945Sweongyo
3157203945Sweongyo	if (dr->dr_tx) {
3158203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
3159203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3160203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
3161203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
3162203945Sweongyo		} else
3163203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
3164203945Sweongyo	} else {
3165203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
3166203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
3167203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
3168203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
3169203945Sweongyo		} else
3170203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
3171203945Sweongyo	}
3172203945Sweongyo}
3173203945Sweongyo
3174203945Sweongyostatic void
3175203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
3176203945Sweongyo{
3177203945Sweongyo	struct bwn_dmadesc_generic *desc;
3178203945Sweongyo	struct bwn_dmadesc_meta *meta;
3179203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
3180203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3181203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3182203945Sweongyo	int i;
3183203945Sweongyo
3184203945Sweongyo	if (!dr->dr_usedslot)
3185203945Sweongyo		return;
3186203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
3187203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
3188203945Sweongyo
3189203945Sweongyo		if (meta->mt_m == NULL) {
3190203945Sweongyo			if (!dr->dr_tx)
3191203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
3192203945Sweongyo				    __func__);
3193203945Sweongyo			continue;
3194203945Sweongyo		}
3195203945Sweongyo		if (dr->dr_tx) {
3196203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
3197203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
3198203945Sweongyo				    meta->mt_dmap);
3199203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
3200203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
3201203945Sweongyo				    meta->mt_dmap);
3202203945Sweongyo		} else
3203203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
3204203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
3205203945Sweongyo	}
3206203945Sweongyo}
3207203945Sweongyo
3208203945Sweongyostatic int
3209203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
3210203945Sweongyo    int type)
3211203945Sweongyo{
3212203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3213203945Sweongyo	uint32_t value;
3214203945Sweongyo	int i;
3215203945Sweongyo	uint16_t offset;
3216203945Sweongyo
3217203945Sweongyo	for (i = 0; i < 10; i++) {
3218203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
3219203945Sweongyo		    BWN_DMA32_TXSTATUS;
3220203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3221203945Sweongyo		if (type == BWN_DMA_64BIT) {
3222203945Sweongyo			value &= BWN_DMA64_TXSTAT;
3223203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
3224203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
3225203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
3226203945Sweongyo				break;
3227203945Sweongyo		} else {
3228203945Sweongyo			value &= BWN_DMA32_TXSTATE;
3229203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
3230203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
3231203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
3232203945Sweongyo				break;
3233203945Sweongyo		}
3234203945Sweongyo		DELAY(1000);
3235203945Sweongyo	}
3236203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
3237203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
3238203945Sweongyo	for (i = 0; i < 10; i++) {
3239203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
3240203945Sweongyo						   BWN_DMA32_TXSTATUS;
3241203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3242203945Sweongyo		if (type == BWN_DMA_64BIT) {
3243203945Sweongyo			value &= BWN_DMA64_TXSTAT;
3244203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
3245203945Sweongyo				i = -1;
3246203945Sweongyo				break;
3247203945Sweongyo			}
3248203945Sweongyo		} else {
3249203945Sweongyo			value &= BWN_DMA32_TXSTATE;
3250203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
3251203945Sweongyo				i = -1;
3252203945Sweongyo				break;
3253203945Sweongyo			}
3254203945Sweongyo		}
3255203945Sweongyo		DELAY(1000);
3256203945Sweongyo	}
3257203945Sweongyo	if (i != -1) {
3258203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
3259203945Sweongyo		return (ENODEV);
3260203945Sweongyo	}
3261203945Sweongyo	DELAY(1000);
3262203945Sweongyo
3263203945Sweongyo	return (0);
3264203945Sweongyo}
3265203945Sweongyo
3266203945Sweongyostatic int
3267203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
3268203945Sweongyo    int type)
3269203945Sweongyo{
3270203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3271203945Sweongyo	uint32_t value;
3272203945Sweongyo	int i;
3273203945Sweongyo	uint16_t offset;
3274203945Sweongyo
3275203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
3276203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
3277203945Sweongyo	for (i = 0; i < 10; i++) {
3278203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
3279203945Sweongyo		    BWN_DMA32_RXSTATUS;
3280203945Sweongyo		value = BWN_READ_4(mac, base + offset);
3281203945Sweongyo		if (type == BWN_DMA_64BIT) {
3282203945Sweongyo			value &= BWN_DMA64_RXSTAT;
3283203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
3284203945Sweongyo				i = -1;
3285203945Sweongyo				break;
3286203945Sweongyo			}
3287203945Sweongyo		} else {
3288203945Sweongyo			value &= BWN_DMA32_RXSTATE;
3289203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
3290203945Sweongyo				i = -1;
3291203945Sweongyo				break;
3292203945Sweongyo			}
3293203945Sweongyo		}
3294203945Sweongyo		DELAY(1000);
3295203945Sweongyo	}
3296203945Sweongyo	if (i != -1) {
3297203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
3298203945Sweongyo		return (ENODEV);
3299203945Sweongyo	}
3300203945Sweongyo
3301203945Sweongyo	return (0);
3302203945Sweongyo}
3303203945Sweongyo
3304203945Sweongyostatic void
3305203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
3306203945Sweongyo    struct bwn_dmadesc_meta *meta)
3307203945Sweongyo{
3308203945Sweongyo
3309203945Sweongyo	if (meta->mt_m != NULL) {
3310203945Sweongyo		m_freem(meta->mt_m);
3311203945Sweongyo		meta->mt_m = NULL;
3312203945Sweongyo	}
3313203945Sweongyo	if (meta->mt_ni != NULL) {
3314203945Sweongyo		ieee80211_free_node(meta->mt_ni);
3315203945Sweongyo		meta->mt_ni = NULL;
3316203945Sweongyo	}
3317203945Sweongyo}
3318203945Sweongyo
3319203945Sweongyostatic void
3320203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
3321203945Sweongyo{
3322203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
3323203945Sweongyo	unsigned char *frame;
3324203945Sweongyo
3325203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
3326203945Sweongyo	rxhdr->frame_len = 0;
3327203945Sweongyo
3328203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
3329203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
3330203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3331203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
3332203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
3333203945Sweongyo}
3334203945Sweongyo
3335203945Sweongyostatic uint8_t
3336203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
3337203945Sweongyo{
3338203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
3339203945Sweongyo
3340203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
3341203945Sweongyo	    == 0xff);
3342203945Sweongyo}
3343203945Sweongyo
3344203945Sweongyostatic void
3345203945Sweongyobwn_wme_init(struct bwn_mac *mac)
3346203945Sweongyo{
3347203945Sweongyo
3348203945Sweongyo	bwn_wme_load(mac);
3349203945Sweongyo
3350203945Sweongyo	/* enable WME support. */
3351203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
3352203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
3353203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
3354203945Sweongyo}
3355203945Sweongyo
3356203945Sweongyostatic void
3357203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
3358203945Sweongyo{
3359203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3360287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3361203945Sweongyo	uint16_t delay;	/* microsec */
3362203945Sweongyo
3363203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
3364203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
3365203945Sweongyo		delay = 500;
3366203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
3367203945Sweongyo		delay = max(delay, (uint16_t)2400);
3368203945Sweongyo
3369203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
3370203945Sweongyo}
3371203945Sweongyo
3372203945Sweongyostatic void
3373203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
3374203945Sweongyo{
3375204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3376203945Sweongyo	uint64_t hf;
3377203945Sweongyo
3378203945Sweongyo	if (bwn_bluetooth == 0)
3379203945Sweongyo		return;
3380204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
3381203945Sweongyo		return;
3382203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
3383203945Sweongyo		return;
3384203945Sweongyo
3385203945Sweongyo	hf = bwn_hf_read(mac);
3386204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
3387203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
3388203945Sweongyo	else
3389203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
3390203945Sweongyo	bwn_hf_write(mac, hf);
3391203945Sweongyo}
3392203945Sweongyo
3393203945Sweongyostatic void
3394203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
3395203945Sweongyo{
3396203945Sweongyo
3397203945Sweongyo	bwn_mac_write_bssid(mac);
3398287197Sglebius	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF,
3399287197Sglebius	    mac->mac_sc->sc_ic.ic_macaddr);
3400203945Sweongyo}
3401203945Sweongyo
3402203945Sweongyostatic void
3403203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
3404203945Sweongyo{
3405203945Sweongyo	int i;
3406203945Sweongyo
3407203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
3408203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
3409203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3410203945Sweongyo
3411203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
3412203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
3413203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
3414203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
3415203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
3416203945Sweongyo		}
3417203945Sweongyo		mac->mac_key[i].keyconf = NULL;
3418203945Sweongyo	}
3419203945Sweongyo}
3420203945Sweongyo
3421203945Sweongyostatic void
3422203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
3423203945Sweongyo{
3424204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3425203945Sweongyo
3426204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
3427203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
3428203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3429203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
3430203945Sweongyo	mac->mac_ktp *= 2;
3431204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
3432204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
3433203945Sweongyo	bwn_clear_keys(mac);
3434203945Sweongyo}
3435203945Sweongyo
3436203945Sweongyostatic void
3437203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
3438203945Sweongyo{
3439204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3440203945Sweongyo
3441203945Sweongyo	bwn_phy_exit(mac);
3442204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
3443203945Sweongyo}
3444203945Sweongyo
3445203945Sweongyostatic int
3446203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
3447203945Sweongyo{
3448203945Sweongyo	int error;
3449203945Sweongyo
3450203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
3451203945Sweongyo	if (error == 0)
3452203945Sweongyo		return (0);
3453203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
3454203945Sweongyo	if (error == 0)
3455203945Sweongyo		return (0);
3456203945Sweongyo	return (error);
3457203945Sweongyo}
3458203945Sweongyo
3459203945Sweongyostatic int
3460203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
3461203945Sweongyo{
3462204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3463204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
3464203945Sweongyo
3465203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3466203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
3467203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
3468203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
3469203945Sweongyo
3470204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
3471203945Sweongyo		mask |= 0x0060;
3472203945Sweongyo		set |= 0x0060;
3473203945Sweongyo	}
3474204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
3475203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
3476203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
3477203945Sweongyo		mask |= 0x0200;
3478203945Sweongyo		set |= 0x0200;
3479203945Sweongyo	}
3480204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
3481203945Sweongyo		mask |= 0x0010;
3482204922Sweongyo
3483204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
3484204922Sweongyo	if (value == -1)
3485203945Sweongyo		return (0);
3486204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
3487203945Sweongyo
3488203945Sweongyo	return (0);
3489203945Sweongyo}
3490203945Sweongyo
3491203945Sweongyostatic int
3492203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
3493203945Sweongyo{
3494203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
3495203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
3496203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
3497203945Sweongyo	const struct bwn_fwhdr *hdr;
3498203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
3499203945Sweongyo	int error;
3500203945Sweongyo
3501203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
3502203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
3503203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
3504203945Sweongyo	if (error)
3505203945Sweongyo		return (error);
3506203945Sweongyo	if (fw->initvals_band.fw) {
3507203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
3508203945Sweongyo		error = bwn_fwinitvals_write(mac,
3509203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
3510203945Sweongyo		    be32toh(hdr->size),
3511203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
3512203945Sweongyo	}
3513203945Sweongyo	return (error);
3514203945Sweongyo#undef GETFWOFFSET
3515203945Sweongyo}
3516203945Sweongyo
3517203945Sweongyostatic int
3518203945Sweongyobwn_phy_init(struct bwn_mac *mac)
3519203945Sweongyo{
3520203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3521203945Sweongyo	int error;
3522203945Sweongyo
3523203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
3524203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
3525203945Sweongyo	error = mac->mac_phy.init(mac);
3526203945Sweongyo	if (error) {
3527203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
3528203945Sweongyo		goto fail0;
3529203945Sweongyo	}
3530203945Sweongyo	error = bwn_switch_channel(mac,
3531203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
3532203945Sweongyo	if (error) {
3533203945Sweongyo		device_printf(sc->sc_dev,
3534203945Sweongyo		    "failed to switch default channel\n");
3535203945Sweongyo		goto fail1;
3536203945Sweongyo	}
3537203945Sweongyo	return (0);
3538203945Sweongyofail1:
3539203945Sweongyo	if (mac->mac_phy.exit)
3540203945Sweongyo		mac->mac_phy.exit(mac);
3541203945Sweongyofail0:
3542203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
3543203945Sweongyo
3544203945Sweongyo	return (error);
3545203945Sweongyo}
3546203945Sweongyo
3547203945Sweongyostatic void
3548203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
3549203945Sweongyo{
3550203945Sweongyo	uint16_t ant;
3551203945Sweongyo	uint16_t tmp;
3552203945Sweongyo
3553203945Sweongyo	ant = bwn_ant2phy(antenna);
3554203945Sweongyo
3555203945Sweongyo	/* For ACK/CTS */
3556203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
3557203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
3558203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
3559203945Sweongyo	/* For Probe Resposes */
3560203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
3561203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
3562203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
3563203945Sweongyo}
3564203945Sweongyo
3565203945Sweongyostatic void
3566203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
3567203945Sweongyo{
3568203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3569287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3570203945Sweongyo	uint32_t ctl;
3571203945Sweongyo	uint16_t cfp_pretbtt;
3572203945Sweongyo
3573203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
3574203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
3575203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
3576203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
3577203945Sweongyo	ctl |= BWN_MACCTL_STA;
3578203945Sweongyo
3579203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
3580203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
3581203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
3582203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
3583203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
3584203945Sweongyo	ctl |= sc->sc_filters;
3585203945Sweongyo
3586204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
3587203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
3588203945Sweongyo
3589203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
3590203945Sweongyo
3591203945Sweongyo	cfp_pretbtt = 2;
3592203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
3593204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
3594204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
3595203945Sweongyo			cfp_pretbtt = 100;
3596203945Sweongyo		else
3597203945Sweongyo			cfp_pretbtt = 50;
3598203945Sweongyo	}
3599203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
3600203945Sweongyo}
3601203945Sweongyo
3602203945Sweongyostatic int
3603203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
3604203945Sweongyo{
3605203945Sweongyo	uint32_t tmp;
3606203945Sweongyo	uint16_t base;
3607203945Sweongyo
3608203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3609203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3610203945Sweongyo		return (BWN_DMA_64BIT);
3611203945Sweongyo	base = bwn_dma_base(0, 0);
3612203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3613203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3614203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3615203945Sweongyo		return (BWN_DMA_32BIT);
3616203945Sweongyo
3617203945Sweongyo	return (BWN_DMA_30BIT);
3618203945Sweongyo}
3619203945Sweongyo
3620203945Sweongyostatic void
3621203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
3622203945Sweongyo{
3623203945Sweongyo	if (!error) {
3624203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
3625203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
3626203945Sweongyo	}
3627203945Sweongyo}
3628203945Sweongyo
3629298948Sadrianvoid
3630298952Sadrianbwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
3631298952Sadrian{
3632298952Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3633298952Sadrian	struct bwn_softc *sc = mac->mac_sc;
3634298952Sadrian	unsigned int i, max_loop;
3635298952Sadrian	uint16_t value;
3636298952Sadrian	uint32_t buffer[5] = {
3637298952Sadrian		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
3638298952Sadrian	};
3639298952Sadrian
3640298952Sadrian	if (ofdm) {
3641298952Sadrian		max_loop = 0x1e;
3642298952Sadrian		buffer[0] = 0x000201cc;
3643298952Sadrian	} else {
3644298952Sadrian		max_loop = 0xfa;
3645298952Sadrian		buffer[0] = 0x000b846e;
3646298952Sadrian	}
3647298952Sadrian
3648298952Sadrian	BWN_ASSERT_LOCKED(mac->mac_sc);
3649298952Sadrian
3650298952Sadrian	for (i = 0; i < 5; i++)
3651298952Sadrian		bwn_ram_write(mac, i * 4, buffer[i]);
3652298952Sadrian
3653298952Sadrian	BWN_WRITE_2(mac, 0x0568, 0x0000);
3654298952Sadrian	BWN_WRITE_2(mac, 0x07c0,
3655298952Sadrian	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
3656298954Sadrian
3657298954Sadrian	value = (ofdm ? 0x41 : 0x40);
3658298952Sadrian	BWN_WRITE_2(mac, 0x050c, value);
3659298954Sadrian
3660298954Sadrian	if (phy->type == BWN_PHYTYPE_N || phy->type == BWN_PHYTYPE_LP ||
3661298954Sadrian	    phy->type == BWN_PHYTYPE_LCN)
3662298952Sadrian		BWN_WRITE_2(mac, 0x0514, 0x1a02);
3663298952Sadrian	BWN_WRITE_2(mac, 0x0508, 0x0000);
3664298952Sadrian	BWN_WRITE_2(mac, 0x050a, 0x0000);
3665298952Sadrian	BWN_WRITE_2(mac, 0x054c, 0x0000);
3666298952Sadrian	BWN_WRITE_2(mac, 0x056a, 0x0014);
3667298952Sadrian	BWN_WRITE_2(mac, 0x0568, 0x0826);
3668298952Sadrian	BWN_WRITE_2(mac, 0x0500, 0x0000);
3669298954Sadrian
3670298954Sadrian	/* XXX TODO: n phy pa override? */
3671298954Sadrian
3672298954Sadrian	switch (phy->type) {
3673298954Sadrian	case BWN_PHYTYPE_N:
3674298954Sadrian	case BWN_PHYTYPE_LCN:
3675298954Sadrian		BWN_WRITE_2(mac, 0x0502, 0x00d0);
3676298954Sadrian		break;
3677298954Sadrian	case BWN_PHYTYPE_LP:
3678298952Sadrian		BWN_WRITE_2(mac, 0x0502, 0x0050);
3679298954Sadrian		break;
3680298954Sadrian	default:
3681298952Sadrian		BWN_WRITE_2(mac, 0x0502, 0x0030);
3682298954Sadrian		break;
3683298954Sadrian	}
3684298952Sadrian
3685298954Sadrian	/* flush */
3686298954Sadrian	BWN_READ_2(mac, 0x0502);
3687298954Sadrian
3688298952Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
3689298952Sadrian		BWN_RF_WRITE(mac, 0x0051, 0x0017);
3690298952Sadrian	for (i = 0x00; i < max_loop; i++) {
3691298952Sadrian		value = BWN_READ_2(mac, 0x050e);
3692298952Sadrian		if (value & 0x0080)
3693298952Sadrian			break;
3694298952Sadrian		DELAY(10);
3695298952Sadrian	}
3696298952Sadrian	for (i = 0x00; i < 0x0a; i++) {
3697298952Sadrian		value = BWN_READ_2(mac, 0x050e);
3698298952Sadrian		if (value & 0x0400)
3699298952Sadrian			break;
3700298952Sadrian		DELAY(10);
3701298952Sadrian	}
3702298952Sadrian	for (i = 0x00; i < 0x19; i++) {
3703298952Sadrian		value = BWN_READ_2(mac, 0x0690);
3704298952Sadrian		if (!(value & 0x0100))
3705298952Sadrian			break;
3706298952Sadrian		DELAY(10);
3707298952Sadrian	}
3708298952Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
3709298952Sadrian		BWN_RF_WRITE(mac, 0x0051, 0x0037);
3710298952Sadrian}
3711298952Sadrian
3712298952Sadrianvoid
3713203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
3714203945Sweongyo{
3715203945Sweongyo	uint32_t macctl;
3716203945Sweongyo
3717203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
3718203945Sweongyo
3719203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3720203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
3721203945Sweongyo		printf("TODO: need swap\n");
3722203945Sweongyo
3723203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
3724203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
3725203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
3726203945Sweongyo}
3727203945Sweongyo
3728298944Sadrianvoid
3729203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
3730203945Sweongyo{
3731203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3732203945Sweongyo	int i;
3733203945Sweongyo	uint32_t tmp;
3734203945Sweongyo
3735203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
3736203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3737203945Sweongyo
3738300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: suspended=%d\n",
3739300189Sadrian	    __func__, mac->mac_suspended);
3740300189Sadrian
3741203945Sweongyo	if (mac->mac_suspended == 0) {
3742203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
3743203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
3744203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
3745203945Sweongyo			    & ~BWN_MACCTL_ON);
3746203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
3747203945Sweongyo		for (i = 35; i; i--) {
3748203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
3749203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
3750203945Sweongyo				goto out;
3751203945Sweongyo			DELAY(10);
3752203945Sweongyo		}
3753203945Sweongyo		for (i = 40; i; i--) {
3754203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
3755203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
3756203945Sweongyo				goto out;
3757203945Sweongyo			DELAY(1000);
3758203945Sweongyo		}
3759203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
3760203945Sweongyo	}
3761203945Sweongyoout:
3762203945Sweongyo	mac->mac_suspended++;
3763203945Sweongyo}
3764203945Sweongyo
3765298944Sadrianvoid
3766203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
3767203945Sweongyo{
3768203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3769203945Sweongyo	uint16_t state;
3770203945Sweongyo
3771300189Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: suspended=%d\n",
3772300189Sadrian	    __func__, mac->mac_suspended);
3773300189Sadrian
3774203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
3775203945Sweongyo	    BWN_SHARED_UCODESTAT);
3776203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
3777300195Sadrian	    state != BWN_SHARED_UCODESTAT_SLEEP) {
3778300195Sadrian		DPRINTF(sc, BWN_DEBUG_FW,
3779300195Sadrian		    "%s: warn: firmware state (%d)\n",
3780300195Sadrian		    __func__, state);
3781300195Sadrian	}
3782203945Sweongyo
3783203945Sweongyo	mac->mac_suspended--;
3784203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
3785203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3786203945Sweongyo	if (mac->mac_suspended == 0) {
3787203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
3788203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
3789203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
3790203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
3791203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
3792203945Sweongyo		bwn_psctl(mac, 0);
3793203945Sweongyo	}
3794203945Sweongyo}
3795203945Sweongyo
3796298948Sadrianvoid
3797203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
3798203945Sweongyo{
3799204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3800203945Sweongyo	int i;
3801203945Sweongyo	uint16_t ucstat;
3802203945Sweongyo
3803203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
3804203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3805203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
3806203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3807203945Sweongyo
3808203945Sweongyo	/* XXX forcibly awake and hwps-off */
3809203945Sweongyo
3810203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3811203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
3812203945Sweongyo	    ~BWN_MACCTL_HWPS);
3813203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
3814204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
3815203945Sweongyo		for (i = 0; i < 100; i++) {
3816203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
3817203945Sweongyo			    BWN_SHARED_UCODESTAT);
3818203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
3819203945Sweongyo				break;
3820203945Sweongyo			DELAY(10);
3821203945Sweongyo		}
3822203945Sweongyo	}
3823300114Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: ucstat=%d\n", __func__,
3824300114Sadrian	    ucstat);
3825203945Sweongyo}
3826203945Sweongyo
3827203945Sweongyostatic int
3828203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
3829203945Sweongyo{
3830203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3831203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
3832204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
3833203945Sweongyo	const char *filename;
3834203945Sweongyo	uint32_t high;
3835203945Sweongyo	int error;
3836203945Sweongyo
3837203945Sweongyo	/* microcode */
3838299780Sadrian	filename = NULL;
3839299780Sadrian	switch (rev) {
3840299780Sadrian	case 42:
3841299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_AC)
3842299780Sadrian			filename = "ucode42";
3843299780Sadrian		break;
3844299780Sadrian	case 40:
3845299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_AC)
3846299780Sadrian			filename = "ucode40";
3847299780Sadrian		break;
3848299780Sadrian	case 33:
3849299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_LCN40)
3850299780Sadrian			filename = "ucode33_lcn40";
3851299780Sadrian		break;
3852299780Sadrian	case 30:
3853299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3854299780Sadrian			filename = "ucode30_mimo";
3855299780Sadrian		break;
3856299780Sadrian	case 29:
3857299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_HT)
3858299780Sadrian			filename = "ucode29_mimo";
3859299780Sadrian		break;
3860299780Sadrian	case 26:
3861299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_HT)
3862299780Sadrian			filename = "ucode26_mimo";
3863299780Sadrian		break;
3864299780Sadrian	case 28:
3865299780Sadrian	case 25:
3866299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3867299780Sadrian			filename = "ucode25_mimo";
3868299780Sadrian		else if (mac->mac_phy.type == BWN_PHYTYPE_LCN)
3869299780Sadrian			filename = "ucode25_lcn";
3870299780Sadrian		break;
3871299780Sadrian	case 24:
3872299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_LCN)
3873299780Sadrian			filename = "ucode24_lcn";
3874299780Sadrian		break;
3875299780Sadrian	case 23:
3876299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3877299780Sadrian			filename = "ucode16_mimo";
3878299780Sadrian		break;
3879299780Sadrian	case 16:
3880299780Sadrian	case 17:
3881299780Sadrian	case 18:
3882299780Sadrian	case 19:
3883299780Sadrian		if (mac->mac_phy.type == BWN_PHYTYPE_N)
3884299780Sadrian			filename = "ucode16_mimo";
3885299780Sadrian		else if (mac->mac_phy.type == BWN_PHYTYPE_LP)
3886299780Sadrian			filename = "ucode16_lp";
3887299780Sadrian		break;
3888299780Sadrian	case 15:
3889299780Sadrian		filename = "ucode15";
3890299780Sadrian		break;
3891299780Sadrian	case 14:
3892299780Sadrian		filename = "ucode14";
3893299780Sadrian		break;
3894299780Sadrian	case 13:
3895299780Sadrian		filename = "ucode13";
3896299780Sadrian		break;
3897299780Sadrian	case 12:
3898299780Sadrian	case 11:
3899299780Sadrian		filename = "ucode11";
3900299780Sadrian		break;
3901299780Sadrian	case 10:
3902299780Sadrian	case 9:
3903299780Sadrian	case 8:
3904299780Sadrian	case 7:
3905299780Sadrian	case 6:
3906299780Sadrian	case 5:
3907203945Sweongyo		filename = "ucode5";
3908299780Sadrian		break;
3909299780Sadrian	default:
3910203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
3911203945Sweongyo		bwn_release_firmware(mac);
3912203945Sweongyo		return (EOPNOTSUPP);
3913203945Sweongyo	}
3914299780Sadrian
3915299780Sadrian	device_printf(sc->sc_dev, "ucode fw: %s\n", filename);
3916203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
3917203945Sweongyo	if (error) {
3918203945Sweongyo		bwn_release_firmware(mac);
3919203945Sweongyo		return (error);
3920203945Sweongyo	}
3921203945Sweongyo
3922203945Sweongyo	/* PCM */
3923203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
3924203945Sweongyo	if (rev >= 5 && rev <= 10) {
3925203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
3926203945Sweongyo		if (error == ENOENT)
3927203945Sweongyo			fw->no_pcmfile = 1;
3928203945Sweongyo		else if (error) {
3929203945Sweongyo			bwn_release_firmware(mac);
3930203945Sweongyo			return (error);
3931203945Sweongyo		}
3932203945Sweongyo	} else if (rev < 11) {
3933203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
3934203945Sweongyo		return (EOPNOTSUPP);
3935203945Sweongyo	}
3936203945Sweongyo
3937203945Sweongyo	/* initvals */
3938204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
3939203945Sweongyo	switch (mac->mac_phy.type) {
3940203945Sweongyo	case BWN_PHYTYPE_A:
3941203945Sweongyo		if (rev < 5 || rev > 10)
3942203945Sweongyo			goto fail1;
3943203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
3944203945Sweongyo			filename = "a0g1initvals5";
3945203945Sweongyo		else
3946203945Sweongyo			filename = "a0g0initvals5";
3947203945Sweongyo		break;
3948203945Sweongyo	case BWN_PHYTYPE_G:
3949203945Sweongyo		if (rev >= 5 && rev <= 10)
3950203945Sweongyo			filename = "b0g0initvals5";
3951203945Sweongyo		else if (rev >= 13)
3952203945Sweongyo			filename = "b0g0initvals13";
3953203945Sweongyo		else
3954203945Sweongyo			goto fail1;
3955203945Sweongyo		break;
3956203945Sweongyo	case BWN_PHYTYPE_LP:
3957203945Sweongyo		if (rev == 13)
3958203945Sweongyo			filename = "lp0initvals13";
3959203945Sweongyo		else if (rev == 14)
3960203945Sweongyo			filename = "lp0initvals14";
3961203945Sweongyo		else if (rev >= 15)
3962203945Sweongyo			filename = "lp0initvals15";
3963203945Sweongyo		else
3964203945Sweongyo			goto fail1;
3965203945Sweongyo		break;
3966203945Sweongyo	case BWN_PHYTYPE_N:
3967299780Sadrian		if (rev == 30)
3968299780Sadrian			filename = "n16initvals30";
3969299780Sadrian		else if (rev == 28 || rev == 25)
3970299780Sadrian			filename = "n0initvals25";
3971299780Sadrian		else if (rev == 24)
3972299780Sadrian			filename = "n0initvals24";
3973299780Sadrian		else if (rev == 23)
3974299780Sadrian			filename = "n0initvals16";
3975299780Sadrian		else if (rev >= 16 && rev <= 18)
3976299780Sadrian			filename = "n0initvals16";
3977299780Sadrian		else if (rev >= 11 && rev <= 12)
3978203945Sweongyo			filename = "n0initvals11";
3979203945Sweongyo		else
3980203945Sweongyo			goto fail1;
3981203945Sweongyo		break;
3982203945Sweongyo	default:
3983203945Sweongyo		goto fail1;
3984203945Sweongyo	}
3985203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
3986203945Sweongyo	if (error) {
3987203945Sweongyo		bwn_release_firmware(mac);
3988203945Sweongyo		return (error);
3989203945Sweongyo	}
3990203945Sweongyo
3991203945Sweongyo	/* bandswitch initvals */
3992203945Sweongyo	switch (mac->mac_phy.type) {
3993203945Sweongyo	case BWN_PHYTYPE_A:
3994203945Sweongyo		if (rev >= 5 && rev <= 10) {
3995203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
3996203945Sweongyo				filename = "a0g1bsinitvals5";
3997203945Sweongyo			else
3998203945Sweongyo				filename = "a0g0bsinitvals5";
3999203945Sweongyo		} else if (rev >= 11)
4000203945Sweongyo			filename = NULL;
4001203945Sweongyo		else
4002203945Sweongyo			goto fail1;
4003203945Sweongyo		break;
4004203945Sweongyo	case BWN_PHYTYPE_G:
4005203945Sweongyo		if (rev >= 5 && rev <= 10)
4006203945Sweongyo			filename = "b0g0bsinitvals5";
4007203945Sweongyo		else if (rev >= 11)
4008203945Sweongyo			filename = NULL;
4009203945Sweongyo		else
4010203945Sweongyo			goto fail1;
4011203945Sweongyo		break;
4012203945Sweongyo	case BWN_PHYTYPE_LP:
4013203945Sweongyo		if (rev == 13)
4014203945Sweongyo			filename = "lp0bsinitvals13";
4015203945Sweongyo		else if (rev == 14)
4016203945Sweongyo			filename = "lp0bsinitvals14";
4017203945Sweongyo		else if (rev >= 15)
4018203945Sweongyo			filename = "lp0bsinitvals15";
4019203945Sweongyo		else
4020203945Sweongyo			goto fail1;
4021203945Sweongyo		break;
4022203945Sweongyo	case BWN_PHYTYPE_N:
4023299780Sadrian		if (rev == 30)
4024299780Sadrian			filename = "n16bsinitvals30";
4025299780Sadrian		else if (rev == 28 || rev == 25)
4026299780Sadrian			filename = "n0bsinitvals25";
4027299780Sadrian		else if (rev == 24)
4028299780Sadrian			filename = "n0bsinitvals24";
4029299780Sadrian		else if (rev == 23)
4030299780Sadrian			filename = "n0bsinitvals16";
4031299780Sadrian		else if (rev >= 16 && rev <= 18)
4032299780Sadrian			filename = "n0bsinitvals16";
4033299780Sadrian		else if (rev >= 11 && rev <= 12)
4034203945Sweongyo			filename = "n0bsinitvals11";
4035203945Sweongyo		else
4036203945Sweongyo			goto fail1;
4037203945Sweongyo		break;
4038203945Sweongyo	default:
4039299780Sadrian		device_printf(sc->sc_dev, "unknown phy (%d)\n",
4040299780Sadrian		    mac->mac_phy.type);
4041203945Sweongyo		goto fail1;
4042203945Sweongyo	}
4043203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
4044203945Sweongyo	if (error) {
4045203945Sweongyo		bwn_release_firmware(mac);
4046203945Sweongyo		return (error);
4047203945Sweongyo	}
4048203945Sweongyo	return (0);
4049203945Sweongyofail1:
4050299780Sadrian	device_printf(sc->sc_dev, "no INITVALS for rev %d, phy.type %d\n",
4051299780Sadrian	    rev, mac->mac_phy.type);
4052203945Sweongyo	bwn_release_firmware(mac);
4053203945Sweongyo	return (EOPNOTSUPP);
4054203945Sweongyo}
4055203945Sweongyo
4056203945Sweongyostatic int
4057203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
4058203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
4059203945Sweongyo{
4060203945Sweongyo	const struct bwn_fwhdr *hdr;
4061203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4062203945Sweongyo	const struct firmware *fw;
4063203945Sweongyo	char namebuf[64];
4064203945Sweongyo
4065203945Sweongyo	if (name == NULL) {
4066203945Sweongyo		bwn_do_release_fw(bfw);
4067203945Sweongyo		return (0);
4068203945Sweongyo	}
4069203945Sweongyo	if (bfw->filename != NULL) {
4070203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
4071203945Sweongyo			return (0);
4072203945Sweongyo		bwn_do_release_fw(bfw);
4073203945Sweongyo	}
4074203945Sweongyo
4075204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
4076204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
4077204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
4078203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
4079203945Sweongyo	fw = firmware_get(namebuf);
4080203945Sweongyo	if (fw == NULL) {
4081203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
4082203945Sweongyo		    namebuf);
4083203945Sweongyo		return (ENOENT);
4084203945Sweongyo	}
4085203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
4086203945Sweongyo		goto fail;
4087203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
4088203945Sweongyo	switch (hdr->type) {
4089203945Sweongyo	case BWN_FWTYPE_UCODE:
4090203945Sweongyo	case BWN_FWTYPE_PCM:
4091203945Sweongyo		if (be32toh(hdr->size) !=
4092203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
4093203945Sweongyo			goto fail;
4094203945Sweongyo		/* FALLTHROUGH */
4095203945Sweongyo	case BWN_FWTYPE_IV:
4096203945Sweongyo		if (hdr->ver != 1)
4097203945Sweongyo			goto fail;
4098203945Sweongyo		break;
4099203945Sweongyo	default:
4100203945Sweongyo		goto fail;
4101203945Sweongyo	}
4102203945Sweongyo	bfw->filename = name;
4103203945Sweongyo	bfw->fw = fw;
4104203945Sweongyo	bfw->type = type;
4105203945Sweongyo	return (0);
4106203945Sweongyofail:
4107203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
4108203945Sweongyo	if (fw != NULL)
4109203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
4110203945Sweongyo	return (EPROTO);
4111203945Sweongyo}
4112203945Sweongyo
4113203945Sweongyostatic void
4114203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
4115203945Sweongyo{
4116203945Sweongyo
4117203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
4118203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
4119203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
4120203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
4121203945Sweongyo}
4122203945Sweongyo
4123203945Sweongyostatic void
4124203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
4125203945Sweongyo{
4126203945Sweongyo
4127203945Sweongyo	if (bfw->fw != NULL)
4128203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
4129203945Sweongyo	bfw->fw = NULL;
4130203945Sweongyo	bfw->filename = NULL;
4131203945Sweongyo}
4132203945Sweongyo
4133203945Sweongyostatic int
4134203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
4135203945Sweongyo{
4136203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
4137203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
4138203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
4139203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
4140203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4141203945Sweongyo	const uint32_t *data;
4142203945Sweongyo	unsigned int i;
4143203945Sweongyo	uint32_t ctl;
4144203945Sweongyo	uint16_t date, fwcaps, time;
4145203945Sweongyo	int error = 0;
4146203945Sweongyo
4147203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4148203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
4149203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
4150203945Sweongyo	    __LINE__));
4151203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4152203945Sweongyo	for (i = 0; i < 64; i++)
4153203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
4154203945Sweongyo	for (i = 0; i < 4096; i += 2)
4155203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
4156203945Sweongyo
4157203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
4158203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
4159203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
4160203945Sweongyo	     i++) {
4161203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
4162203945Sweongyo		DELAY(10);
4163203945Sweongyo	}
4164203945Sweongyo
4165203945Sweongyo	if (mac->mac_fw.pcm.fw) {
4166203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
4167203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
4168203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
4169203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
4170203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
4171203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
4172203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
4173203945Sweongyo			DELAY(10);
4174203945Sweongyo		}
4175203945Sweongyo	}
4176203945Sweongyo
4177203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
4178203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4179203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
4180203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
4181203945Sweongyo
4182203945Sweongyo	for (i = 0; i < 21; i++) {
4183203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
4184203945Sweongyo			break;
4185203945Sweongyo		if (i >= 20) {
4186203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
4187203945Sweongyo			error = ENXIO;
4188203945Sweongyo			goto error;
4189203945Sweongyo		}
4190203945Sweongyo		DELAY(50000);
4191203945Sweongyo	}
4192203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
4193203945Sweongyo
4194203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
4195203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
4196203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
4197203945Sweongyo		error = EOPNOTSUPP;
4198203945Sweongyo		goto error;
4199203945Sweongyo	}
4200299110Sadrian
4201299110Sadrian	/*
4202299110Sadrian	 * Determine firmware header version; needed for TX/RX packet
4203299110Sadrian	 * handling.
4204299110Sadrian	 */
4205299110Sadrian	if (mac->mac_fw.rev >= 598)
4206299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_598;
4207299110Sadrian	else if (mac->mac_fw.rev >= 410)
4208299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_410;
4209299110Sadrian	else
4210299110Sadrian		mac->mac_fw.fw_hdr_format = BWN_FW_HDR_351;
4211299110Sadrian
4212299110Sadrian	/*
4213299110Sadrian	 * We don't support rev 598 or later; that requires
4214299110Sadrian	 * another round of changes to the TX/RX descriptor
4215299110Sadrian	 * and status layout.
4216299110Sadrian	 *
4217299110Sadrian	 * So, complain this is the case and exit out, rather
4218299110Sadrian	 * than attaching and then failing.
4219299110Sadrian	 */
4220300114Sadrian#if 0
4221299110Sadrian	if (mac->mac_fw.fw_hdr_format == BWN_FW_HDR_598) {
4222299110Sadrian		device_printf(sc->sc_dev,
4223299110Sadrian		    "firmware is too new (>=598); not supported\n");
4224299110Sadrian		error = EOPNOTSUPP;
4225299110Sadrian		goto error;
4226299110Sadrian	}
4227300114Sadrian#endif
4228299110Sadrian
4229203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
4230203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
4231203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
4232203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
4233203945Sweongyo	if (bwn_wme != 0)
4234203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
4235203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
4236203945Sweongyo
4237203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
4238203945Sweongyo	if (mac->mac_fw.opensource == 0) {
4239203945Sweongyo		device_printf(sc->sc_dev,
4240203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
4241203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
4242203945Sweongyo		if (mac->mac_fw.no_pcmfile)
4243203945Sweongyo			device_printf(sc->sc_dev,
4244203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
4245203945Sweongyo	} else {
4246203945Sweongyo		mac->mac_fw.patch = time;
4247203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
4248203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
4249203945Sweongyo			device_printf(sc->sc_dev,
4250203945Sweongyo			    "disabling HW crypto acceleration\n");
4251203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
4252203945Sweongyo		}
4253203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
4254203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
4255203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
4256203945Sweongyo		}
4257203945Sweongyo	}
4258203945Sweongyo
4259203945Sweongyo	if (BWN_ISOLDFMT(mac))
4260203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
4261203945Sweongyo
4262203945Sweongyo	return (0);
4263203945Sweongyo
4264203945Sweongyoerror:
4265203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4266203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
4267203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
4268203945Sweongyo
4269203945Sweongyo	return (error);
4270203945Sweongyo#undef GETFWSIZE
4271203945Sweongyo#undef GETFWOFFSET
4272203945Sweongyo}
4273203945Sweongyo
4274203945Sweongyo/* OpenFirmware only */
4275203945Sweongyostatic uint16_t
4276203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
4277203945Sweongyo{
4278203945Sweongyo
4279203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
4280203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4281203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
4282203945Sweongyo}
4283203945Sweongyo
4284203945Sweongyostatic int
4285203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
4286203945Sweongyo    size_t count, size_t array_size)
4287203945Sweongyo{
4288203945Sweongyo#define	GET_NEXTIV16(iv)						\
4289203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
4290203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
4291203945Sweongyo#define	GET_NEXTIV32(iv)						\
4292203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
4293203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
4294203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4295203945Sweongyo	const struct bwn_fwinitvals *iv;
4296203945Sweongyo	uint16_t offset;
4297203945Sweongyo	size_t i;
4298203945Sweongyo	uint8_t bit32;
4299203945Sweongyo
4300203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
4301203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4302203945Sweongyo	iv = ivals;
4303203945Sweongyo	for (i = 0; i < count; i++) {
4304203945Sweongyo		if (array_size < sizeof(iv->offset_size))
4305203945Sweongyo			goto fail;
4306203945Sweongyo		array_size -= sizeof(iv->offset_size);
4307203945Sweongyo		offset = be16toh(iv->offset_size);
4308203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
4309203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
4310203945Sweongyo		if (offset >= 0x1000)
4311203945Sweongyo			goto fail;
4312203945Sweongyo		if (bit32) {
4313203945Sweongyo			if (array_size < sizeof(iv->data.d32))
4314203945Sweongyo				goto fail;
4315203945Sweongyo			array_size -= sizeof(iv->data.d32);
4316203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
4317203945Sweongyo			iv = GET_NEXTIV32(iv);
4318203945Sweongyo		} else {
4319203945Sweongyo
4320203945Sweongyo			if (array_size < sizeof(iv->data.d16))
4321203945Sweongyo				goto fail;
4322203945Sweongyo			array_size -= sizeof(iv->data.d16);
4323203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
4324203945Sweongyo
4325203945Sweongyo			iv = GET_NEXTIV16(iv);
4326203945Sweongyo		}
4327203945Sweongyo	}
4328203945Sweongyo	if (array_size != 0)
4329203945Sweongyo		goto fail;
4330203945Sweongyo	return (0);
4331203945Sweongyofail:
4332203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
4333203945Sweongyo	return (EPROTO);
4334203945Sweongyo#undef GET_NEXTIV16
4335203945Sweongyo#undef GET_NEXTIV32
4336203945Sweongyo}
4337203945Sweongyo
4338298948Sadrianint
4339203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
4340203945Sweongyo{
4341203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
4342203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4343287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4344203945Sweongyo	uint16_t channelcookie, savedcookie;
4345203945Sweongyo	int error;
4346203945Sweongyo
4347203945Sweongyo	if (chan == 0xffff)
4348203945Sweongyo		chan = phy->get_default_chan(mac);
4349203945Sweongyo
4350203945Sweongyo	channelcookie = chan;
4351203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
4352203945Sweongyo		channelcookie |= 0x100;
4353203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
4354203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
4355203945Sweongyo	error = phy->switch_channel(mac, chan);
4356203945Sweongyo	if (error)
4357203945Sweongyo		goto fail;
4358203945Sweongyo
4359203945Sweongyo	mac->mac_phy.chan = chan;
4360203945Sweongyo	DELAY(8000);
4361203945Sweongyo	return (0);
4362203945Sweongyofail:
4363203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
4364203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
4365203945Sweongyo	return (error);
4366203945Sweongyo}
4367203945Sweongyo
4368203945Sweongyostatic uint16_t
4369203945Sweongyobwn_ant2phy(int antenna)
4370203945Sweongyo{
4371203945Sweongyo
4372203945Sweongyo	switch (antenna) {
4373203945Sweongyo	case BWN_ANT0:
4374203945Sweongyo		return (BWN_TX_PHY_ANT0);
4375203945Sweongyo	case BWN_ANT1:
4376203945Sweongyo		return (BWN_TX_PHY_ANT1);
4377203945Sweongyo	case BWN_ANT2:
4378203945Sweongyo		return (BWN_TX_PHY_ANT2);
4379203945Sweongyo	case BWN_ANT3:
4380203945Sweongyo		return (BWN_TX_PHY_ANT3);
4381203945Sweongyo	case BWN_ANTAUTO:
4382203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
4383203945Sweongyo	}
4384203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
4385203945Sweongyo	return (0);
4386203945Sweongyo}
4387203945Sweongyo
4388203945Sweongyostatic void
4389203945Sweongyobwn_wme_load(struct bwn_mac *mac)
4390203945Sweongyo{
4391203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4392203945Sweongyo	int i;
4393203945Sweongyo
4394203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
4395203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4396203945Sweongyo
4397203945Sweongyo	bwn_mac_suspend(mac);
4398203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
4399203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
4400203945Sweongyo		    bwn_wme_shm_offsets[i]);
4401203945Sweongyo	bwn_mac_enable(mac);
4402203945Sweongyo}
4403203945Sweongyo
4404203945Sweongyostatic void
4405203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
4406203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
4407203945Sweongyo{
4408203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
4409203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4410203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
4411203945Sweongyo	int slot, tmp;
4412203945Sweongyo	unsigned int i;
4413203945Sweongyo
4414203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
4415203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4416203945Sweongyo
4417203945Sweongyo	memset(&params, 0, sizeof(params));
4418203945Sweongyo
4419203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
4420203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
4421203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
4422203945Sweongyo
4423203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
4424203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4425203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
4426203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
4427203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
4428203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
4429203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
4430203945Sweongyo
4431203945Sweongyo	for (i = 0; i < N(params); i++) {
4432203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
4433203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
4434203945Sweongyo			    shm_offset + (i * 2));
4435203945Sweongyo			tmp |= 0x100;
4436203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
4437203945Sweongyo			    tmp);
4438203945Sweongyo		} else {
4439203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
4440203945Sweongyo			    params[i]);
4441203945Sweongyo		}
4442203945Sweongyo	}
4443203945Sweongyo}
4444203945Sweongyo
4445203945Sweongyostatic void
4446203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
4447203945Sweongyo{
4448203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4449203945Sweongyo	uint32_t tmp;
4450203945Sweongyo	int i;
4451203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
4452203945Sweongyo
4453203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
4454287197Sglebius	memcpy(mac_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
4455203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
4456203945Sweongyo	    IEEE80211_ADDR_LEN);
4457203945Sweongyo
4458203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
4459203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
4460203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
4461203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
4462203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
4463203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
4464203945Sweongyo	}
4465203945Sweongyo}
4466203945Sweongyo
4467203945Sweongyostatic void
4468203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
4469203945Sweongyo    const uint8_t *macaddr)
4470203945Sweongyo{
4471203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
4472203945Sweongyo	uint16_t data;
4473203945Sweongyo
4474203945Sweongyo	if (!mac)
4475203945Sweongyo		macaddr = zero;
4476203945Sweongyo
4477203945Sweongyo	offset |= 0x0020;
4478203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
4479203945Sweongyo
4480203945Sweongyo	data = macaddr[0];
4481203945Sweongyo	data |= macaddr[1] << 8;
4482203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4483203945Sweongyo	data = macaddr[2];
4484203945Sweongyo	data |= macaddr[3] << 8;
4485203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4486203945Sweongyo	data = macaddr[4];
4487203945Sweongyo	data |= macaddr[5] << 8;
4488203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
4489203945Sweongyo}
4490203945Sweongyo
4491203945Sweongyostatic void
4492203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
4493203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
4494203945Sweongyo{
4495203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
4496203945Sweongyo	uint8_t per_sta_keys_start = 8;
4497203945Sweongyo
4498203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
4499203945Sweongyo		per_sta_keys_start = 4;
4500203945Sweongyo
4501203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
4502203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4503203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
4504203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4505203945Sweongyo
4506203945Sweongyo	if (index >= per_sta_keys_start)
4507203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
4508203945Sweongyo	if (key)
4509203945Sweongyo		memcpy(buf, key, key_len);
4510203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
4511203945Sweongyo	if (index >= per_sta_keys_start)
4512203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
4513203945Sweongyo
4514203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
4515203945Sweongyo}
4516203945Sweongyo
4517203945Sweongyostatic void
4518203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
4519203945Sweongyo{
4520204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4521203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
4522203945Sweongyo	uint8_t start = 8;
4523203945Sweongyo
4524203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
4525203945Sweongyo		start = 4;
4526203945Sweongyo
4527203945Sweongyo	KASSERT(index >= start,
4528203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4529203945Sweongyo	index -= start;
4530203945Sweongyo
4531203945Sweongyo	if (addr) {
4532203945Sweongyo		addrtmp[0] = addr[0];
4533203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
4534203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
4535203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
4536203945Sweongyo		addrtmp[1] = addr[4];
4537203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
4538203945Sweongyo	}
4539203945Sweongyo
4540204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
4541203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
4542203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
4543203945Sweongyo	} else {
4544203945Sweongyo		if (index >= 8) {
4545203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
4546203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
4547203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
4548203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
4549203945Sweongyo		}
4550203945Sweongyo	}
4551203945Sweongyo}
4552203945Sweongyo
4553203945Sweongyostatic void
4554203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
4555203945Sweongyo    const uint8_t *key)
4556203945Sweongyo{
4557203945Sweongyo	unsigned int i;
4558203945Sweongyo	uint32_t offset;
4559203945Sweongyo	uint16_t kidx, value;
4560203945Sweongyo
4561203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
4562203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
4563203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
4564203945Sweongyo
4565203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
4566203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
4567203945Sweongyo		value = key[i];
4568203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
4569203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
4570203945Sweongyo	}
4571203945Sweongyo}
4572203945Sweongyo
4573203945Sweongyostatic void
4574203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
4575203945Sweongyo{
4576203945Sweongyo
4577203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4578203945Sweongyo	if (mac->mac_phy.exit != NULL)
4579203945Sweongyo		mac->mac_phy.exit(mac);
4580203945Sweongyo}
4581203945Sweongyo
4582203945Sweongyostatic void
4583203945Sweongyobwn_dma_free(struct bwn_mac *mac)
4584203945Sweongyo{
4585203945Sweongyo	struct bwn_dma *dma;
4586203945Sweongyo
4587203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
4588203945Sweongyo		return;
4589203945Sweongyo	dma = &mac->mac_method.dma;
4590203945Sweongyo
4591203945Sweongyo	bwn_dma_ringfree(&dma->rx);
4592203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
4593203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
4594203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
4595203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
4596203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
4597203945Sweongyo}
4598203945Sweongyo
4599203945Sweongyostatic void
4600203945Sweongyobwn_core_stop(struct bwn_mac *mac)
4601203945Sweongyo{
4602203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4603203945Sweongyo
4604203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4605203945Sweongyo
4606203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
4607203945Sweongyo		return;
4608203945Sweongyo
4609203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
4610203945Sweongyo	callout_stop(&sc->sc_task_ch);
4611203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
4612203945Sweongyo	sc->sc_watchdog_timer = 0;
4613203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
4614203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
4615203945Sweongyo	bwn_mac_suspend(mac);
4616203945Sweongyo
4617203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
4618203945Sweongyo}
4619203945Sweongyo
4620203945Sweongyostatic int
4621203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
4622203945Sweongyo{
4623203945Sweongyo	struct bwn_mac *up_dev = NULL;
4624203945Sweongyo	struct bwn_mac *down_dev;
4625203945Sweongyo	struct bwn_mac *mac;
4626203945Sweongyo	int err, status;
4627203945Sweongyo	uint8_t gmode;
4628203945Sweongyo
4629203945Sweongyo	BWN_ASSERT_LOCKED(sc);
4630203945Sweongyo
4631203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
4632203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
4633203945Sweongyo		    mac->mac_phy.supports_2ghz) {
4634203945Sweongyo			up_dev = mac;
4635203945Sweongyo			gmode = 1;
4636203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
4637203945Sweongyo		    mac->mac_phy.supports_5ghz) {
4638203945Sweongyo			up_dev = mac;
4639203945Sweongyo			gmode = 0;
4640203945Sweongyo		} else {
4641203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
4642203945Sweongyo			return (EINVAL);
4643203945Sweongyo		}
4644203945Sweongyo		if (up_dev != NULL)
4645203945Sweongyo			break;
4646203945Sweongyo	}
4647203945Sweongyo	if (up_dev == NULL) {
4648203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
4649203945Sweongyo		return (ENODEV);
4650203945Sweongyo	}
4651203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
4652203945Sweongyo		return (0);
4653203945Sweongyo
4654299793Sadrian	DPRINTF(sc, BWN_DEBUG_RF | BWN_DEBUG_PHY | BWN_DEBUG_RESET,
4655299793Sadrian	    "switching to %s-GHz band\n",
4656203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
4657203945Sweongyo
4658216227Skevlo	down_dev = sc->sc_curmac;
4659203945Sweongyo	status = down_dev->mac_status;
4660203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
4661203945Sweongyo		bwn_core_stop(down_dev);
4662203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
4663203945Sweongyo		bwn_core_exit(down_dev);
4664203945Sweongyo
4665203945Sweongyo	if (down_dev != up_dev)
4666203945Sweongyo		bwn_phy_reset(down_dev);
4667203945Sweongyo
4668203945Sweongyo	up_dev->mac_phy.gmode = gmode;
4669203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
4670203945Sweongyo		err = bwn_core_init(up_dev);
4671203945Sweongyo		if (err) {
4672203945Sweongyo			device_printf(sc->sc_dev,
4673203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
4674203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
4675203945Sweongyo			goto fail;
4676203945Sweongyo		}
4677203945Sweongyo	}
4678203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
4679203945Sweongyo		bwn_core_start(up_dev);
4680203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
4681203945Sweongyo	sc->sc_curmac = up_dev;
4682203945Sweongyo
4683203945Sweongyo	return (0);
4684203945Sweongyofail:
4685203945Sweongyo	sc->sc_curmac = NULL;
4686203945Sweongyo	return (err);
4687203945Sweongyo}
4688203945Sweongyo
4689203945Sweongyostatic void
4690203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
4691203945Sweongyo{
4692203945Sweongyo
4693299793Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
4694299793Sadrian
4695203945Sweongyo	bwn_mac_suspend(mac);
4696203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4697203945Sweongyo	mac->mac_phy.rf_on = 1;
4698203945Sweongyo	bwn_mac_enable(mac);
4699203945Sweongyo}
4700203945Sweongyo
4701203945Sweongyostatic void
4702203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
4703203945Sweongyo{
4704203945Sweongyo
4705299793Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__);
4706299793Sadrian
4707203945Sweongyo	bwn_mac_suspend(mac);
4708203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4709203945Sweongyo	mac->mac_phy.rf_on = 0;
4710203945Sweongyo	bwn_mac_enable(mac);
4711203945Sweongyo}
4712203945Sweongyo
4713299776Sadrian/*
4714299776Sadrian * SSB PHY reset.
4715299776Sadrian *
4716299776Sadrian * XXX TODO: BCMA PHY reset.
4717299776Sadrian */
4718203945Sweongyostatic void
4719203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
4720203945Sweongyo{
4721204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4722203945Sweongyo
4723204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
4724204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
4725203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
4726203945Sweongyo	DELAY(1000);
4727204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
4728299776Sadrian	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC));
4729203945Sweongyo	DELAY(1000);
4730203945Sweongyo}
4731203945Sweongyo
4732203945Sweongyostatic int
4733203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
4734203945Sweongyo{
4735203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
4736203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
4737203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
4738286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
4739203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
4740203945Sweongyo	int error;
4741203945Sweongyo
4742203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
4743203945Sweongyo	    ieee80211_state_name[vap->iv_state],
4744203945Sweongyo	    ieee80211_state_name[nstate]);
4745203945Sweongyo
4746203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
4747203945Sweongyo	if (error != 0)
4748203945Sweongyo		return (error);
4749203945Sweongyo
4750203945Sweongyo	BWN_LOCK(sc);
4751203945Sweongyo
4752203945Sweongyo	bwn_led_newstate(mac, nstate);
4753203945Sweongyo
4754203945Sweongyo	/*
4755203945Sweongyo	 * Clear the BSSID when we stop a STA
4756203945Sweongyo	 */
4757203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
4758203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
4759203945Sweongyo			/*
4760203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
4761203945Sweongyo			 * the same AP, this will reinialize things
4762203945Sweongyo			 * correctly...
4763203945Sweongyo			 */
4764203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
4765203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
4766203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
4767203945Sweongyo				bwn_set_macaddr(mac);
4768203945Sweongyo			}
4769203945Sweongyo		}
4770203945Sweongyo	}
4771203945Sweongyo
4772204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
4773204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
4774203945Sweongyo		/* XXX nothing to do? */
4775203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
4776203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
4777203945Sweongyo		bwn_set_opmode(mac);
4778203945Sweongyo		bwn_set_pretbtt(mac);
4779203945Sweongyo		bwn_spu_setdelay(mac, 0);
4780203945Sweongyo		bwn_set_macaddr(mac);
4781203945Sweongyo	}
4782203945Sweongyo
4783203945Sweongyo	BWN_UNLOCK(sc);
4784203945Sweongyo
4785203945Sweongyo	return (error);
4786203945Sweongyo}
4787203945Sweongyo
4788203945Sweongyostatic void
4789203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
4790203945Sweongyo{
4791203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4792287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4793203945Sweongyo	uint16_t pretbtt;
4794203945Sweongyo
4795203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
4796203945Sweongyo		pretbtt = 2;
4797203945Sweongyo	else
4798203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
4799203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
4800203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
4801203945Sweongyo}
4802203945Sweongyo
4803203945Sweongyostatic int
4804203945Sweongyobwn_intr(void *arg)
4805203945Sweongyo{
4806203945Sweongyo	struct bwn_mac *mac = arg;
4807203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4808203945Sweongyo	uint32_t reason;
4809203945Sweongyo
4810204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
4811204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
4812203945Sweongyo		return (FILTER_STRAY);
4813203945Sweongyo
4814300189Sadrian	DPRINTF(sc, BWN_DEBUG_INTR, "%s: called\n", __func__);
4815300189Sadrian
4816203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
4817203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
4818203945Sweongyo		return (FILTER_STRAY);
4819203945Sweongyo	reason &= mac->mac_intr_mask;
4820203945Sweongyo	if (reason == 0)
4821203945Sweongyo		return (FILTER_HANDLED);
4822300189Sadrian	DPRINTF(sc, BWN_DEBUG_INTR, "%s: reason=0x%08x\n", __func__, reason);
4823203945Sweongyo
4824203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
4825203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
4826203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
4827203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
4828203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
4829203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
4830203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
4831203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
4832203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
4833203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
4834203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
4835203945Sweongyo
4836203945Sweongyo	/* Disable interrupts. */
4837203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
4838203945Sweongyo
4839203945Sweongyo	mac->mac_reason_intr = reason;
4840203945Sweongyo
4841203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
4842203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
4843203945Sweongyo
4844296272Sjhb	taskqueue_enqueue(sc->sc_tq, &mac->mac_intrtask);
4845203945Sweongyo	return (FILTER_HANDLED);
4846203945Sweongyo}
4847203945Sweongyo
4848203945Sweongyostatic void
4849203945Sweongyobwn_intrtask(void *arg, int npending)
4850203945Sweongyo{
4851203945Sweongyo	struct bwn_mac *mac = arg;
4852203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4853203945Sweongyo	uint32_t merged = 0;
4854203945Sweongyo	int i, tx = 0, rx = 0;
4855203945Sweongyo
4856203945Sweongyo	BWN_LOCK(sc);
4857204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
4858204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
4859203945Sweongyo		BWN_UNLOCK(sc);
4860203945Sweongyo		return;
4861203945Sweongyo	}
4862203945Sweongyo
4863203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
4864203945Sweongyo		merged |= mac->mac_reason[i];
4865203945Sweongyo
4866203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
4867203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
4868203945Sweongyo
4869203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
4870203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
4871203945Sweongyo		mac->mac_phy.txerrors--;
4872203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
4873203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
4874203945Sweongyo			bwn_restart(mac, "PHY TX errors");
4875203945Sweongyo		}
4876203945Sweongyo	}
4877203945Sweongyo
4878203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
4879203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
4880203945Sweongyo			device_printf(sc->sc_dev,
4881203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
4882203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
4883203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
4884203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
4885203945Sweongyo			bwn_restart(mac, "DMA error");
4886203945Sweongyo			BWN_UNLOCK(sc);
4887203945Sweongyo			return;
4888203945Sweongyo		}
4889203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
4890203945Sweongyo			device_printf(sc->sc_dev,
4891203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
4892203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
4893203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
4894203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
4895203945Sweongyo		}
4896203945Sweongyo	}
4897203945Sweongyo
4898203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
4899203945Sweongyo		bwn_intr_ucode_debug(mac);
4900203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
4901203945Sweongyo		bwn_intr_tbtt_indication(mac);
4902203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
4903203945Sweongyo		bwn_intr_atim_end(mac);
4904203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
4905203945Sweongyo		bwn_intr_beacon(mac);
4906203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
4907203945Sweongyo		bwn_intr_pmq(mac);
4908203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
4909203945Sweongyo		bwn_intr_noise(mac);
4910203945Sweongyo
4911203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
4912203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
4913203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
4914203945Sweongyo			rx = 1;
4915203945Sweongyo		}
4916203945Sweongyo	} else
4917203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
4918203945Sweongyo
4919203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4920203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4921203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4922203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4923203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
4924203945Sweongyo
4925203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
4926203945Sweongyo		bwn_intr_txeof(mac);
4927203945Sweongyo		tx = 1;
4928203945Sweongyo	}
4929203945Sweongyo
4930203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
4931203945Sweongyo
4932203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
4933203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
4934203945Sweongyo
4935203945Sweongyo		if (tx && rx) {
4936203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
4937203945Sweongyo				evt = BWN_LED_EVENT_RX;
4938203945Sweongyo			else
4939203945Sweongyo				evt = BWN_LED_EVENT_TX;
4940203945Sweongyo		} else if (tx) {
4941203945Sweongyo			evt = BWN_LED_EVENT_TX;
4942203945Sweongyo		} else if (rx) {
4943203945Sweongyo			evt = BWN_LED_EVENT_RX;
4944203945Sweongyo		} else if (rx == 0) {
4945203945Sweongyo			evt = BWN_LED_EVENT_POLL;
4946203945Sweongyo		}
4947203945Sweongyo
4948203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
4949203945Sweongyo			bwn_led_event(mac, evt);
4950203945Sweongyo       }
4951203945Sweongyo
4952287197Sglebius	if (mbufq_first(&sc->sc_snd) != NULL)
4953287197Sglebius		bwn_start(sc);
4954203945Sweongyo
4955203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
4956203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
4957203945Sweongyo
4958203945Sweongyo	BWN_UNLOCK(sc);
4959203945Sweongyo}
4960203945Sweongyo
4961203945Sweongyostatic void
4962203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
4963203945Sweongyo{
4964203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4965287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4966203945Sweongyo
4967203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
4968203945Sweongyo		return;
4969203945Sweongyo
4970203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
4971203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
4972203945Sweongyo}
4973203945Sweongyo
4974203945Sweongyostatic void
4975203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
4976203945Sweongyo{
4977203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4978203945Sweongyo	uint16_t reason;
4979203945Sweongyo
4980203945Sweongyo	if (mac->mac_fw.opensource == 0)
4981203945Sweongyo		return;
4982203945Sweongyo
4983203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
4984203945Sweongyo	switch (reason) {
4985203945Sweongyo	case BWN_DEBUGINTR_PANIC:
4986203945Sweongyo		bwn_handle_fwpanic(mac);
4987203945Sweongyo		break;
4988203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
4989203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
4990203945Sweongyo		break;
4991203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
4992203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
4993203945Sweongyo		break;
4994203945Sweongyo	case BWN_DEBUGINTR_MARKER:
4995203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
4996203945Sweongyo		break;
4997203945Sweongyo	default:
4998203945Sweongyo		device_printf(sc->sc_dev,
4999203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
5000203945Sweongyo	}
5001203945Sweongyo
5002203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
5003203945Sweongyo	    BWN_DEBUGINTR_ACK);
5004203945Sweongyo}
5005203945Sweongyo
5006203945Sweongyostatic void
5007203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
5008203945Sweongyo{
5009203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5010287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5011203945Sweongyo
5012203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
5013203945Sweongyo		bwn_psctl(mac, 0);
5014203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
5015203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
5016203945Sweongyo}
5017203945Sweongyo
5018203945Sweongyostatic void
5019203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
5020203945Sweongyo{
5021203945Sweongyo
5022203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
5023203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
5024203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
5025203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
5026203945Sweongyo	}
5027203945Sweongyo}
5028203945Sweongyo
5029203945Sweongyostatic void
5030203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
5031203945Sweongyo{
5032203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5033287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5034203945Sweongyo	uint32_t cmd, beacon0, beacon1;
5035203945Sweongyo
5036203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5037203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
5038203945Sweongyo		return;
5039203945Sweongyo
5040203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
5041203945Sweongyo
5042203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
5043203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
5044203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
5045203945Sweongyo
5046203945Sweongyo	if (beacon0 && beacon1) {
5047203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
5048203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
5049203945Sweongyo		return;
5050203945Sweongyo	}
5051203945Sweongyo
5052203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
5053203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
5054203945Sweongyo		bwn_load_beacon0(mac);
5055203945Sweongyo		bwn_load_beacon1(mac);
5056203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
5057203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
5058203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
5059203945Sweongyo	} else {
5060203945Sweongyo		if (!beacon0) {
5061203945Sweongyo			bwn_load_beacon0(mac);
5062203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
5063203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
5064203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
5065203945Sweongyo		} else if (!beacon1) {
5066203945Sweongyo			bwn_load_beacon1(mac);
5067203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
5068203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
5069203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
5070203945Sweongyo		}
5071203945Sweongyo	}
5072203945Sweongyo}
5073203945Sweongyo
5074203945Sweongyostatic void
5075203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
5076203945Sweongyo{
5077203945Sweongyo	uint32_t tmp;
5078203945Sweongyo
5079203945Sweongyo	while (1) {
5080203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
5081203945Sweongyo		if (!(tmp & 0x00000008))
5082203945Sweongyo			break;
5083203945Sweongyo	}
5084203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
5085203945Sweongyo}
5086203945Sweongyo
5087203945Sweongyostatic void
5088203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
5089203945Sweongyo{
5090203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5091203945Sweongyo	uint16_t tmp;
5092203945Sweongyo	uint8_t noise[4];
5093203945Sweongyo	uint8_t i, j;
5094203945Sweongyo	int32_t average;
5095203945Sweongyo
5096203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
5097203945Sweongyo		return;
5098203945Sweongyo
5099203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
5100203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
5101203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
5102203945Sweongyo	    noise[3] == 0x7f)
5103203945Sweongyo		goto new;
5104203945Sweongyo
5105203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
5106203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5107203945Sweongyo	i = mac->mac_noise.noi_nsamples;
5108203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
5109203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
5110203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
5111203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
5112203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
5113203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
5114203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
5115203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
5116203945Sweongyo	mac->mac_noise.noi_nsamples++;
5117203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
5118203945Sweongyo		average = 0;
5119203945Sweongyo		for (i = 0; i < 8; i++) {
5120203945Sweongyo			for (j = 0; j < 4; j++)
5121203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
5122203945Sweongyo		}
5123203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
5124203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
5125203945Sweongyo		if (tmp >= 8)
5126203945Sweongyo			average += 2;
5127203945Sweongyo		else
5128203945Sweongyo			average -= 25;
5129203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
5130203945Sweongyo
5131203945Sweongyo		mac->mac_stats.link_noise = average;
5132203945Sweongyo		mac->mac_noise.noi_running = 0;
5133203945Sweongyo		return;
5134203945Sweongyo	}
5135203945Sweongyonew:
5136203945Sweongyo	bwn_noise_gensample(mac);
5137203945Sweongyo}
5138203945Sweongyo
5139203945Sweongyostatic int
5140203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
5141203945Sweongyo{
5142203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
5143203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5144203945Sweongyo	unsigned int i;
5145203945Sweongyo
5146203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5147203945Sweongyo
5148203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
5149203945Sweongyo		return (0);
5150203945Sweongyo
5151203945Sweongyo	for (i = 0; i < 5000; i++) {
5152203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
5153203945Sweongyo			break;
5154203945Sweongyo	}
5155203945Sweongyo	if (i >= 5000)
5156203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
5157203945Sweongyo	return ((i > 0) ? 1 : 0);
5158203945Sweongyo}
5159203945Sweongyo
5160203945Sweongyostatic void
5161203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
5162203945Sweongyo{
5163203945Sweongyo	int slot, curslot;
5164203945Sweongyo
5165203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
5166203945Sweongyo	curslot = dr->get_curslot(dr);
5167203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
5168203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5169203945Sweongyo
5170203945Sweongyo	slot = dr->dr_curslot;
5171203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
5172203945Sweongyo		bwn_dma_rxeof(dr, &slot);
5173203945Sweongyo
5174203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
5175203945Sweongyo	    BUS_DMASYNC_PREWRITE);
5176203945Sweongyo
5177203945Sweongyo	dr->set_curslot(dr, slot);
5178203945Sweongyo	dr->dr_curslot = slot;
5179203945Sweongyo}
5180203945Sweongyo
5181203945Sweongyostatic void
5182203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
5183203945Sweongyo{
5184203945Sweongyo	struct bwn_txstatus stat;
5185203945Sweongyo	uint32_t stat0, stat1;
5186203945Sweongyo	uint16_t tmp;
5187203945Sweongyo
5188203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
5189203945Sweongyo
5190203945Sweongyo	while (1) {
5191203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
5192203945Sweongyo		if (!(stat0 & 0x00000001))
5193203945Sweongyo			break;
5194203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
5195203945Sweongyo
5196299036Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_XMIT,
5197299036Sadrian		    "%s: stat0=0x%08x, stat1=0x%08x\n",
5198299036Sadrian		    __func__,
5199299036Sadrian		    stat0,
5200299036Sadrian		    stat1);
5201299036Sadrian
5202203945Sweongyo		stat.cookie = (stat0 >> 16);
5203203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
5204203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
5205203945Sweongyo		tmp = (stat0 & 0x0000ffff);
5206203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
5207203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
5208203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
5209203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
5210203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
5211203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
5212203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
5213203945Sweongyo
5214299782Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_XMIT,
5215299782Sadrian		    "%s: cookie=%d, seq=%d, phystat=0x%02x, framecnt=%d, "
5216299782Sadrian		    "rtscnt=%d, sreason=%d, pm=%d, im=%d, ampdu=%d, ack=%d\n",
5217299782Sadrian		    __func__,
5218299782Sadrian		    stat.cookie,
5219299782Sadrian		    stat.seq,
5220299782Sadrian		    stat.phy_stat,
5221299782Sadrian		    stat.framecnt,
5222299782Sadrian		    stat.rtscnt,
5223299782Sadrian		    stat.sreason,
5224299782Sadrian		    stat.pm,
5225299782Sadrian		    stat.im,
5226299782Sadrian		    stat.ampdu,
5227299782Sadrian		    stat.ack);
5228299782Sadrian
5229203945Sweongyo		bwn_handle_txeof(mac, &stat);
5230203945Sweongyo	}
5231203945Sweongyo}
5232203945Sweongyo
5233203945Sweongyostatic void
5234203945Sweongyobwn_hwreset(void *arg, int npending)
5235203945Sweongyo{
5236203945Sweongyo	struct bwn_mac *mac = arg;
5237203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5238203945Sweongyo	int error = 0;
5239203945Sweongyo	int prev_status;
5240203945Sweongyo
5241203945Sweongyo	BWN_LOCK(sc);
5242203945Sweongyo
5243203945Sweongyo	prev_status = mac->mac_status;
5244203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
5245203945Sweongyo		bwn_core_stop(mac);
5246203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
5247203945Sweongyo		bwn_core_exit(mac);
5248203945Sweongyo
5249203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
5250203945Sweongyo		error = bwn_core_init(mac);
5251203945Sweongyo		if (error)
5252203945Sweongyo			goto out;
5253203945Sweongyo	}
5254203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
5255203945Sweongyo		bwn_core_start(mac);
5256203945Sweongyoout:
5257203945Sweongyo	if (error) {
5258203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
5259203945Sweongyo		sc->sc_curmac = NULL;
5260203945Sweongyo	}
5261203945Sweongyo	BWN_UNLOCK(sc);
5262203945Sweongyo}
5263203945Sweongyo
5264203945Sweongyostatic void
5265203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
5266203945Sweongyo{
5267203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5268203945Sweongyo	uint16_t reason;
5269203945Sweongyo
5270203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
5271203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
5272203945Sweongyo
5273203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
5274203945Sweongyo		bwn_restart(mac, "ucode panic");
5275203945Sweongyo}
5276203945Sweongyo
5277203945Sweongyostatic void
5278203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
5279203945Sweongyo{
5280203945Sweongyo
5281203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5282203945Sweongyo}
5283203945Sweongyo
5284203945Sweongyostatic void
5285203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
5286203945Sweongyo{
5287203945Sweongyo
5288203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5289203945Sweongyo}
5290203945Sweongyo
5291203945Sweongyostatic uint32_t
5292203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
5293203945Sweongyo{
5294203945Sweongyo	uint32_t val = 0;
5295203945Sweongyo
5296203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
5297203945Sweongyo	val <<= 16;
5298203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
5299203945Sweongyo
5300203945Sweongyo	return (val);
5301203945Sweongyo}
5302203945Sweongyo
5303203945Sweongyostatic void
5304203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
5305203945Sweongyo{
5306203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
5307203945Sweongyo
5308203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
5309203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
5310203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
5311203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
5312203945Sweongyo}
5313203945Sweongyo
5314203945Sweongyostatic int
5315203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
5316203945Sweongyo{
5317204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
5318203945Sweongyo
5319203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
5320203945Sweongyo}
5321203945Sweongyo
5322203945Sweongyostatic int
5323203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
5324203945Sweongyo{
5325204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
5326203945Sweongyo
5327203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
5328203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5329203945Sweongyo	if (slot == dr->dr_numslots - 1)
5330203945Sweongyo		return (0);
5331203945Sweongyo	return (slot + 1);
5332203945Sweongyo}
5333203945Sweongyo
5334203945Sweongyostatic void
5335203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
5336203945Sweongyo{
5337203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
5338203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5339203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5340203945Sweongyo	struct bwn_dmadesc_generic *desc;
5341203945Sweongyo	struct bwn_dmadesc_meta *meta;
5342203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
5343203945Sweongyo	struct mbuf *m;
5344203945Sweongyo	uint32_t macstat;
5345203945Sweongyo	int32_t tmp;
5346203945Sweongyo	int cnt = 0;
5347203945Sweongyo	uint16_t len;
5348203945Sweongyo
5349203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
5350203945Sweongyo
5351203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
5352203945Sweongyo	m = meta->mt_m;
5353203945Sweongyo
5354203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
5355287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
5356203945Sweongyo		return;
5357203945Sweongyo	}
5358203945Sweongyo
5359203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
5360203945Sweongyo	len = le16toh(rxhdr->frame_len);
5361203945Sweongyo	if (len <= 0) {
5362287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
5363203945Sweongyo		return;
5364203945Sweongyo	}
5365203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
5366203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
5367203945Sweongyo		bwn_dma_set_redzone(dr, m);
5368203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5369203945Sweongyo		    BUS_DMASYNC_PREWRITE);
5370203945Sweongyo		return;
5371203945Sweongyo	}
5372203945Sweongyo	if (len > dr->dr_rx_bufsize) {
5373203945Sweongyo		tmp = len;
5374203945Sweongyo		while (1) {
5375203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
5376203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
5377203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5378203945Sweongyo			    BUS_DMASYNC_PREWRITE);
5379203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
5380203945Sweongyo			cnt++;
5381203945Sweongyo			tmp -= dr->dr_rx_bufsize;
5382203945Sweongyo			if (tmp <= 0)
5383203945Sweongyo				break;
5384203945Sweongyo		}
5385203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
5386203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
5387203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
5388203945Sweongyo		return;
5389203945Sweongyo	}
5390300114Sadrian
5391300114Sadrian	switch (mac->mac_fw.fw_hdr_format) {
5392300114Sadrian	case BWN_FW_HDR_351:
5393300114Sadrian	case BWN_FW_HDR_410:
5394300114Sadrian		macstat = le32toh(rxhdr->ps4.r351.mac_status);
5395300114Sadrian		break;
5396300114Sadrian	case BWN_FW_HDR_598:
5397300114Sadrian		macstat = le32toh(rxhdr->ps4.r598.mac_status);
5398300114Sadrian		break;
5399300114Sadrian	}
5400300114Sadrian
5401203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
5402203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
5403203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
5404203945Sweongyo			return;
5405203945Sweongyo		}
5406203945Sweongyo	}
5407203945Sweongyo
5408203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
5409203945Sweongyo	m_adj(m, dr->dr_frameoffset);
5410203945Sweongyo
5411203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
5412203945Sweongyo}
5413203945Sweongyo
5414203945Sweongyostatic void
5415203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
5416203945Sweongyo{
5417203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5418204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
5419203945Sweongyo
5420203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
5421203945Sweongyo
5422203945Sweongyo	if (status->im)
5423203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
5424203945Sweongyo	if (status->ampdu)
5425203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
5426203945Sweongyo	if (status->rtscnt) {
5427203945Sweongyo		if (status->rtscnt == 0xf)
5428204257Sweongyo			stats->rtsfail++;
5429203945Sweongyo		else
5430204257Sweongyo			stats->rts++;
5431203945Sweongyo	}
5432203945Sweongyo
5433203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
5434203945Sweongyo		bwn_dma_handle_txeof(mac, status);
5435203945Sweongyo	} else {
5436203945Sweongyo		bwn_pio_handle_txeof(mac, status);
5437203945Sweongyo	}
5438203945Sweongyo
5439203945Sweongyo	bwn_phy_txpower_check(mac, 0);
5440203945Sweongyo}
5441203945Sweongyo
5442203945Sweongyostatic uint8_t
5443203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
5444203945Sweongyo{
5445203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
5446203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5447203945Sweongyo	struct bwn_rxhdr4 rxhdr;
5448203945Sweongyo	struct mbuf *m;
5449203945Sweongyo	uint32_t ctl32, macstat, v32;
5450203945Sweongyo	unsigned int i, padding;
5451209888Sweongyo	uint16_t ctl16, len, totlen, v16;
5452203945Sweongyo	unsigned char *mp;
5453203945Sweongyo	char *data;
5454203945Sweongyo
5455203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
5456203945Sweongyo
5457203945Sweongyo	if (prq->prq_rev >= 8) {
5458203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
5459203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
5460203945Sweongyo			return (0);
5461203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
5462203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
5463203945Sweongyo		for (i = 0; i < 10; i++) {
5464203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
5465203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
5466203945Sweongyo				goto ready;
5467203945Sweongyo			DELAY(10);
5468203945Sweongyo		}
5469203945Sweongyo	} else {
5470203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
5471203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
5472203945Sweongyo			return (0);
5473203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
5474203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
5475203945Sweongyo		for (i = 0; i < 10; i++) {
5476203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
5477203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
5478203945Sweongyo				goto ready;
5479203945Sweongyo			DELAY(10);
5480203945Sweongyo		}
5481203945Sweongyo	}
5482203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
5483203945Sweongyo	return (1);
5484203945Sweongyoready:
5485203945Sweongyo	if (prq->prq_rev >= 8)
5486204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
5487203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
5488203945Sweongyo	else
5489204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
5490203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
5491203945Sweongyo	len = le16toh(rxhdr.frame_len);
5492203945Sweongyo	if (len > 0x700) {
5493203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
5494203945Sweongyo		goto error;
5495203945Sweongyo	}
5496203945Sweongyo	if (len == 0) {
5497203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
5498203945Sweongyo		goto error;
5499203945Sweongyo	}
5500203945Sweongyo
5501300114Sadrian	switch (mac->mac_fw.fw_hdr_format) {
5502300114Sadrian	case BWN_FW_HDR_351:
5503300114Sadrian	case BWN_FW_HDR_410:
5504300114Sadrian		macstat = le32toh(rxhdr.ps4.r351.mac_status);
5505300114Sadrian		break;
5506300114Sadrian	case BWN_FW_HDR_598:
5507300114Sadrian		macstat = le32toh(rxhdr.ps4.r598.mac_status);
5508300114Sadrian		break;
5509300114Sadrian	}
5510300114Sadrian
5511203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
5512203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
5513203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
5514203945Sweongyo			goto error;
5515203945Sweongyo		}
5516203945Sweongyo	}
5517203945Sweongyo
5518203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
5519209888Sweongyo	totlen = len + padding;
5520209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
5521243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5522203945Sweongyo	if (m == NULL) {
5523203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
5524203945Sweongyo		goto error;
5525203945Sweongyo	}
5526203945Sweongyo	mp = mtod(m, unsigned char *);
5527203945Sweongyo	if (prq->prq_rev >= 8) {
5528209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
5529203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
5530209888Sweongyo		if (totlen & 3) {
5531203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
5532209888Sweongyo			data = &(mp[totlen - 1]);
5533209888Sweongyo			switch (totlen & 3) {
5534203945Sweongyo			case 3:
5535203945Sweongyo				*data = (v32 >> 16);
5536203945Sweongyo				data--;
5537203945Sweongyo			case 2:
5538203945Sweongyo				*data = (v32 >> 8);
5539203945Sweongyo				data--;
5540203945Sweongyo			case 1:
5541203945Sweongyo				*data = v32;
5542203945Sweongyo			}
5543203945Sweongyo		}
5544203945Sweongyo	} else {
5545209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
5546203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
5547209888Sweongyo		if (totlen & 1) {
5548203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
5549209888Sweongyo			mp[totlen - 1] = v16;
5550203945Sweongyo		}
5551203945Sweongyo	}
5552203945Sweongyo
5553209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
5554203945Sweongyo
5555203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
5556203945Sweongyo
5557203945Sweongyo	return (1);
5558203945Sweongyoerror:
5559203945Sweongyo	if (prq->prq_rev >= 8)
5560203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
5561203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
5562203945Sweongyo	else
5563203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
5564203945Sweongyo	return (1);
5565203945Sweongyo}
5566203945Sweongyo
5567203945Sweongyostatic int
5568203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
5569203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
5570203945Sweongyo{
5571203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
5572203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5573203945Sweongyo	struct bwn_rxhdr4 *hdr;
5574203945Sweongyo	bus_dmamap_t map;
5575203945Sweongyo	bus_addr_t paddr;
5576203945Sweongyo	struct mbuf *m;
5577203945Sweongyo	int error;
5578203945Sweongyo
5579243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
5580203945Sweongyo	if (m == NULL) {
5581203945Sweongyo		error = ENOBUFS;
5582203945Sweongyo
5583203945Sweongyo		/*
5584203945Sweongyo		 * If the NIC is up and running, we need to:
5585203945Sweongyo		 * - Clear RX buffer's header.
5586203945Sweongyo		 * - Restore RX descriptor settings.
5587203945Sweongyo		 */
5588203945Sweongyo		if (init)
5589203945Sweongyo			return (error);
5590203945Sweongyo		else
5591203945Sweongyo			goto back;
5592203945Sweongyo	}
5593203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
5594203945Sweongyo
5595203945Sweongyo	bwn_dma_set_redzone(dr, m);
5596203945Sweongyo
5597203945Sweongyo	/*
5598203945Sweongyo	 * Try to load RX buf into temporary DMA map
5599203945Sweongyo	 */
5600203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
5601203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
5602203945Sweongyo	if (error) {
5603203945Sweongyo		m_freem(m);
5604203945Sweongyo
5605203945Sweongyo		/*
5606203945Sweongyo		 * See the comment above
5607203945Sweongyo		 */
5608203945Sweongyo		if (init)
5609203945Sweongyo			return (error);
5610203945Sweongyo		else
5611203945Sweongyo			goto back;
5612203945Sweongyo	}
5613203945Sweongyo
5614203945Sweongyo	if (!init)
5615203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
5616203945Sweongyo	meta->mt_m = m;
5617203945Sweongyo	meta->mt_paddr = paddr;
5618203945Sweongyo
5619203945Sweongyo	/*
5620203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
5621203945Sweongyo	 */
5622203945Sweongyo	map = meta->mt_dmap;
5623203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
5624203945Sweongyo	dr->dr_spare_dmap = map;
5625203945Sweongyo
5626203945Sweongyoback:
5627203945Sweongyo	/*
5628203945Sweongyo	 * Clear RX buf header
5629203945Sweongyo	 */
5630203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
5631203945Sweongyo	bzero(hdr, sizeof(*hdr));
5632203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
5633203945Sweongyo	    BUS_DMASYNC_PREWRITE);
5634203945Sweongyo
5635203945Sweongyo	/*
5636203945Sweongyo	 * Setup RX buf descriptor
5637203945Sweongyo	 */
5638250314Shiren	dr->setdesc(dr, desc, meta->mt_paddr, meta->mt_m->m_len -
5639203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
5640203945Sweongyo	return (error);
5641203945Sweongyo}
5642203945Sweongyo
5643203945Sweongyostatic void
5644203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
5645203945Sweongyo		 bus_size_t mapsz __unused, int error)
5646203945Sweongyo{
5647203945Sweongyo
5648203945Sweongyo	if (!error) {
5649203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
5650203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
5651203945Sweongyo	}
5652203945Sweongyo}
5653203945Sweongyo
5654203945Sweongyostatic int
5655203945Sweongyobwn_hwrate2ieeerate(int rate)
5656203945Sweongyo{
5657203945Sweongyo
5658203945Sweongyo	switch (rate) {
5659203945Sweongyo	case BWN_CCK_RATE_1MB:
5660203945Sweongyo		return (2);
5661203945Sweongyo	case BWN_CCK_RATE_2MB:
5662203945Sweongyo		return (4);
5663203945Sweongyo	case BWN_CCK_RATE_5MB:
5664203945Sweongyo		return (11);
5665203945Sweongyo	case BWN_CCK_RATE_11MB:
5666203945Sweongyo		return (22);
5667203945Sweongyo	case BWN_OFDM_RATE_6MB:
5668203945Sweongyo		return (12);
5669203945Sweongyo	case BWN_OFDM_RATE_9MB:
5670203945Sweongyo		return (18);
5671203945Sweongyo	case BWN_OFDM_RATE_12MB:
5672203945Sweongyo		return (24);
5673203945Sweongyo	case BWN_OFDM_RATE_18MB:
5674203945Sweongyo		return (36);
5675203945Sweongyo	case BWN_OFDM_RATE_24MB:
5676203945Sweongyo		return (48);
5677203945Sweongyo	case BWN_OFDM_RATE_36MB:
5678203945Sweongyo		return (72);
5679203945Sweongyo	case BWN_OFDM_RATE_48MB:
5680203945Sweongyo		return (96);
5681203945Sweongyo	case BWN_OFDM_RATE_54MB:
5682203945Sweongyo		return (108);
5683203945Sweongyo	default:
5684203945Sweongyo		printf("Ooops\n");
5685203945Sweongyo		return (0);
5686203945Sweongyo	}
5687203945Sweongyo}
5688203945Sweongyo
5689299110Sadrian/*
5690299110Sadrian * Post process the RX provided RSSI.
5691299110Sadrian *
5692299110Sadrian * Valid for A, B, G, LP PHYs.
5693299110Sadrian */
5694299110Sadrianstatic int8_t
5695299131Sadrianbwn_rx_rssi_calc(struct bwn_mac *mac, uint8_t in_rssi,
5696299110Sadrian    int ofdm, int adjust_2053, int adjust_2050)
5697299110Sadrian{
5698299110Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5699299110Sadrian	struct bwn_phy_g *gphy = &phy->phy_g;
5700299110Sadrian	int tmp;
5701299110Sadrian
5702299110Sadrian	switch (phy->rf_ver) {
5703299110Sadrian	case 0x2050:
5704299110Sadrian		if (ofdm) {
5705299110Sadrian			tmp = in_rssi;
5706299110Sadrian			if (tmp > 127)
5707299110Sadrian				tmp -= 256;
5708299110Sadrian			tmp = tmp * 73 / 64;
5709299110Sadrian			if (adjust_2050)
5710299110Sadrian				tmp += 25;
5711299110Sadrian			else
5712299110Sadrian				tmp -= 3;
5713299110Sadrian		} else {
5714299110Sadrian			if (siba_sprom_get_bf_lo(mac->mac_sc->sc_dev)
5715299110Sadrian			    & BWN_BFL_RSSI) {
5716299110Sadrian				if (in_rssi > 63)
5717299110Sadrian					in_rssi = 63;
5718299110Sadrian				tmp = gphy->pg_nrssi_lt[in_rssi];
5719299110Sadrian				tmp = (31 - tmp) * -131 / 128 - 57;
5720299110Sadrian			} else {
5721299110Sadrian				tmp = in_rssi;
5722299110Sadrian				tmp = (31 - tmp) * -149 / 128 - 68;
5723299110Sadrian			}
5724299110Sadrian			if (phy->type == BWN_PHYTYPE_G && adjust_2050)
5725299110Sadrian				tmp += 25;
5726299110Sadrian		}
5727299110Sadrian		break;
5728299110Sadrian	case 0x2060:
5729299110Sadrian		if (in_rssi > 127)
5730299110Sadrian			tmp = in_rssi - 256;
5731299110Sadrian		else
5732299110Sadrian			tmp = in_rssi;
5733299110Sadrian		break;
5734299110Sadrian	default:
5735299110Sadrian		tmp = in_rssi;
5736299110Sadrian		tmp = (tmp - 11) * 103 / 64;
5737299110Sadrian		if (adjust_2053)
5738299110Sadrian			tmp -= 109;
5739299110Sadrian		else
5740299110Sadrian			tmp -= 83;
5741299110Sadrian	}
5742299110Sadrian
5743299110Sadrian	return (tmp);
5744299110Sadrian}
5745299110Sadrian
5746203945Sweongyostatic void
5747203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
5748203945Sweongyo{
5749203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
5750203945Sweongyo	struct bwn_plcp6 *plcp;
5751203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5752203945Sweongyo	struct ieee80211_frame_min *wh;
5753203945Sweongyo	struct ieee80211_node *ni;
5754287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5755203945Sweongyo	uint32_t macstat;
5756204242Simp	int padding, rate, rssi = 0, noise = 0, type;
5757203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
5758203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
5759204242Simp	static int rx_mac_dec_rpt = 0;
5760203945Sweongyo
5761203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5762203945Sweongyo
5763203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
5764299110Sadrian
5765300114Sadrian	/*
5766300114Sadrian	 * XXX Note: phy_status3 doesn't exist for HT-PHY; it's only
5767300114Sadrian	 * used for LP-PHY.
5768300114Sadrian	 */
5769300114Sadrian	phystat3 = le16toh(rxhdr->ps3.lp.phy_status3);
5770299110Sadrian
5771300114Sadrian	switch (mac->mac_fw.fw_hdr_format) {
5772300114Sadrian	case BWN_FW_HDR_351:
5773300114Sadrian	case BWN_FW_HDR_410:
5774300114Sadrian		macstat = le32toh(rxhdr->ps4.r351.mac_status);
5775300114Sadrian		chanstat = le16toh(rxhdr->ps4.r351.channel);
5776300114Sadrian		break;
5777300114Sadrian	case BWN_FW_HDR_598:
5778300114Sadrian		macstat = le32toh(rxhdr->ps4.r598.mac_status);
5779300114Sadrian		chanstat = le16toh(rxhdr->ps4.r598.channel);
5780300114Sadrian		break;
5781300114Sadrian	}
5782300114Sadrian
5783300114Sadrian
5784203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
5785203945Sweongyo
5786203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
5787203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
5788203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
5789203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
5790203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
5791203945Sweongyo		goto drop;
5792203945Sweongyo
5793203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
5794203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
5795204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
5796204081Sweongyo		    m->m_pkthdr.len);
5797203945Sweongyo		goto drop;
5798203945Sweongyo	}
5799203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
5800203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
5801203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
5802204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
5803204081Sweongyo		    m->m_pkthdr.len);
5804203945Sweongyo		goto drop;
5805203945Sweongyo	}
5806203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
5807203945Sweongyo
5808204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
5809204081Sweongyo		device_printf(sc->sc_dev,
5810204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
5811204081Sweongyo		    BWN_ISOLDFMT(mac),
5812204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
5813203945Sweongyo
5814203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
5815203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
5816203945Sweongyo		    phytype == BWN_PHYTYPE_A);
5817203945Sweongyo	else
5818203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
5819203945Sweongyo	if (rate == -1) {
5820203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
5821203945Sweongyo			goto drop;
5822203945Sweongyo	}
5823203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
5824203945Sweongyo
5825299110Sadrian	/* rssi/noise */
5826299110Sadrian	switch (phytype) {
5827299110Sadrian	case BWN_PHYTYPE_A:
5828299110Sadrian	case BWN_PHYTYPE_B:
5829299110Sadrian	case BWN_PHYTYPE_G:
5830299110Sadrian	case BWN_PHYTYPE_LP:
5831299110Sadrian		rssi = bwn_rx_rssi_calc(mac, rxhdr->phy.abg.rssi,
5832299110Sadrian		    !! (phystat0 & BWN_RX_PHYST0_OFDM),
5833299110Sadrian		    !! (phystat0 & BWN_RX_PHYST0_GAINCTL),
5834299110Sadrian		    !! (phystat3 & BWN_RX_PHYST3_TRSTATE));
5835299110Sadrian		break;
5836299795Sadrian	case BWN_PHYTYPE_N:
5837299795Sadrian		/* Broadcom has code for min/avg, but always used max */
5838299795Sadrian		if (rxhdr->phy.n.power0 == 16 || rxhdr->phy.n.power0 == 32)
5839299795Sadrian			rssi = max(rxhdr->phy.n.power1, rxhdr->ps2.n.power2);
5840299795Sadrian		else
5841299795Sadrian			rssi = max(rxhdr->phy.n.power0, rxhdr->phy.n.power1);
5842300079Sadrian#if 0
5843300079Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_RECV,
5844300079Sadrian		    "%s: power0=%d, power1=%d, power2=%d\n",
5845300079Sadrian		    __func__,
5846300079Sadrian		    rxhdr->phy.n.power0,
5847300079Sadrian		    rxhdr->phy.n.power1,
5848300079Sadrian		    rxhdr->ps2.n.power2);
5849300079Sadrian#endif
5850299795Sadrian		break;
5851299110Sadrian	default:
5852299110Sadrian		/* XXX TODO: implement rssi for other PHYs */
5853299110Sadrian		break;
5854299110Sadrian	}
5855299110Sadrian
5856300079Sadrian	/*
5857300079Sadrian	 * RSSI here is absolute, not relative to the noise floor.
5858300079Sadrian	 */
5859299110Sadrian	noise = mac->mac_stats.link_noise;
5860300079Sadrian	rssi = rssi - noise;
5861299110Sadrian
5862203945Sweongyo	/* RX radio tap */
5863203945Sweongyo	if (ieee80211_radiotap_active(ic))
5864203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
5865203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
5866203945Sweongyo
5867203945Sweongyo	BWN_UNLOCK(sc);
5868203945Sweongyo
5869203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
5870203945Sweongyo	if (ni != NULL) {
5871203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
5872203945Sweongyo		ieee80211_free_node(ni);
5873203945Sweongyo	} else
5874203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
5875203945Sweongyo
5876203945Sweongyo	BWN_LOCK(sc);
5877203945Sweongyo	return;
5878203945Sweongyodrop:
5879203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
5880203945Sweongyo}
5881203945Sweongyo
5882203945Sweongyostatic void
5883203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
5884203945Sweongyo    const struct bwn_txstatus *status)
5885203945Sweongyo{
5886203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
5887203945Sweongyo	struct bwn_dma_ring *dr;
5888203945Sweongyo	struct bwn_dmadesc_generic *desc;
5889203945Sweongyo	struct bwn_dmadesc_meta *meta;
5890203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5891203945Sweongyo	int slot;
5892299032Sadrian	int retrycnt = 0;
5893203945Sweongyo
5894203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5895203945Sweongyo
5896203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
5897203945Sweongyo	if (dr == NULL) {
5898203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
5899203945Sweongyo		return;
5900203945Sweongyo	}
5901203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
5902203945Sweongyo
5903203945Sweongyo	while (1) {
5904203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
5905203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5906203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
5907203945Sweongyo
5908203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
5909203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
5910203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
5911203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
5912203945Sweongyo
5913203945Sweongyo		if (meta->mt_islast) {
5914203945Sweongyo			KASSERT(meta->mt_m != NULL,
5915203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
5916203945Sweongyo
5917299782Sadrian			/*
5918299782Sadrian			 * If we don't get an ACK, then we should log the
5919299782Sadrian			 * full framecnt.  That may be 0 if it's a PHY
5920299782Sadrian			 * failure, so ensure that gets logged as some
5921299782Sadrian			 * retry attempt.
5922299782Sadrian			 */
5923299782Sadrian			if (status->ack) {
5924299782Sadrian				retrycnt = status->framecnt - 1;
5925299782Sadrian			} else {
5926299782Sadrian				retrycnt = status->framecnt;
5927299782Sadrian				if (retrycnt == 0)
5928299782Sadrian					retrycnt = 1;
5929299782Sadrian			}
5930299032Sadrian			ieee80211_ratectl_tx_complete(meta->mt_ni->ni_vap, meta->mt_ni,
5931299032Sadrian			    status->ack ?
5932299032Sadrian			      IEEE80211_RATECTL_TX_SUCCESS :
5933299032Sadrian			      IEEE80211_RATECTL_TX_FAILURE,
5934299032Sadrian			    &retrycnt, 0);
5935287197Sglebius			ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0);
5936287197Sglebius			meta->mt_ni = NULL;
5937203945Sweongyo			meta->mt_m = NULL;
5938287197Sglebius		} else
5939203945Sweongyo			KASSERT(meta->mt_m == NULL,
5940203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
5941203945Sweongyo
5942203945Sweongyo		dr->dr_usedslot--;
5943287197Sglebius		if (meta->mt_islast)
5944203945Sweongyo			break;
5945203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
5946203945Sweongyo	}
5947203945Sweongyo	sc->sc_watchdog_timer = 0;
5948203945Sweongyo	if (dr->dr_stop) {
5949203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
5950203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5951203945Sweongyo		dr->dr_stop = 0;
5952203945Sweongyo	}
5953203945Sweongyo}
5954203945Sweongyo
5955203945Sweongyostatic void
5956203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
5957203945Sweongyo    const struct bwn_txstatus *status)
5958203945Sweongyo{
5959203945Sweongyo	struct bwn_pio_txqueue *tq;
5960203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
5961203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5962299032Sadrian	int retrycnt = 0;
5963203945Sweongyo
5964203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5965203945Sweongyo
5966203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
5967203945Sweongyo	if (tq == NULL)
5968203945Sweongyo		return;
5969203945Sweongyo
5970203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
5971203945Sweongyo	tq->tq_free++;
5972203945Sweongyo
5973203945Sweongyo	if (tp->tp_ni != NULL) {
5974203945Sweongyo		/*
5975203945Sweongyo		 * Do any tx complete callback.  Note this must
5976203945Sweongyo		 * be done before releasing the node reference.
5977203945Sweongyo		 */
5978299032Sadrian
5979299782Sadrian		/*
5980299782Sadrian		 * If we don't get an ACK, then we should log the
5981299782Sadrian		 * full framecnt.  That may be 0 if it's a PHY
5982299782Sadrian		 * failure, so ensure that gets logged as some
5983299782Sadrian		 * retry attempt.
5984299782Sadrian		 */
5985299782Sadrian		if (status->ack) {
5986299782Sadrian			retrycnt = status->framecnt - 1;
5987299782Sadrian		} else {
5988299782Sadrian			retrycnt = status->framecnt;
5989299782Sadrian			if (retrycnt == 0)
5990299782Sadrian				retrycnt = 1;
5991299782Sadrian		}
5992299032Sadrian		ieee80211_ratectl_tx_complete(tp->tp_ni->ni_vap, tp->tp_ni,
5993299032Sadrian		    status->ack ?
5994299032Sadrian		      IEEE80211_RATECTL_TX_SUCCESS :
5995299032Sadrian		      IEEE80211_RATECTL_TX_FAILURE,
5996299032Sadrian		    &retrycnt, 0);
5997299032Sadrian
5998203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
5999203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
6000203945Sweongyo		ieee80211_free_node(tp->tp_ni);
6001203945Sweongyo		tp->tp_ni = NULL;
6002203945Sweongyo	}
6003203945Sweongyo	m_freem(tp->tp_m);
6004203945Sweongyo	tp->tp_m = NULL;
6005203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
6006203945Sweongyo
6007203945Sweongyo	sc->sc_watchdog_timer = 0;
6008203945Sweongyo}
6009203945Sweongyo
6010203945Sweongyostatic void
6011203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
6012203945Sweongyo{
6013203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6014203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6015287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
6016203945Sweongyo	unsigned long now;
6017299794Sadrian	bwn_txpwr_result_t result;
6018203945Sweongyo
6019203945Sweongyo	BWN_GETTIME(now);
6020203945Sweongyo
6021297409Sadrian	if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime))
6022203945Sweongyo		return;
6023203945Sweongyo	phy->nexttime = now + 2 * 1000;
6024203945Sweongyo
6025204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
6026204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
6027203945Sweongyo		return;
6028203945Sweongyo
6029203945Sweongyo	if (phy->recalc_txpwr != NULL) {
6030203945Sweongyo		result = phy->recalc_txpwr(mac,
6031203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
6032203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
6033203945Sweongyo			return;
6034203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
6035203945Sweongyo		    ("%s: fail", __func__));
6036203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
6037203945Sweongyo
6038203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
6039203945Sweongyo	}
6040203945Sweongyo}
6041203945Sweongyo
6042203945Sweongyostatic uint16_t
6043203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
6044203945Sweongyo{
6045203945Sweongyo
6046203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
6047203945Sweongyo}
6048203945Sweongyo
6049203945Sweongyostatic uint32_t
6050203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
6051203945Sweongyo{
6052203945Sweongyo
6053203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
6054203945Sweongyo}
6055203945Sweongyo
6056203945Sweongyostatic void
6057203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
6058203945Sweongyo{
6059203945Sweongyo
6060203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
6061203945Sweongyo}
6062203945Sweongyo
6063203945Sweongyostatic void
6064203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
6065203945Sweongyo{
6066203945Sweongyo
6067203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
6068203945Sweongyo}
6069203945Sweongyo
6070203945Sweongyostatic int
6071203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
6072203945Sweongyo{
6073203945Sweongyo
6074203945Sweongyo	switch (rate) {
6075203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
6076203945Sweongyo	case 12:
6077203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6078203945Sweongyo	case 18:
6079203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6080203945Sweongyo	case 24:
6081203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6082203945Sweongyo	case 36:
6083203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6084203945Sweongyo	case 48:
6085203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6086203945Sweongyo	case 72:
6087203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6088203945Sweongyo	case 96:
6089203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6090203945Sweongyo	case 108:
6091203945Sweongyo		return (BWN_OFDM_RATE_54MB);
6092203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
6093203945Sweongyo	case 2:
6094203945Sweongyo		return (BWN_CCK_RATE_1MB);
6095203945Sweongyo	case 4:
6096203945Sweongyo		return (BWN_CCK_RATE_2MB);
6097203945Sweongyo	case 11:
6098203945Sweongyo		return (BWN_CCK_RATE_5MB);
6099203945Sweongyo	case 22:
6100203945Sweongyo		return (BWN_CCK_RATE_11MB);
6101203945Sweongyo	}
6102203945Sweongyo
6103203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
6104203945Sweongyo	return (BWN_CCK_RATE_1MB);
6105203945Sweongyo}
6106203945Sweongyo
6107299799Sadrianstatic uint16_t
6108299799Sadrianbwn_set_txhdr_phyctl1(struct bwn_mac *mac, uint8_t bitrate)
6109299799Sadrian{
6110299799Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6111299799Sadrian	uint16_t control = 0;
6112299799Sadrian	uint16_t bw;
6113299799Sadrian
6114299799Sadrian	/* XXX TODO: this is for LP phy, what about N-PHY, etc? */
6115299799Sadrian	bw = BWN_TXH_PHY1_BW_20;
6116299799Sadrian
6117299799Sadrian	if (BWN_ISCCKRATE(bitrate) && phy->type != BWN_PHYTYPE_LP) {
6118299799Sadrian		control = bw;
6119299799Sadrian	} else {
6120299799Sadrian		control = bw;
6121299799Sadrian		/* Figure out coding rate and modulation */
6122299799Sadrian		/* XXX TODO: table-ize, for MCS transmit */
6123299799Sadrian		/* Note: this is BWN_*_RATE values */
6124299799Sadrian		switch (bitrate) {
6125299799Sadrian		case BWN_CCK_RATE_1MB:
6126299799Sadrian			control |= 0;
6127299799Sadrian			break;
6128299799Sadrian		case BWN_CCK_RATE_2MB:
6129299799Sadrian			control |= 1;
6130299799Sadrian			break;
6131299799Sadrian		case BWN_CCK_RATE_5MB:
6132299799Sadrian			control |= 2;
6133299799Sadrian			break;
6134299799Sadrian		case BWN_CCK_RATE_11MB:
6135299799Sadrian			control |= 3;
6136299799Sadrian			break;
6137299799Sadrian		case BWN_OFDM_RATE_6MB:
6138299799Sadrian			control |= BWN_TXH_PHY1_CRATE_1_2;
6139299799Sadrian			control |= BWN_TXH_PHY1_MODUL_BPSK;
6140299799Sadrian			break;
6141299799Sadrian		case BWN_OFDM_RATE_9MB:
6142299799Sadrian			control |= BWN_TXH_PHY1_CRATE_3_4;
6143299799Sadrian			control |= BWN_TXH_PHY1_MODUL_BPSK;
6144299799Sadrian			break;
6145299799Sadrian		case BWN_OFDM_RATE_12MB:
6146299799Sadrian			control |= BWN_TXH_PHY1_CRATE_1_2;
6147299799Sadrian			control |= BWN_TXH_PHY1_MODUL_QPSK;
6148299799Sadrian			break;
6149299799Sadrian		case BWN_OFDM_RATE_18MB:
6150299799Sadrian			control |= BWN_TXH_PHY1_CRATE_3_4;
6151299799Sadrian			control |= BWN_TXH_PHY1_MODUL_QPSK;
6152299799Sadrian			break;
6153299799Sadrian		case BWN_OFDM_RATE_24MB:
6154299799Sadrian			control |= BWN_TXH_PHY1_CRATE_1_2;
6155299799Sadrian			control |= BWN_TXH_PHY1_MODUL_QAM16;
6156299799Sadrian			break;
6157299799Sadrian		case BWN_OFDM_RATE_36MB:
6158299799Sadrian			control |= BWN_TXH_PHY1_CRATE_3_4;
6159299799Sadrian			control |= BWN_TXH_PHY1_MODUL_QAM16;
6160299799Sadrian			break;
6161299799Sadrian		case BWN_OFDM_RATE_48MB:
6162299799Sadrian			control |= BWN_TXH_PHY1_CRATE_1_2;
6163299799Sadrian			control |= BWN_TXH_PHY1_MODUL_QAM64;
6164299799Sadrian			break;
6165299799Sadrian		case BWN_OFDM_RATE_54MB:
6166299799Sadrian			control |= BWN_TXH_PHY1_CRATE_3_4;
6167299799Sadrian			control |= BWN_TXH_PHY1_MODUL_QAM64;
6168299799Sadrian			break;
6169299799Sadrian		default:
6170299799Sadrian			break;
6171299799Sadrian		}
6172299799Sadrian		control |= BWN_TXH_PHY1_MODE_SISO;
6173299799Sadrian	}
6174299799Sadrian
6175299799Sadrian	return control;
6176299799Sadrian}
6177299799Sadrian
6178203945Sweongyostatic int
6179203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
6180203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
6181203945Sweongyo{
6182203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
6183203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6184203945Sweongyo	struct ieee80211_frame *wh;
6185203945Sweongyo	struct ieee80211_frame *protwh;
6186203945Sweongyo	struct ieee80211_frame_cts *cts;
6187203945Sweongyo	struct ieee80211_frame_rts *rts;
6188203945Sweongyo	const struct ieee80211_txparam *tp;
6189203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
6190287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
6191203945Sweongyo	struct mbuf *mprot;
6192203945Sweongyo	unsigned int len;
6193203945Sweongyo	uint32_t macctl = 0;
6194203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
6195203945Sweongyo	uint16_t phyctl = 0;
6196203945Sweongyo	uint8_t rate, rate_fb;
6197299799Sadrian	int fill_phy_ctl1 = 0;
6198203945Sweongyo
6199203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
6200203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
6201203945Sweongyo
6202203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
6203203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
6204203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
6205203945Sweongyo
6206299799Sadrian	if ((phy->type == BWN_PHYTYPE_N) || (phy->type == BWN_PHYTYPE_LP)
6207299799Sadrian	    || (phy->type == BWN_PHYTYPE_HT))
6208299799Sadrian		fill_phy_ctl1 = 1;
6209299799Sadrian
6210203945Sweongyo	/*
6211203945Sweongyo	 * Find TX rate
6212203945Sweongyo	 */
6213203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
6214203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
6215203945Sweongyo		rate = rate_fb = tp->mgmtrate;
6216203945Sweongyo	else if (ismcast)
6217203945Sweongyo		rate = rate_fb = tp->mcastrate;
6218203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
6219203945Sweongyo		rate = rate_fb = tp->ucastrate;
6220203945Sweongyo	else {
6221299032Sadrian		/* XXX TODO: don't fall back to CCK rates for OFDM */
6222206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
6223203945Sweongyo		rate = ni->ni_txrate;
6224203945Sweongyo
6225203945Sweongyo		if (rix > 0)
6226203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
6227203945Sweongyo			    IEEE80211_RATE_VAL;
6228203945Sweongyo		else
6229203945Sweongyo			rate_fb = rate;
6230203945Sweongyo	}
6231203945Sweongyo
6232203945Sweongyo	sc->sc_tx_rate = rate;
6233203945Sweongyo
6234299032Sadrian	/* Note: this maps the select ieee80211 rate to hardware rate */
6235203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
6236203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
6237203945Sweongyo
6238203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
6239203945Sweongyo	    bwn_plcp_getcck(rate);
6240203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
6241203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
6242203945Sweongyo
6243299032Sadrian	/* XXX rate/rate_fb is the hardware rate */
6244203945Sweongyo	if ((rate_fb == rate) ||
6245203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
6246203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
6247203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
6248203945Sweongyo	else
6249203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
6250203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
6251203945Sweongyo
6252203945Sweongyo	/* XXX TX encryption */
6253300114Sadrian
6254300114Sadrian	switch (mac->mac_fw.fw_hdr_format) {
6255300114Sadrian	case BWN_FW_HDR_351:
6256300114Sadrian		bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->body.r351.plcp),
6257300114Sadrian		    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
6258300114Sadrian		break;
6259300114Sadrian	case BWN_FW_HDR_410:
6260300114Sadrian		bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->body.r410.plcp),
6261300114Sadrian		    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
6262300114Sadrian		break;
6263300114Sadrian	case BWN_FW_HDR_598:
6264300114Sadrian		bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->body.r598.plcp),
6265300114Sadrian		    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
6266300114Sadrian		break;
6267300114Sadrian	}
6268300114Sadrian
6269203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
6270203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
6271203945Sweongyo
6272203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
6273203945Sweongyo	    BWN_TX_EFT_FB_CCK;
6274203945Sweongyo	txhdr->chan = phy->chan;
6275203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
6276203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
6277299032Sadrian	/* XXX preamble? obey net80211 */
6278203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
6279203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
6280203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
6281203945Sweongyo
6282299798Sadrian	if (! phy->gmode)
6283299798Sadrian		macctl |= BWN_TX_MAC_5GHZ;
6284299798Sadrian
6285203945Sweongyo	/* XXX TX antenna selection */
6286203945Sweongyo
6287203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
6288203945Sweongyo	case 0:
6289203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
6290203945Sweongyo		break;
6291203945Sweongyo	case 1:
6292203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
6293203945Sweongyo		break;
6294203945Sweongyo	case 2:
6295203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
6296203945Sweongyo		break;
6297203945Sweongyo	case 3:
6298203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
6299203945Sweongyo		break;
6300203945Sweongyo	case 4:
6301203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
6302203945Sweongyo		break;
6303203945Sweongyo	default:
6304203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6305203945Sweongyo	}
6306203945Sweongyo
6307203945Sweongyo	if (!ismcast)
6308203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
6309203945Sweongyo
6310203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
6311203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
6312203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
6313203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
6314203945Sweongyo
6315203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
6316203945Sweongyo		/* XXX RTS rate is always 1MB??? */
6317299032Sadrian		/* XXX TODO: don't fall back to CCK rates for OFDM */
6318203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
6319203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
6320203945Sweongyo
6321299032Sadrian		/* XXX 'rate' here is hardware rate now, not the net80211 rate */
6322203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
6323203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
6324203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
6325203945Sweongyo
6326203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
6327300114Sadrian
6328300114Sadrian			switch (mac->mac_fw.fw_hdr_format) {
6329300114Sadrian			case BWN_FW_HDR_351:
6330300114Sadrian				cts = (struct ieee80211_frame_cts *)
6331300114Sadrian				    txhdr->body.r351.rts_frame;
6332300114Sadrian				break;
6333300114Sadrian			case BWN_FW_HDR_410:
6334300114Sadrian				cts = (struct ieee80211_frame_cts *)
6335300114Sadrian				    txhdr->body.r410.rts_frame;
6336300114Sadrian				break;
6337300114Sadrian			case BWN_FW_HDR_598:
6338300114Sadrian				cts = (struct ieee80211_frame_cts *)
6339300114Sadrian				    txhdr->body.r598.rts_frame;
6340300114Sadrian				break;
6341300114Sadrian			}
6342300114Sadrian
6343203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
6344203945Sweongyo			    protdur);
6345203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
6346203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
6347203945Sweongyo			    mprot->m_pkthdr.len);
6348203945Sweongyo			m_freem(mprot);
6349203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
6350203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
6351203945Sweongyo		} else {
6352300114Sadrian			switch (mac->mac_fw.fw_hdr_format) {
6353300114Sadrian			case BWN_FW_HDR_351:
6354300114Sadrian				rts = (struct ieee80211_frame_rts *)
6355300114Sadrian				    txhdr->body.r351.rts_frame;
6356300114Sadrian				break;
6357300114Sadrian			case BWN_FW_HDR_410:
6358300114Sadrian				rts = (struct ieee80211_frame_rts *)
6359300114Sadrian				    txhdr->body.r410.rts_frame;
6360300114Sadrian				break;
6361300114Sadrian			case BWN_FW_HDR_598:
6362300114Sadrian				rts = (struct ieee80211_frame_rts *)
6363300114Sadrian				    txhdr->body.r598.rts_frame;
6364300114Sadrian				break;
6365300114Sadrian			}
6366300114Sadrian
6367299032Sadrian			/* XXX rate/rate_fb is the hardware rate */
6368203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
6369203945Sweongyo			    isshort);
6370203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
6371203945Sweongyo			    wh->i_addr2, protdur);
6372203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
6373203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
6374203945Sweongyo			    mprot->m_pkthdr.len);
6375203945Sweongyo			m_freem(mprot);
6376203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
6377203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
6378203945Sweongyo		}
6379203945Sweongyo		len += IEEE80211_CRC_LEN;
6380300114Sadrian
6381300114Sadrian		switch (mac->mac_fw.fw_hdr_format) {
6382300114Sadrian		case BWN_FW_HDR_351:
6383300114Sadrian			bwn_plcp_genhdr((struct bwn_plcp4 *)
6384300114Sadrian			    &txhdr->body.r351.rts_plcp, len, rts_rate);
6385300114Sadrian			break;
6386300114Sadrian		case BWN_FW_HDR_410:
6387300114Sadrian			bwn_plcp_genhdr((struct bwn_plcp4 *)
6388300114Sadrian			    &txhdr->body.r410.rts_plcp, len, rts_rate);
6389300114Sadrian			break;
6390300114Sadrian		case BWN_FW_HDR_598:
6391300114Sadrian			bwn_plcp_genhdr((struct bwn_plcp4 *)
6392300114Sadrian			    &txhdr->body.r598.rts_plcp, len, rts_rate);
6393300114Sadrian			break;
6394300114Sadrian		}
6395300114Sadrian
6396203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
6397203945Sweongyo		    rts_rate_fb);
6398203945Sweongyo
6399300114Sadrian		switch (mac->mac_fw.fw_hdr_format) {
6400300114Sadrian		case BWN_FW_HDR_351:
6401300114Sadrian			protwh = (struct ieee80211_frame *)
6402300114Sadrian			    &txhdr->body.r351.rts_frame;
6403300114Sadrian			break;
6404300114Sadrian		case BWN_FW_HDR_410:
6405300114Sadrian			protwh = (struct ieee80211_frame *)
6406300114Sadrian			    &txhdr->body.r410.rts_frame;
6407300114Sadrian			break;
6408300114Sadrian		case BWN_FW_HDR_598:
6409300114Sadrian			protwh = (struct ieee80211_frame *)
6410300114Sadrian			    &txhdr->body.r598.rts_frame;
6411300114Sadrian			break;
6412300114Sadrian		}
6413300114Sadrian
6414203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
6415203945Sweongyo
6416203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
6417203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
6418203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
6419203945Sweongyo		} else {
6420203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
6421203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
6422203945Sweongyo		}
6423203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
6424203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
6425299799Sadrian
6426299799Sadrian		if (fill_phy_ctl1) {
6427299799Sadrian			txhdr->phyctl_1rts = htole16(bwn_set_txhdr_phyctl1(mac, rts_rate));
6428299799Sadrian			txhdr->phyctl_1rtsfb = htole16(bwn_set_txhdr_phyctl1(mac, rts_rate_fb));
6429299799Sadrian		}
6430203945Sweongyo	}
6431203945Sweongyo
6432299799Sadrian	if (fill_phy_ctl1) {
6433299799Sadrian		txhdr->phyctl_1 = htole16(bwn_set_txhdr_phyctl1(mac, rate));
6434299799Sadrian		txhdr->phyctl_1fb = htole16(bwn_set_txhdr_phyctl1(mac, rate_fb));
6435299799Sadrian	}
6436299799Sadrian
6437300114Sadrian	switch (mac->mac_fw.fw_hdr_format) {
6438300114Sadrian	case BWN_FW_HDR_351:
6439300114Sadrian		txhdr->body.r351.cookie = htole16(cookie);
6440300114Sadrian		break;
6441300114Sadrian	case BWN_FW_HDR_410:
6442300114Sadrian		txhdr->body.r410.cookie = htole16(cookie);
6443300114Sadrian		break;
6444300114Sadrian	case BWN_FW_HDR_598:
6445300114Sadrian		txhdr->body.r598.cookie = htole16(cookie);
6446300114Sadrian		break;
6447300114Sadrian	}
6448203945Sweongyo
6449203945Sweongyo	txhdr->macctl = htole32(macctl);
6450203945Sweongyo	txhdr->phyctl = htole16(phyctl);
6451203945Sweongyo
6452203945Sweongyo	/*
6453203945Sweongyo	 * TX radio tap
6454203945Sweongyo	 */
6455203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
6456203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
6457260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
6458203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
6459203945Sweongyo		if (isshort &&
6460203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
6461203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
6462203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
6463203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
6464203945Sweongyo
6465203945Sweongyo		ieee80211_radiotap_tx(vap, m);
6466203945Sweongyo	}
6467203945Sweongyo
6468203945Sweongyo	return (0);
6469203945Sweongyo}
6470203945Sweongyo
6471203945Sweongyostatic void
6472203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
6473203945Sweongyo    const uint8_t rate)
6474203945Sweongyo{
6475203945Sweongyo	uint32_t d, plen;
6476203945Sweongyo	uint8_t *raw = plcp->o.raw;
6477203945Sweongyo
6478203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
6479203945Sweongyo		d = bwn_plcp_getofdm(rate);
6480203945Sweongyo		KASSERT(!(octets & 0xf000),
6481203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6482203945Sweongyo		d |= (octets << 5);
6483203945Sweongyo		plcp->o.data = htole32(d);
6484203945Sweongyo	} else {
6485203945Sweongyo		plen = octets * 16 / rate;
6486203945Sweongyo		if ((octets * 16 % rate) > 0) {
6487203945Sweongyo			plen++;
6488203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
6489203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
6490203945Sweongyo				raw[1] = 0x84;
6491203945Sweongyo			} else
6492203945Sweongyo				raw[1] = 0x04;
6493203945Sweongyo		} else
6494203945Sweongyo			raw[1] = 0x04;
6495203945Sweongyo		plcp->o.data |= htole32(plen << 16);
6496203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
6497203945Sweongyo	}
6498203945Sweongyo}
6499203945Sweongyo
6500203945Sweongyostatic uint8_t
6501203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
6502203945Sweongyo{
6503204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6504203945Sweongyo	uint8_t mask;
6505203945Sweongyo
6506203945Sweongyo	if (n == 0)
6507203945Sweongyo		return (0);
6508203945Sweongyo	if (mac->mac_phy.gmode)
6509204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
6510203945Sweongyo	else
6511204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
6512203945Sweongyo	if (!(mask & (1 << (n - 1))))
6513203945Sweongyo		return (0);
6514203945Sweongyo	return (n);
6515203945Sweongyo}
6516203945Sweongyo
6517299028Sadrian/*
6518299028Sadrian * Return a fallback rate for the given rate.
6519299028Sadrian *
6520299028Sadrian * Note: Don't fall back from OFDM to CCK.
6521299028Sadrian */
6522203945Sweongyostatic uint8_t
6523203945Sweongyobwn_get_fbrate(uint8_t bitrate)
6524203945Sweongyo{
6525203945Sweongyo	switch (bitrate) {
6526299028Sadrian	/* CCK */
6527203945Sweongyo	case BWN_CCK_RATE_1MB:
6528203945Sweongyo		return (BWN_CCK_RATE_1MB);
6529203945Sweongyo	case BWN_CCK_RATE_2MB:
6530203945Sweongyo		return (BWN_CCK_RATE_1MB);
6531203945Sweongyo	case BWN_CCK_RATE_5MB:
6532203945Sweongyo		return (BWN_CCK_RATE_2MB);
6533203945Sweongyo	case BWN_CCK_RATE_11MB:
6534203945Sweongyo		return (BWN_CCK_RATE_5MB);
6535299028Sadrian
6536299028Sadrian	/* OFDM */
6537203945Sweongyo	case BWN_OFDM_RATE_6MB:
6538299028Sadrian		return (BWN_OFDM_RATE_6MB);
6539203945Sweongyo	case BWN_OFDM_RATE_9MB:
6540203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6541203945Sweongyo	case BWN_OFDM_RATE_12MB:
6542203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6543203945Sweongyo	case BWN_OFDM_RATE_18MB:
6544203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6545203945Sweongyo	case BWN_OFDM_RATE_24MB:
6546203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6547203945Sweongyo	case BWN_OFDM_RATE_36MB:
6548203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6549203945Sweongyo	case BWN_OFDM_RATE_48MB:
6550203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6551203945Sweongyo	case BWN_OFDM_RATE_54MB:
6552203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6553203945Sweongyo	}
6554203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6555203945Sweongyo	return (0);
6556203945Sweongyo}
6557203945Sweongyo
6558203945Sweongyostatic uint32_t
6559203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6560203945Sweongyo    uint32_t ctl, const void *_data, int len)
6561203945Sweongyo{
6562204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6563203945Sweongyo	uint32_t value = 0;
6564203945Sweongyo	const uint8_t *data = _data;
6565203945Sweongyo
6566203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
6567203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
6568203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
6569203945Sweongyo
6570204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
6571203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
6572203945Sweongyo	if (len & 3) {
6573203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
6574203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
6575203945Sweongyo		data = &(data[len - 1]);
6576203945Sweongyo		switch (len & 3) {
6577203945Sweongyo		case 3:
6578203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
6579203945Sweongyo			value |= (uint32_t)(*data) << 16;
6580203945Sweongyo			data--;
6581203945Sweongyo		case 2:
6582203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
6583203945Sweongyo			value |= (uint32_t)(*data) << 8;
6584203945Sweongyo			data--;
6585203945Sweongyo		case 1:
6586203945Sweongyo			value |= (uint32_t)(*data);
6587203945Sweongyo		}
6588203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
6589203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
6590203945Sweongyo	}
6591203945Sweongyo
6592203945Sweongyo	return (ctl);
6593203945Sweongyo}
6594203945Sweongyo
6595203945Sweongyostatic void
6596203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6597203945Sweongyo    uint16_t offset, uint32_t value)
6598203945Sweongyo{
6599203945Sweongyo
6600203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
6601203945Sweongyo}
6602203945Sweongyo
6603203945Sweongyostatic uint16_t
6604203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6605203945Sweongyo    uint16_t ctl, const void *_data, int len)
6606203945Sweongyo{
6607204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6608203945Sweongyo	const uint8_t *data = _data;
6609203945Sweongyo
6610203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
6611203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6612203945Sweongyo
6613204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
6614203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
6615203945Sweongyo	if (len & 1) {
6616203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
6617203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6618203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
6619203945Sweongyo	}
6620203945Sweongyo
6621203945Sweongyo	return (ctl);
6622203945Sweongyo}
6623203945Sweongyo
6624203945Sweongyostatic uint16_t
6625203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
6626203945Sweongyo    uint16_t ctl, struct mbuf *m0)
6627203945Sweongyo{
6628203945Sweongyo	int i, j = 0;
6629203945Sweongyo	uint16_t data = 0;
6630203945Sweongyo	const uint8_t *buf;
6631203945Sweongyo	struct mbuf *m = m0;
6632203945Sweongyo
6633203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
6634203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6635203945Sweongyo
6636203945Sweongyo	for (; m != NULL; m = m->m_next) {
6637203945Sweongyo		buf = mtod(m, const uint8_t *);
6638203945Sweongyo		for (i = 0; i < m->m_len; i++) {
6639203945Sweongyo			if (!((j++) % 2))
6640203945Sweongyo				data |= buf[i];
6641203945Sweongyo			else {
6642203945Sweongyo				data |= (buf[i] << 8);
6643203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
6644203945Sweongyo				data = 0;
6645203945Sweongyo			}
6646203945Sweongyo		}
6647203945Sweongyo	}
6648203945Sweongyo	if (m0->m_pkthdr.len % 2) {
6649203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
6650203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
6651203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
6652203945Sweongyo	}
6653203945Sweongyo
6654203945Sweongyo	return (ctl);
6655203945Sweongyo}
6656203945Sweongyo
6657203945Sweongyostatic void
6658203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
6659203945Sweongyo{
6660203945Sweongyo
6661299797Sadrian	/* XXX should exit if 5GHz band .. */
6662203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
6663203945Sweongyo		return;
6664299797Sadrian
6665203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
6666299797Sadrian	/* Disabled in Linux b43, can adversely effect performance */
6667299797Sadrian#if 0
6668203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
6669299797Sadrian#endif
6670203945Sweongyo}
6671203945Sweongyo
6672203945Sweongyostatic struct bwn_dma_ring *
6673203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
6674203945Sweongyo{
6675203945Sweongyo
6676203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
6677203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
6678203945Sweongyo
6679203945Sweongyo	switch (prio) {
6680203945Sweongyo	case 3:
6681203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
6682203945Sweongyo	case 2:
6683203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
6684203945Sweongyo	case 0:
6685203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
6686203945Sweongyo	case 1:
6687203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
6688203945Sweongyo	}
6689203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
6690204242Simp	return (NULL);
6691203945Sweongyo}
6692203945Sweongyo
6693203945Sweongyostatic int
6694203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
6695203945Sweongyo{
6696203945Sweongyo	int slot;
6697203945Sweongyo
6698204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
6699203945Sweongyo
6700203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
6701203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
6702203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
6703203945Sweongyo
6704203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
6705203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
6706203945Sweongyo	dr->dr_curslot = slot;
6707203945Sweongyo	dr->dr_usedslot++;
6708203945Sweongyo
6709203945Sweongyo	return (slot);
6710203945Sweongyo}
6711203945Sweongyo
6712203945Sweongyostatic struct bwn_pio_txqueue *
6713203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
6714203945Sweongyo    struct bwn_pio_txpkt **pack)
6715203945Sweongyo{
6716203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
6717203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
6718203945Sweongyo	unsigned int index;
6719203945Sweongyo
6720203945Sweongyo	switch (cookie & 0xf000) {
6721203945Sweongyo	case 0x1000:
6722203945Sweongyo		tq = &pio->wme[WME_AC_BK];
6723203945Sweongyo		break;
6724203945Sweongyo	case 0x2000:
6725203945Sweongyo		tq = &pio->wme[WME_AC_BE];
6726203945Sweongyo		break;
6727203945Sweongyo	case 0x3000:
6728203945Sweongyo		tq = &pio->wme[WME_AC_VI];
6729203945Sweongyo		break;
6730203945Sweongyo	case 0x4000:
6731203945Sweongyo		tq = &pio->wme[WME_AC_VO];
6732203945Sweongyo		break;
6733203945Sweongyo	case 0x5000:
6734203945Sweongyo		tq = &pio->mcast;
6735203945Sweongyo		break;
6736203945Sweongyo	}
6737203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
6738203945Sweongyo	if (tq == NULL)
6739203945Sweongyo		return (NULL);
6740203945Sweongyo	index = (cookie & 0x0fff);
6741203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
6742203945Sweongyo	if (index >= N(tq->tq_pkts))
6743203945Sweongyo		return (NULL);
6744203945Sweongyo	*pack = &tq->tq_pkts[index];
6745203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
6746203945Sweongyo	return (tq);
6747203945Sweongyo}
6748203945Sweongyo
6749203945Sweongyostatic void
6750203945Sweongyobwn_txpwr(void *arg, int npending)
6751203945Sweongyo{
6752203945Sweongyo	struct bwn_mac *mac = arg;
6753203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6754203945Sweongyo
6755203945Sweongyo	BWN_LOCK(sc);
6756203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
6757203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
6758203945Sweongyo		mac->mac_phy.set_txpwr(mac);
6759203945Sweongyo	BWN_UNLOCK(sc);
6760203945Sweongyo}
6761203945Sweongyo
6762203945Sweongyostatic void
6763203945Sweongyobwn_task_15s(struct bwn_mac *mac)
6764203945Sweongyo{
6765203945Sweongyo	uint16_t reg;
6766203945Sweongyo
6767203945Sweongyo	if (mac->mac_fw.opensource) {
6768203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
6769203945Sweongyo		if (reg) {
6770203945Sweongyo			bwn_restart(mac, "fw watchdog");
6771203945Sweongyo			return;
6772203945Sweongyo		}
6773203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
6774203945Sweongyo	}
6775203945Sweongyo	if (mac->mac_phy.task_15s)
6776203945Sweongyo		mac->mac_phy.task_15s(mac);
6777203945Sweongyo
6778203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
6779203945Sweongyo}
6780203945Sweongyo
6781203945Sweongyostatic void
6782203945Sweongyobwn_task_30s(struct bwn_mac *mac)
6783203945Sweongyo{
6784203945Sweongyo
6785203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
6786203945Sweongyo		return;
6787203945Sweongyo	mac->mac_noise.noi_running = 1;
6788203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
6789203945Sweongyo
6790203945Sweongyo	bwn_noise_gensample(mac);
6791203945Sweongyo}
6792203945Sweongyo
6793203945Sweongyostatic void
6794203945Sweongyobwn_task_60s(struct bwn_mac *mac)
6795203945Sweongyo{
6796203945Sweongyo
6797203945Sweongyo	if (mac->mac_phy.task_60s)
6798203945Sweongyo		mac->mac_phy.task_60s(mac);
6799203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
6800203945Sweongyo}
6801203945Sweongyo
6802203945Sweongyostatic void
6803203945Sweongyobwn_tasks(void *arg)
6804203945Sweongyo{
6805203945Sweongyo	struct bwn_mac *mac = arg;
6806203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6807203945Sweongyo
6808203945Sweongyo	BWN_ASSERT_LOCKED(sc);
6809203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
6810203945Sweongyo		return;
6811203945Sweongyo
6812203945Sweongyo	if (mac->mac_task_state % 4 == 0)
6813203945Sweongyo		bwn_task_60s(mac);
6814203945Sweongyo	if (mac->mac_task_state % 2 == 0)
6815203945Sweongyo		bwn_task_30s(mac);
6816203945Sweongyo	bwn_task_15s(mac);
6817203945Sweongyo
6818203945Sweongyo	mac->mac_task_state++;
6819203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
6820203945Sweongyo}
6821203945Sweongyo
6822203945Sweongyostatic int
6823203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
6824203945Sweongyo{
6825203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6826203945Sweongyo
6827203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
6828203945Sweongyo
6829203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
6830203945Sweongyo	case 0xb:
6831203945Sweongyo		return (BWN_OFDM_RATE_6MB);
6832203945Sweongyo	case 0xf:
6833203945Sweongyo		return (BWN_OFDM_RATE_9MB);
6834203945Sweongyo	case 0xa:
6835203945Sweongyo		return (BWN_OFDM_RATE_12MB);
6836203945Sweongyo	case 0xe:
6837203945Sweongyo		return (BWN_OFDM_RATE_18MB);
6838203945Sweongyo	case 0x9:
6839203945Sweongyo		return (BWN_OFDM_RATE_24MB);
6840203945Sweongyo	case 0xd:
6841203945Sweongyo		return (BWN_OFDM_RATE_36MB);
6842203945Sweongyo	case 0x8:
6843203945Sweongyo		return (BWN_OFDM_RATE_48MB);
6844203945Sweongyo	case 0xc:
6845203945Sweongyo		return (BWN_OFDM_RATE_54MB);
6846203945Sweongyo	}
6847203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
6848203945Sweongyo	    plcp->o.raw[0] & 0xf);
6849203945Sweongyo	return (-1);
6850203945Sweongyo}
6851203945Sweongyo
6852203945Sweongyostatic int
6853203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
6854203945Sweongyo{
6855203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6856203945Sweongyo
6857203945Sweongyo	switch (plcp->o.raw[0]) {
6858203945Sweongyo	case 0x0a:
6859203945Sweongyo		return (BWN_CCK_RATE_1MB);
6860203945Sweongyo	case 0x14:
6861203945Sweongyo		return (BWN_CCK_RATE_2MB);
6862203945Sweongyo	case 0x37:
6863203945Sweongyo		return (BWN_CCK_RATE_5MB);
6864203945Sweongyo	case 0x6e:
6865203945Sweongyo		return (BWN_CCK_RATE_11MB);
6866203945Sweongyo	}
6867203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
6868203945Sweongyo	return (-1);
6869203945Sweongyo}
6870203945Sweongyo
6871203945Sweongyostatic void
6872203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
6873203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
6874203945Sweongyo    int rssi, int noise)
6875203945Sweongyo{
6876203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6877203945Sweongyo	const struct ieee80211_frame_min *wh;
6878203945Sweongyo	uint64_t tsf;
6879203945Sweongyo	uint16_t low_mactime_now;
6880300114Sadrian	uint16_t mt;
6881203945Sweongyo
6882203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
6883203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
6884203945Sweongyo
6885203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
6886260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
6887203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
6888203945Sweongyo
6889203945Sweongyo	bwn_tsf_read(mac, &tsf);
6890203945Sweongyo	low_mactime_now = tsf;
6891203945Sweongyo	tsf = tsf & ~0xffffULL;
6892300114Sadrian
6893300114Sadrian	switch (mac->mac_fw.fw_hdr_format) {
6894300114Sadrian	case BWN_FW_HDR_351:
6895300114Sadrian	case BWN_FW_HDR_410:
6896300114Sadrian		mt = le16toh(rxhdr->ps4.r351.mac_time);
6897300114Sadrian		break;
6898300114Sadrian	case BWN_FW_HDR_598:
6899300114Sadrian		mt = le16toh(rxhdr->ps4.r598.mac_time);
6900300114Sadrian		break;
6901300114Sadrian	}
6902300114Sadrian
6903300114Sadrian	tsf += mt;
6904300114Sadrian	if (low_mactime_now < mt)
6905203945Sweongyo		tsf -= 0x10000;
6906203945Sweongyo
6907203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
6908203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
6909203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
6910203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
6911203945Sweongyo}
6912203945Sweongyo
6913203945Sweongyostatic void
6914203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
6915203945Sweongyo{
6916203945Sweongyo	uint32_t low, high;
6917203945Sweongyo
6918204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
6919203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6920203945Sweongyo
6921203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
6922203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
6923203945Sweongyo	*tsf = high;
6924203945Sweongyo	*tsf <<= 32;
6925203945Sweongyo	*tsf |= low;
6926203945Sweongyo}
6927203945Sweongyo
6928203945Sweongyostatic int
6929203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
6930203945Sweongyo{
6931203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
6932203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6933203945Sweongyo	bus_addr_t lowaddr = 0;
6934203945Sweongyo	int error;
6935203945Sweongyo
6936204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
6937203945Sweongyo		return (0);
6938203945Sweongyo
6939204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
6940203945Sweongyo
6941203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
6942203945Sweongyo
6943203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
6944203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
6945203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
6946203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
6947203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
6948203945Sweongyo	else
6949203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
6950203945Sweongyo
6951203945Sweongyo	/*
6952203945Sweongyo	 * Create top level DMA tag
6953203945Sweongyo	 */
6954203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
6955203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
6956203945Sweongyo			       lowaddr,			/* lowaddr */
6957203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
6958203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
6959280347Smav			       BUS_SPACE_MAXSIZE,	/* maxsize */
6960203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
6961203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
6962203945Sweongyo			       0,			/* flags */
6963203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
6964203945Sweongyo			       &dma->parent_dtag);
6965203945Sweongyo	if (error) {
6966203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
6967203945Sweongyo		return (error);
6968203945Sweongyo	}
6969203945Sweongyo
6970203945Sweongyo	/*
6971203945Sweongyo	 * Create TX/RX mbuf DMA tag
6972203945Sweongyo	 */
6973203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
6974203945Sweongyo				1,
6975203945Sweongyo				0,
6976203945Sweongyo				BUS_SPACE_MAXADDR,
6977203945Sweongyo				BUS_SPACE_MAXADDR,
6978203945Sweongyo				NULL, NULL,
6979203945Sweongyo				MCLBYTES,
6980203945Sweongyo				1,
6981203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
6982203945Sweongyo				0,
6983203945Sweongyo				NULL, NULL,
6984203945Sweongyo				&dma->rxbuf_dtag);
6985203945Sweongyo	if (error) {
6986203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
6987203945Sweongyo		goto fail0;
6988203945Sweongyo	}
6989203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
6990203945Sweongyo				1,
6991203945Sweongyo				0,
6992203945Sweongyo				BUS_SPACE_MAXADDR,
6993203945Sweongyo				BUS_SPACE_MAXADDR,
6994203945Sweongyo				NULL, NULL,
6995203945Sweongyo				MCLBYTES,
6996203945Sweongyo				1,
6997203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
6998203945Sweongyo				0,
6999203945Sweongyo				NULL, NULL,
7000203945Sweongyo				&dma->txbuf_dtag);
7001203945Sweongyo	if (error) {
7002203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
7003203945Sweongyo		goto fail1;
7004203945Sweongyo	}
7005203945Sweongyo
7006203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
7007203945Sweongyo	if (!dma->wme[WME_AC_BK])
7008203945Sweongyo		goto fail2;
7009203945Sweongyo
7010203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
7011203945Sweongyo	if (!dma->wme[WME_AC_BE])
7012203945Sweongyo		goto fail3;
7013203945Sweongyo
7014203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
7015203945Sweongyo	if (!dma->wme[WME_AC_VI])
7016203945Sweongyo		goto fail4;
7017203945Sweongyo
7018203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
7019203945Sweongyo	if (!dma->wme[WME_AC_VO])
7020203945Sweongyo		goto fail5;
7021203945Sweongyo
7022203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
7023203945Sweongyo	if (!dma->mcast)
7024203945Sweongyo		goto fail6;
7025203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
7026203945Sweongyo	if (!dma->rx)
7027203945Sweongyo		goto fail7;
7028203945Sweongyo
7029203945Sweongyo	return (error);
7030203945Sweongyo
7031203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
7032203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
7033203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
7034203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
7035203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
7036203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
7037203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
7038203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
7039203945Sweongyo	return (error);
7040203945Sweongyo}
7041203945Sweongyo
7042203945Sweongyostatic struct bwn_dma_ring *
7043203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
7044203945Sweongyo    uint16_t cookie, int *slot)
7045203945Sweongyo{
7046203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
7047203945Sweongyo	struct bwn_dma_ring *dr;
7048203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7049203945Sweongyo
7050203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
7051203945Sweongyo
7052203945Sweongyo	switch (cookie & 0xf000) {
7053203945Sweongyo	case 0x1000:
7054203945Sweongyo		dr = dma->wme[WME_AC_BK];
7055203945Sweongyo		break;
7056203945Sweongyo	case 0x2000:
7057203945Sweongyo		dr = dma->wme[WME_AC_BE];
7058203945Sweongyo		break;
7059203945Sweongyo	case 0x3000:
7060203945Sweongyo		dr = dma->wme[WME_AC_VI];
7061203945Sweongyo		break;
7062203945Sweongyo	case 0x4000:
7063203945Sweongyo		dr = dma->wme[WME_AC_VO];
7064203945Sweongyo		break;
7065203945Sweongyo	case 0x5000:
7066203945Sweongyo		dr = dma->mcast;
7067203945Sweongyo		break;
7068203945Sweongyo	default:
7069204242Simp		dr = NULL;
7070203945Sweongyo		KASSERT(0 == 1,
7071203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
7072203945Sweongyo	}
7073203945Sweongyo	*slot = (cookie & 0x0fff);
7074203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
7075203945Sweongyo		/*
7076203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
7077203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
7078203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
7079203945Sweongyo		 */
7080203945Sweongyo		KASSERT(status->seq == dma->lastseq,
7081203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
7082203945Sweongyo		device_printf(sc->sc_dev,
7083203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
7084203945Sweongyo		    dr->dr_numslots);
7085203945Sweongyo		return (NULL);
7086203945Sweongyo	}
7087203945Sweongyo	dma->lastseq = status->seq;
7088203945Sweongyo	return (dr);
7089203945Sweongyo}
7090203945Sweongyo
7091203945Sweongyostatic void
7092203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
7093203945Sweongyo{
7094203945Sweongyo	struct bwn_dma *dma;
7095203945Sweongyo
7096203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
7097203945Sweongyo		return;
7098203945Sweongyo	dma = &mac->mac_method.dma;
7099203945Sweongyo
7100203945Sweongyo	bwn_dma_ringstop(&dma->rx);
7101203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
7102203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
7103203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
7104203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
7105203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
7106203945Sweongyo}
7107203945Sweongyo
7108203945Sweongyostatic void
7109203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
7110203945Sweongyo{
7111203945Sweongyo
7112203945Sweongyo	if (dr == NULL)
7113203945Sweongyo		return;
7114203945Sweongyo
7115203945Sweongyo	bwn_dma_cleanup(*dr);
7116203945Sweongyo}
7117203945Sweongyo
7118203945Sweongyostatic void
7119203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
7120203945Sweongyo{
7121203945Sweongyo	struct bwn_pio *pio;
7122203945Sweongyo
7123203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
7124203945Sweongyo		return;
7125203945Sweongyo	pio = &mac->mac_method.pio;
7126203945Sweongyo
7127203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
7128203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
7129203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
7130203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
7131203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
7132203945Sweongyo}
7133203945Sweongyo
7134203945Sweongyostatic void
7135203945Sweongyobwn_led_attach(struct bwn_mac *mac)
7136203945Sweongyo{
7137203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7138203945Sweongyo	const uint8_t *led_act = NULL;
7139203945Sweongyo	uint16_t val[BWN_LED_MAX];
7140203945Sweongyo	int i;
7141203945Sweongyo
7142203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
7143203945Sweongyo	sc->sc_led_blink = 1;
7144203945Sweongyo
7145203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
7146204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
7147204922Sweongyo		    bwn_vendor_led_act[i].vid) {
7148203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
7149203945Sweongyo			break;
7150203945Sweongyo		}
7151203945Sweongyo	}
7152203945Sweongyo	if (led_act == NULL)
7153203945Sweongyo		led_act = bwn_default_led_act;
7154203945Sweongyo
7155204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
7156204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
7157204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
7158204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
7159203945Sweongyo
7160203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
7161203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
7162203945Sweongyo
7163203945Sweongyo		if (val[i] == 0xff) {
7164203945Sweongyo			led->led_act = led_act[i];
7165203945Sweongyo		} else {
7166203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
7167203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
7168203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
7169203945Sweongyo		}
7170203945Sweongyo		led->led_mask = (1 << i);
7171203945Sweongyo
7172203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
7173203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
7174203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
7175203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
7176203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
7177203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
7178203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
7179203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
7180203945Sweongyo
7181203945Sweongyo			if (sc->sc_blink_led == NULL) {
7182203945Sweongyo				sc->sc_blink_led = led;
7183203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
7184203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
7185203945Sweongyo			}
7186203945Sweongyo		}
7187203945Sweongyo
7188203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
7189203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
7190203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
7191203945Sweongyo	}
7192203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
7193203945Sweongyo}
7194203945Sweongyo
7195203945Sweongyostatic __inline uint16_t
7196203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
7197203945Sweongyo{
7198203945Sweongyo
7199203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
7200203945Sweongyo		on = !on;
7201203945Sweongyo	if (on)
7202203945Sweongyo		val |= led->led_mask;
7203203945Sweongyo	else
7204203945Sweongyo		val &= ~led->led_mask;
7205203945Sweongyo	return val;
7206203945Sweongyo}
7207203945Sweongyo
7208203945Sweongyostatic void
7209203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
7210203945Sweongyo{
7211203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7212287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
7213203945Sweongyo	uint16_t val;
7214203945Sweongyo	int i;
7215203945Sweongyo
7216203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
7217203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
7218203945Sweongyo		sc->sc_led_blinking = 0;
7219203945Sweongyo	}
7220203945Sweongyo
7221287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0)
7222203945Sweongyo		return;
7223203945Sweongyo
7224203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
7225203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
7226203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
7227203945Sweongyo		int on;
7228203945Sweongyo
7229203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
7230203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
7231203945Sweongyo			continue;
7232203945Sweongyo
7233203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
7234203945Sweongyo		    nstate != IEEE80211_S_INIT)
7235203945Sweongyo			continue;
7236203945Sweongyo
7237203945Sweongyo		switch (led->led_act) {
7238203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
7239203945Sweongyo			on = 1;
7240203945Sweongyo			break;
7241203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
7242203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
7243203945Sweongyo			on = 0;
7244203945Sweongyo			break;
7245203945Sweongyo		default:
7246203945Sweongyo			on = 1;
7247203945Sweongyo			switch (nstate) {
7248203945Sweongyo			case IEEE80211_S_INIT:
7249203945Sweongyo				on = 0;
7250203945Sweongyo				break;
7251203945Sweongyo			case IEEE80211_S_RUN:
7252203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
7253203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
7254203945Sweongyo					on = 0;
7255203945Sweongyo				break;
7256203945Sweongyo			default:
7257203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
7258203945Sweongyo					on = 0;
7259203945Sweongyo				break;
7260203945Sweongyo			}
7261203945Sweongyo			break;
7262203945Sweongyo		}
7263203945Sweongyo
7264203945Sweongyo		val = bwn_led_onoff(led, val, on);
7265203945Sweongyo	}
7266203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
7267203945Sweongyo}
7268203945Sweongyo
7269203945Sweongyostatic void
7270203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
7271203945Sweongyo{
7272203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7273204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
7274204922Sweongyo	int rate;
7275203945Sweongyo
7276204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
7277204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
7278204922Sweongyo			return;
7279204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
7280204922Sweongyo			return;
7281204922Sweongyo	}
7282203945Sweongyo
7283204922Sweongyo	sc->sc_led_ticks = ticks;
7284204922Sweongyo	if (sc->sc_led_blinking)
7285204922Sweongyo		return;
7286203945Sweongyo
7287204922Sweongyo	switch (event) {
7288204922Sweongyo	case BWN_LED_EVENT_RX:
7289204922Sweongyo		rate = sc->sc_rx_rate;
7290204922Sweongyo		break;
7291204922Sweongyo	case BWN_LED_EVENT_TX:
7292204922Sweongyo		rate = sc->sc_tx_rate;
7293204922Sweongyo		break;
7294204922Sweongyo	case BWN_LED_EVENT_POLL:
7295204922Sweongyo		rate = 0;
7296204922Sweongyo		break;
7297204922Sweongyo	default:
7298204922Sweongyo		panic("unknown LED event %d\n", event);
7299204922Sweongyo		break;
7300204922Sweongyo	}
7301204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
7302204922Sweongyo	    bwn_led_duration[rate].off_dur);
7303203945Sweongyo}
7304203945Sweongyo
7305203945Sweongyostatic void
7306203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
7307203945Sweongyo{
7308203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7309204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
7310204922Sweongyo	uint16_t val;
7311203945Sweongyo
7312204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
7313204922Sweongyo	val = bwn_led_onoff(led, val, 1);
7314204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
7315203945Sweongyo
7316204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
7317204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
7318204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
7319204922Sweongyo	}
7320203945Sweongyo
7321204922Sweongyo	sc->sc_led_blinking = 1;
7322204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
7323203945Sweongyo
7324204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
7325203945Sweongyo}
7326203945Sweongyo
7327203945Sweongyostatic void
7328203945Sweongyobwn_led_blink_next(void *arg)
7329203945Sweongyo{
7330203945Sweongyo	struct bwn_mac *mac = arg;
7331204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7332204922Sweongyo	uint16_t val;
7333203945Sweongyo
7334204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
7335204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
7336204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
7337203945Sweongyo
7338204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
7339204922Sweongyo	    bwn_led_blink_end, mac);
7340203945Sweongyo}
7341203945Sweongyo
7342203945Sweongyostatic void
7343203945Sweongyobwn_led_blink_end(void *arg)
7344203945Sweongyo{
7345203945Sweongyo	struct bwn_mac *mac = arg;
7346204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7347203945Sweongyo
7348204922Sweongyo	sc->sc_led_blinking = 0;
7349203945Sweongyo}
7350203945Sweongyo
7351203945Sweongyostatic int
7352203945Sweongyobwn_suspend(device_t dev)
7353203945Sweongyo{
7354203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
7355203945Sweongyo
7356287197Sglebius	BWN_LOCK(sc);
7357287197Sglebius	bwn_stop(sc);
7358287197Sglebius	BWN_UNLOCK(sc);
7359203945Sweongyo	return (0);
7360203945Sweongyo}
7361203945Sweongyo
7362203945Sweongyostatic int
7363203945Sweongyobwn_resume(device_t dev)
7364203945Sweongyo{
7365203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
7366287197Sglebius	int error = EDOOFUS;
7367203945Sweongyo
7368287197Sglebius	BWN_LOCK(sc);
7369287197Sglebius	if (sc->sc_ic.ic_nrunning > 0)
7370287197Sglebius		error = bwn_init(sc);
7371287197Sglebius	BWN_UNLOCK(sc);
7372287197Sglebius	if (error == 0)
7373287197Sglebius		ieee80211_start_all(&sc->sc_ic);
7374203945Sweongyo	return (0);
7375203945Sweongyo}
7376203945Sweongyo
7377203945Sweongyostatic void
7378203945Sweongyobwn_rfswitch(void *arg)
7379203945Sweongyo{
7380203945Sweongyo	struct bwn_softc *sc = arg;
7381203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
7382203945Sweongyo	int cur = 0, prev = 0;
7383203945Sweongyo
7384203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
7385203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
7386203945Sweongyo
7387299796Sadrian	if (mac->mac_phy.rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP
7388299796Sadrian	    || mac->mac_phy.type == BWN_PHYTYPE_N) {
7389203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
7390203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
7391203945Sweongyo			cur = 1;
7392203945Sweongyo	} else {
7393203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
7394203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
7395203945Sweongyo			cur = 1;
7396203945Sweongyo	}
7397203945Sweongyo
7398203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
7399203945Sweongyo		prev = 1;
7400203945Sweongyo
7401299796Sadrian	DPRINTF(sc, BWN_DEBUG_RESET, "%s: called; cur=%d, prev=%d\n",
7402299796Sadrian	    __func__, cur, prev);
7403299796Sadrian
7404203945Sweongyo	if (cur != prev) {
7405203945Sweongyo		if (cur)
7406203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
7407203945Sweongyo		else
7408203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
7409203945Sweongyo
7410203945Sweongyo		device_printf(sc->sc_dev,
7411203945Sweongyo		    "status of RF switch is changed to %s\n",
7412203945Sweongyo		    cur ? "ON" : "OFF");
7413203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
7414203945Sweongyo			if (cur)
7415203945Sweongyo				bwn_rf_turnon(mac);
7416203945Sweongyo			else
7417203945Sweongyo				bwn_rf_turnoff(mac);
7418203945Sweongyo		}
7419203945Sweongyo	}
7420203945Sweongyo
7421203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
7422203945Sweongyo}
7423203945Sweongyo
7424203945Sweongyostatic void
7425204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
7426204257Sweongyo{
7427204257Sweongyo	device_t dev = sc->sc_dev;
7428204257Sweongyo	struct bwn_mac *mac;
7429204257Sweongyo	struct bwn_stats *stats;
7430204257Sweongyo
7431204257Sweongyo	/* XXX assume that count of MAC is only 1. */
7432204257Sweongyo
7433204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
7434204257Sweongyo		return;
7435204257Sweongyo	stats = &mac->mac_stats;
7436204257Sweongyo
7437217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
7438204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7439204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
7440217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
7441204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7442204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
7443217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
7444204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7445204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
7446204257Sweongyo
7447204257Sweongyo#ifdef BWN_DEBUG
7448204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
7449204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
7450204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
7451204257Sweongyo#endif
7452204257Sweongyo}
7453204257Sweongyo
7454203945Sweongyostatic device_method_t bwn_methods[] = {
7455203945Sweongyo	/* Device interface */
7456203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
7457203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
7458203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
7459203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
7460203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
7461227848Smarius	DEVMETHOD_END
7462203945Sweongyo};
7463203945Sweongyostatic driver_t bwn_driver = {
7464203945Sweongyo	"bwn",
7465203945Sweongyo	bwn_methods,
7466203945Sweongyo	sizeof(struct bwn_softc)
7467203945Sweongyo};
7468203945Sweongyostatic devclass_t bwn_devclass;
7469203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
7470203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
7471203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
7472203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
7473203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
7474299097SadrianMODULE_VERSION(bwn, 1);
7475