1178676Ssam/*-
2258833Sadrian * Copyright (c) 2007-2009 Damien Bergamini <damien.bergamini@free.fr>
3258833Sadrian * Copyright (c) 2008 Benjamin Close <benjsc@FreeBSD.org>
4258833Sadrian * Copyright (c) 2008 Sam Leffler, Errno Consulting
5258833Sadrian * Copyright (c) 2011 Intel Corporation
6254204Sadrian * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr>
7258833Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
8178676Ssam *
9178676Ssam * Permission to use, copy, modify, and distribute this software for any
10178676Ssam * purpose with or without fee is hereby granted, provided that the above
11178676Ssam * copyright notice and this permission notice appear in all copies.
12178676Ssam *
13178676Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14178676Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15178676Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16178676Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17178676Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18178676Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19178676Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20178676Ssam */
21178676Ssam
22178676Ssam/*
23201209Srpaulo * Driver for Intel WiFi Link 4965 and 1000/5000/6000 Series 802.11 network
24201209Srpaulo * adapters.
25178676Ssam */
26178676Ssam
27178676Ssam#include <sys/cdefs.h>
28178676Ssam__FBSDID("$FreeBSD: stable/11/sys/dev/iwn/if_iwn.c 345636 2019-03-28 09:50:25Z avos $");
29178676Ssam
30243692Sadrian#include "opt_wlan.h"
31253868Sadrian#include "opt_iwn.h"
32243692Sadrian
33178676Ssam#include <sys/param.h>
34178676Ssam#include <sys/sockio.h>
35178676Ssam#include <sys/sysctl.h>
36178676Ssam#include <sys/mbuf.h>
37178676Ssam#include <sys/kernel.h>
38178676Ssam#include <sys/socket.h>
39178676Ssam#include <sys/systm.h>
40178676Ssam#include <sys/malloc.h>
41178676Ssam#include <sys/bus.h>
42287312Sadrian#include <sys/conf.h>
43178676Ssam#include <sys/rman.h>
44178676Ssam#include <sys/endian.h>
45178676Ssam#include <sys/firmware.h>
46178676Ssam#include <sys/limits.h>
47178676Ssam#include <sys/module.h>
48287312Sadrian#include <sys/priv.h>
49178676Ssam#include <sys/queue.h>
50178676Ssam#include <sys/taskqueue.h>
51178676Ssam
52178676Ssam#include <machine/bus.h>
53178676Ssam#include <machine/resource.h>
54178676Ssam#include <machine/clock.h>
55178676Ssam
56178676Ssam#include <dev/pci/pcireg.h>
57178676Ssam#include <dev/pci/pcivar.h>
58178676Ssam
59178676Ssam#include <net/if.h>
60257176Sglebius#include <net/if_var.h>
61178676Ssam#include <net/if_dl.h>
62178676Ssam#include <net/if_media.h>
63178676Ssam
64178676Ssam#include <netinet/in.h>
65178676Ssam#include <netinet/if_ether.h>
66178676Ssam
67178676Ssam#include <net80211/ieee80211_var.h>
68178676Ssam#include <net80211/ieee80211_radiotap.h>
69178676Ssam#include <net80211/ieee80211_regdomain.h>
70206358Srpaulo#include <net80211/ieee80211_ratectl.h>
71178676Ssam
72178676Ssam#include <dev/iwn/if_iwnreg.h>
73178676Ssam#include <dev/iwn/if_iwnvar.h>
74253897Sadrian#include <dev/iwn/if_iwn_devid.h>
75258035Sadrian#include <dev/iwn/if_iwn_chip_cfg.h>
76257035Sadrian#include <dev/iwn/if_iwn_debug.h>
77262422Sadrian#include <dev/iwn/if_iwn_ioctl.h>
78178676Ssam
79220723Sbschmidtstruct iwn_ident {
80220723Sbschmidt	uint16_t	vendor;
81220723Sbschmidt	uint16_t	device;
82220723Sbschmidt	const char	*name;
83220723Sbschmidt};
84220723Sbschmidt
85220895Sbschmidtstatic const struct iwn_ident iwn_ident_table[] = {
86253897Sadrian	{ 0x8086, IWN_DID_6x05_1, "Intel Centrino Advanced-N 6205"		},
87253897Sadrian	{ 0x8086, IWN_DID_1000_1, "Intel Centrino Wireless-N 1000"		},
88253897Sadrian	{ 0x8086, IWN_DID_1000_2, "Intel Centrino Wireless-N 1000"		},
89253897Sadrian	{ 0x8086, IWN_DID_6x05_2, "Intel Centrino Advanced-N 6205"		},
90253897Sadrian	{ 0x8086, IWN_DID_6050_1, "Intel Centrino Advanced-N + WiMAX 6250"	},
91253897Sadrian	{ 0x8086, IWN_DID_6050_2, "Intel Centrino Advanced-N + WiMAX 6250"	},
92253897Sadrian	{ 0x8086, IWN_DID_x030_1, "Intel Centrino Wireless-N 1030"		},
93253897Sadrian	{ 0x8086, IWN_DID_x030_2, "Intel Centrino Wireless-N 1030"		},
94253897Sadrian	{ 0x8086, IWN_DID_x030_3, "Intel Centrino Advanced-N 6230"		},
95253897Sadrian	{ 0x8086, IWN_DID_x030_4, "Intel Centrino Advanced-N 6230"		},
96253897Sadrian	{ 0x8086, IWN_DID_6150_1, "Intel Centrino Wireless-N + WiMAX 6150"	},
97253897Sadrian	{ 0x8086, IWN_DID_6150_2, "Intel Centrino Wireless-N + WiMAX 6150"	},
98258035Sadrian	{ 0x8086, IWN_DID_2x00_1, "Intel(R) Centrino(R) Wireless-N 2200 BGN"	},
99258035Sadrian	{ 0x8086, IWN_DID_2x00_2, "Intel(R) Centrino(R) Wireless-N 2200 BGN"	},
100258035Sadrian	/* XXX 2200D is IWN_SDID_2x00_4; there's no way to express this here! */
101253897Sadrian	{ 0x8086, IWN_DID_2x30_1, "Intel Centrino Wireless-N 2230"		},
102253897Sadrian	{ 0x8086, IWN_DID_2x30_2, "Intel Centrino Wireless-N 2230"		},
103253897Sadrian	{ 0x8086, IWN_DID_130_1, "Intel Centrino Wireless-N 130"		},
104253897Sadrian	{ 0x8086, IWN_DID_130_2, "Intel Centrino Wireless-N 130"		},
105253897Sadrian	{ 0x8086, IWN_DID_100_1, "Intel Centrino Wireless-N 100"		},
106253897Sadrian	{ 0x8086, IWN_DID_100_2, "Intel Centrino Wireless-N 100"		},
107266770Sgavin	{ 0x8086, IWN_DID_105_1, "Intel Centrino Wireless-N 105"		},
108266770Sgavin	{ 0x8086, IWN_DID_105_2, "Intel Centrino Wireless-N 105"		},
109260448Sgavin	{ 0x8086, IWN_DID_135_1, "Intel Centrino Wireless-N 135"		},
110260448Sgavin	{ 0x8086, IWN_DID_135_2, "Intel Centrino Wireless-N 135"		},
111253897Sadrian	{ 0x8086, IWN_DID_4965_1, "Intel Wireless WiFi Link 4965"		},
112253897Sadrian	{ 0x8086, IWN_DID_6x00_1, "Intel Centrino Ultimate-N 6300"		},
113253897Sadrian	{ 0x8086, IWN_DID_6x00_2, "Intel Centrino Advanced-N 6200"		},
114253897Sadrian	{ 0x8086, IWN_DID_4965_2, "Intel Wireless WiFi Link 4965"		},
115253897Sadrian	{ 0x8086, IWN_DID_4965_3, "Intel Wireless WiFi Link 4965"		},
116253897Sadrian	{ 0x8086, IWN_DID_5x00_1, "Intel WiFi Link 5100"			},
117253897Sadrian	{ 0x8086, IWN_DID_4965_4, "Intel Wireless WiFi Link 4965"		},
118253897Sadrian	{ 0x8086, IWN_DID_5x00_3, "Intel Ultimate N WiFi Link 5300"		},
119253897Sadrian	{ 0x8086, IWN_DID_5x00_4, "Intel Ultimate N WiFi Link 5300"		},
120253897Sadrian	{ 0x8086, IWN_DID_5x00_2, "Intel WiFi Link 5100"			},
121253897Sadrian	{ 0x8086, IWN_DID_6x00_3, "Intel Centrino Ultimate-N 6300"		},
122253897Sadrian	{ 0x8086, IWN_DID_6x00_4, "Intel Centrino Advanced-N 6200"		},
123253897Sadrian	{ 0x8086, IWN_DID_5x50_1, "Intel WiMAX/WiFi Link 5350"			},
124253897Sadrian	{ 0x8086, IWN_DID_5x50_2, "Intel WiMAX/WiFi Link 5350"			},
125253897Sadrian	{ 0x8086, IWN_DID_5x50_3, "Intel WiMAX/WiFi Link 5150"			},
126253897Sadrian	{ 0x8086, IWN_DID_5x50_4, "Intel WiMAX/WiFi Link 5150"			},
127258035Sadrian	{ 0x8086, IWN_DID_6035_1, "Intel Centrino Advanced 6235"		},
128258035Sadrian	{ 0x8086, IWN_DID_6035_2, "Intel Centrino Advanced 6235"		},
129220723Sbschmidt	{ 0, 0, NULL }
130220723Sbschmidt};
131220723Sbschmidt
132178676Ssamstatic int	iwn_probe(device_t);
133178676Ssamstatic int	iwn_attach(device_t);
134343507Savosstatic void	iwn4965_attach(struct iwn_softc *, uint16_t);
135343507Savosstatic void	iwn5000_attach(struct iwn_softc *, uint16_t);
136258035Sadrianstatic int	iwn_config_specific(struct iwn_softc *, uint16_t);
137206477Sbschmidtstatic void	iwn_radiotap_attach(struct iwn_softc *);
138220723Sbschmidtstatic void	iwn_sysctlattach(struct iwn_softc *);
139178676Ssamstatic struct ieee80211vap *iwn_vap_create(struct ieee80211com *,
140228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
141228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
142228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
143178676Ssamstatic void	iwn_vap_delete(struct ieee80211vap *);
144206474Sbschmidtstatic int	iwn_detach(device_t);
145220723Sbschmidtstatic int	iwn_shutdown(device_t);
146220723Sbschmidtstatic int	iwn_suspend(device_t);
147220723Sbschmidtstatic int	iwn_resume(device_t);
148206477Sbschmidtstatic int	iwn_nic_lock(struct iwn_softc *);
149206477Sbschmidtstatic int	iwn_eeprom_lock(struct iwn_softc *);
150206477Sbschmidtstatic int	iwn_init_otprom(struct iwn_softc *);
151206477Sbschmidtstatic int	iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int);
152206474Sbschmidtstatic void	iwn_dma_map_addr(void *, bus_dma_segment_t *, int, int);
153178676Ssamstatic int	iwn_dma_contig_alloc(struct iwn_softc *, struct iwn_dma_info *,
154220691Sbschmidt		    void **, bus_size_t, bus_size_t);
155178676Ssamstatic void	iwn_dma_contig_free(struct iwn_dma_info *);
156206477Sbschmidtstatic int	iwn_alloc_sched(struct iwn_softc *);
157206477Sbschmidtstatic void	iwn_free_sched(struct iwn_softc *);
158206477Sbschmidtstatic int	iwn_alloc_kw(struct iwn_softc *);
159206477Sbschmidtstatic void	iwn_free_kw(struct iwn_softc *);
160206477Sbschmidtstatic int	iwn_alloc_ict(struct iwn_softc *);
161206477Sbschmidtstatic void	iwn_free_ict(struct iwn_softc *);
162206477Sbschmidtstatic int	iwn_alloc_fwmem(struct iwn_softc *);
163206477Sbschmidtstatic void	iwn_free_fwmem(struct iwn_softc *);
164206477Sbschmidtstatic int	iwn_alloc_rx_ring(struct iwn_softc *, struct iwn_rx_ring *);
165206477Sbschmidtstatic void	iwn_reset_rx_ring(struct iwn_softc *, struct iwn_rx_ring *);
166206477Sbschmidtstatic void	iwn_free_rx_ring(struct iwn_softc *, struct iwn_rx_ring *);
167206477Sbschmidtstatic int	iwn_alloc_tx_ring(struct iwn_softc *, struct iwn_tx_ring *,
168178676Ssam		    int);
169206477Sbschmidtstatic void	iwn_reset_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
170206477Sbschmidtstatic void	iwn_free_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
171206477Sbschmidtstatic void	iwn5000_ict_reset(struct iwn_softc *);
172206477Sbschmidtstatic int	iwn_read_eeprom(struct iwn_softc *,
173198429Srpaulo		    uint8_t macaddr[IEEE80211_ADDR_LEN]);
174206477Sbschmidtstatic void	iwn4965_read_eeprom(struct iwn_softc *);
175253866Sadrian#ifdef	IWN_DEBUG
176206477Sbschmidtstatic void	iwn4965_print_power_group(struct iwn_softc *, int);
177253866Sadrian#endif
178206477Sbschmidtstatic void	iwn5000_read_eeprom(struct iwn_softc *);
179206474Sbschmidtstatic uint32_t	iwn_eeprom_channel_flags(struct iwn_eeprom_chan *);
180293716Savosstatic void	iwn_read_eeprom_band(struct iwn_softc *, int, int, int *,
181293716Savos		    struct ieee80211_channel[]);
182293716Savosstatic void	iwn_read_eeprom_ht40(struct iwn_softc *, int, int, int *,
183293716Savos		    struct ieee80211_channel[]);
184220726Sbschmidtstatic void	iwn_read_eeprom_channels(struct iwn_softc *, int, uint32_t);
185220723Sbschmidtstatic struct iwn_eeprom_chan *iwn_find_eeprom_channel(struct iwn_softc *,
186220723Sbschmidt		    struct ieee80211_channel *);
187293716Savosstatic void	iwn_getradiocaps(struct ieee80211com *, int, int *,
188293716Savos		    struct ieee80211_channel[]);
189220723Sbschmidtstatic int	iwn_setregdomain(struct ieee80211com *,
190220723Sbschmidt		    struct ieee80211_regdomain *, int,
191220726Sbschmidt		    struct ieee80211_channel[]);
192206477Sbschmidtstatic void	iwn_read_eeprom_enhinfo(struct iwn_softc *);
193206477Sbschmidtstatic struct ieee80211_node *iwn_node_alloc(struct ieee80211vap *,
194198429Srpaulo		    const uint8_t mac[IEEE80211_ADDR_LEN]);
195220715Sbschmidtstatic void	iwn_newassoc(struct ieee80211_node *, int);
196206477Sbschmidtstatic int	iwn_media_change(struct ifnet *);
197206477Sbschmidtstatic int	iwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
198220667Sbschmidtstatic void	iwn_calib_timeout(void *);
199206477Sbschmidtstatic void	iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
200198429Srpaulo		    struct iwn_rx_data *);
201206477Sbschmidtstatic void	iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
202178676Ssam		    struct iwn_rx_data *);
203206477Sbschmidtstatic void	iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
204201209Srpaulo		    struct iwn_rx_data *);
205220674Sbschmidtstatic void	iwn5000_rx_calib_results(struct iwn_softc *,
206220674Sbschmidt		    struct iwn_rx_desc *, struct iwn_rx_data *);
207206477Sbschmidtstatic void	iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *,
208198429Srpaulo		    struct iwn_rx_data *);
209206477Sbschmidtstatic void	iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
210198429Srpaulo		    struct iwn_rx_data *);
211206477Sbschmidtstatic void	iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
212198429Srpaulo		    struct iwn_rx_data *);
213206477Sbschmidtstatic void	iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int,
214198429Srpaulo		    uint8_t);
215270742Sadrianstatic void	iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, void *);
216206477Sbschmidtstatic void	iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
217206477Sbschmidtstatic void	iwn_notif_intr(struct iwn_softc *);
218206477Sbschmidtstatic void	iwn_wakeup_intr(struct iwn_softc *);
219206477Sbschmidtstatic void	iwn_rftoggle_intr(struct iwn_softc *);
220206477Sbschmidtstatic void	iwn_fatal_intr(struct iwn_softc *);
221206477Sbschmidtstatic void	iwn_intr(void *);
222206477Sbschmidtstatic void	iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t,
223198429Srpaulo		    uint16_t);
224206477Sbschmidtstatic void	iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t,
225198429Srpaulo		    uint16_t);
226206475Sbschmidt#ifdef notyet
227206477Sbschmidtstatic void	iwn5000_reset_sched(struct iwn_softc *, int, int);
228206475Sbschmidt#endif
229206477Sbschmidtstatic int	iwn_tx_data(struct iwn_softc *, struct mbuf *,
230220720Sbschmidt		    struct ieee80211_node *);
231220720Sbschmidtstatic int	iwn_tx_data_raw(struct iwn_softc *, struct mbuf *,
232220720Sbschmidt		    struct ieee80211_node *,
233220720Sbschmidt		    const struct ieee80211_bpf_params *params);
234284588Sadrianstatic void	iwn_xmit_task(void *arg0, int pending);
235198429Srpaulostatic int	iwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
236198429Srpaulo		    const struct ieee80211_bpf_params *);
237287197Sglebiusstatic int	iwn_transmit(struct ieee80211com *, struct mbuf *);
238300732Savosstatic void	iwn_scan_timeout(void *);
239220667Sbschmidtstatic void	iwn_watchdog(void *);
240287197Sglebiusstatic int	iwn_ioctl(struct ieee80211com *, u_long , void *);
241287197Sglebiusstatic void	iwn_parent(struct ieee80211com *);
242206477Sbschmidtstatic int	iwn_cmd(struct iwn_softc *, int, const void *, int, int);
243206477Sbschmidtstatic int	iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *,
244198429Srpaulo		    int);
245206477Sbschmidtstatic int	iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *,
246198429Srpaulo		    int);
247220715Sbschmidtstatic int	iwn_set_link_quality(struct iwn_softc *,
248220715Sbschmidt		    struct ieee80211_node *);
249206477Sbschmidtstatic int	iwn_add_broadcast_node(struct iwn_softc *, int);
250220721Sbschmidtstatic int	iwn_updateedca(struct ieee80211com *);
251283540Sglebiusstatic void	iwn_update_mcast(struct ieee80211com *);
252206477Sbschmidtstatic void	iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
253206477Sbschmidtstatic int	iwn_set_critical_temp(struct iwn_softc *);
254206477Sbschmidtstatic int	iwn_set_timing(struct iwn_softc *, struct ieee80211_node *);
255206477Sbschmidtstatic void	iwn4965_power_calibration(struct iwn_softc *, int);
256206477Sbschmidtstatic int	iwn4965_set_txpower(struct iwn_softc *,
257201882Skeramida		    struct ieee80211_channel *, int);
258206477Sbschmidtstatic int	iwn5000_set_txpower(struct iwn_softc *,
259201882Skeramida		    struct ieee80211_channel *, int);
260206477Sbschmidtstatic int	iwn4965_get_rssi(struct iwn_softc *, struct iwn_rx_stat *);
261206477Sbschmidtstatic int	iwn5000_get_rssi(struct iwn_softc *, struct iwn_rx_stat *);
262206477Sbschmidtstatic int	iwn_get_noise(const struct iwn_rx_general_stats *);
263206477Sbschmidtstatic int	iwn4965_get_temperature(struct iwn_softc *);
264206477Sbschmidtstatic int	iwn5000_get_temperature(struct iwn_softc *);
265206477Sbschmidtstatic int	iwn_init_sensitivity(struct iwn_softc *);
266206477Sbschmidtstatic void	iwn_collect_noise(struct iwn_softc *,
267178676Ssam		    const struct iwn_rx_general_stats *);
268206477Sbschmidtstatic int	iwn4965_init_gains(struct iwn_softc *);
269206477Sbschmidtstatic int	iwn5000_init_gains(struct iwn_softc *);
270206477Sbschmidtstatic int	iwn4965_set_gains(struct iwn_softc *);
271206477Sbschmidtstatic int	iwn5000_set_gains(struct iwn_softc *);
272206477Sbschmidtstatic void	iwn_tune_sensitivity(struct iwn_softc *,
273178676Ssam		    const struct iwn_rx_stats *);
274259061Sadrianstatic void	iwn_save_stats_counters(struct iwn_softc *,
275259061Sadrian		    const struct iwn_stats *);
276206477Sbschmidtstatic int	iwn_send_sensitivity(struct iwn_softc *);
277259061Sadrianstatic void	iwn_check_rx_recovery(struct iwn_softc *, struct iwn_stats *);
278206477Sbschmidtstatic int	iwn_set_pslevel(struct iwn_softc *, int, int, int);
279220662Sbschmidtstatic int	iwn_send_btcoex(struct iwn_softc *);
280220891Sbschmidtstatic int	iwn_send_advanced_btcoex(struct iwn_softc *);
281227805Sbschmidtstatic int	iwn5000_runtime_calib(struct iwn_softc *);
282206477Sbschmidtstatic int	iwn_config(struct iwn_softc *);
283259064Sadrianstatic int	iwn_scan(struct iwn_softc *, struct ieee80211vap *,
284259064Sadrian		    struct ieee80211_scan_state *, struct ieee80211_channel *);
285206477Sbschmidtstatic int	iwn_auth(struct iwn_softc *, struct ieee80211vap *vap);
286206477Sbschmidtstatic int	iwn_run(struct iwn_softc *, struct ieee80211vap *vap);
287221650Sbschmidtstatic int	iwn_ampdu_rx_start(struct ieee80211_node *,
288221650Sbschmidt		    struct ieee80211_rx_ampdu *, int, int, int);
289221650Sbschmidtstatic void	iwn_ampdu_rx_stop(struct ieee80211_node *,
290221650Sbschmidt		    struct ieee80211_rx_ampdu *);
291221651Sbschmidtstatic int	iwn_addba_request(struct ieee80211_node *,
292221651Sbschmidt		    struct ieee80211_tx_ampdu *, int, int, int);
293221651Sbschmidtstatic int	iwn_addba_response(struct ieee80211_node *,
294221651Sbschmidt		    struct ieee80211_tx_ampdu *, int, int, int);
295206474Sbschmidtstatic int	iwn_ampdu_tx_start(struct ieee80211com *,
296206474Sbschmidt		    struct ieee80211_node *, uint8_t);
297221651Sbschmidtstatic void	iwn_ampdu_tx_stop(struct ieee80211_node *,
298221651Sbschmidt		    struct ieee80211_tx_ampdu *);
299206474Sbschmidtstatic void	iwn4965_ampdu_tx_start(struct iwn_softc *,
300221651Sbschmidt		    struct ieee80211_node *, int, uint8_t, uint16_t);
301221651Sbschmidtstatic void	iwn4965_ampdu_tx_stop(struct iwn_softc *, int,
302220726Sbschmidt		    uint8_t, uint16_t);
303206474Sbschmidtstatic void	iwn5000_ampdu_tx_start(struct iwn_softc *,
304221651Sbschmidt		    struct ieee80211_node *, int, uint8_t, uint16_t);
305221651Sbschmidtstatic void	iwn5000_ampdu_tx_stop(struct iwn_softc *, int,
306220726Sbschmidt		    uint8_t, uint16_t);
307220674Sbschmidtstatic int	iwn5000_query_calibration(struct iwn_softc *);
308220674Sbschmidtstatic int	iwn5000_send_calibration(struct iwn_softc *);
309206477Sbschmidtstatic int	iwn5000_send_wimax_coex(struct iwn_softc *);
310220677Sbschmidtstatic int	iwn5000_crystal_calib(struct iwn_softc *);
311220676Sbschmidtstatic int	iwn5000_temp_offset_calib(struct iwn_softc *);
312258035Sadrianstatic int	iwn5000_temp_offset_calibv2(struct iwn_softc *);
313206477Sbschmidtstatic int	iwn4965_post_alive(struct iwn_softc *);
314206477Sbschmidtstatic int	iwn5000_post_alive(struct iwn_softc *);
315206477Sbschmidtstatic int	iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *,
316198429Srpaulo		    int);
317206477Sbschmidtstatic int	iwn4965_load_firmware(struct iwn_softc *);
318206477Sbschmidtstatic int	iwn5000_load_firmware_section(struct iwn_softc *, uint32_t,
319198429Srpaulo		    const uint8_t *, int);
320206477Sbschmidtstatic int	iwn5000_load_firmware(struct iwn_softc *);
321210111Sbschmidtstatic int	iwn_read_firmware_leg(struct iwn_softc *,
322210111Sbschmidt		    struct iwn_fw_info *);
323210111Sbschmidtstatic int	iwn_read_firmware_tlv(struct iwn_softc *,
324210111Sbschmidt		    struct iwn_fw_info *, uint16_t);
325206477Sbschmidtstatic int	iwn_read_firmware(struct iwn_softc *);
326293179Savosstatic void	iwn_unload_firmware(struct iwn_softc *);
327206477Sbschmidtstatic int	iwn_clock_wait(struct iwn_softc *);
328206477Sbschmidtstatic int	iwn_apm_init(struct iwn_softc *);
329206477Sbschmidtstatic void	iwn_apm_stop_master(struct iwn_softc *);
330206477Sbschmidtstatic void	iwn_apm_stop(struct iwn_softc *);
331206477Sbschmidtstatic int	iwn4965_nic_config(struct iwn_softc *);
332206477Sbschmidtstatic int	iwn5000_nic_config(struct iwn_softc *);
333206477Sbschmidtstatic int	iwn_hw_prepare(struct iwn_softc *);
334206477Sbschmidtstatic int	iwn_hw_init(struct iwn_softc *);
335206477Sbschmidtstatic void	iwn_hw_stop(struct iwn_softc *);
336220723Sbschmidtstatic void	iwn_radio_on(void *, int);
337220723Sbschmidtstatic void	iwn_radio_off(void *, int);
338266546Straszstatic void	iwn_panicked(void *, int);
339206477Sbschmidtstatic void	iwn_init_locked(struct iwn_softc *);
340287197Sglebiusstatic void	iwn_init(struct iwn_softc *);
341206477Sbschmidtstatic void	iwn_stop_locked(struct iwn_softc *);
342206477Sbschmidtstatic void	iwn_stop(struct iwn_softc *);
343220726Sbschmidtstatic void	iwn_scan_start(struct ieee80211com *);
344220726Sbschmidtstatic void	iwn_scan_end(struct ieee80211com *);
345220726Sbschmidtstatic void	iwn_set_channel(struct ieee80211com *);
346220726Sbschmidtstatic void	iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long);
347220726Sbschmidtstatic void	iwn_scan_mindwell(struct ieee80211_scan_state *);
348253866Sadrian#ifdef	IWN_DEBUG
349253866Sadrianstatic char	*iwn_get_csr_string(int);
350253866Sadrianstatic void	iwn_debug_register(struct iwn_softc *);
351253866Sadrian#endif
352178676Ssam
353220723Sbschmidtstatic device_method_t iwn_methods[] = {
354220723Sbschmidt	/* Device interface */
355220723Sbschmidt	DEVMETHOD(device_probe,		iwn_probe),
356220723Sbschmidt	DEVMETHOD(device_attach,	iwn_attach),
357220723Sbschmidt	DEVMETHOD(device_detach,	iwn_detach),
358220723Sbschmidt	DEVMETHOD(device_shutdown,	iwn_shutdown),
359220723Sbschmidt	DEVMETHOD(device_suspend,	iwn_suspend),
360220723Sbschmidt	DEVMETHOD(device_resume,	iwn_resume),
361260053Smarius
362260053Smarius	DEVMETHOD_END
363178676Ssam};
364178676Ssam
365220723Sbschmidtstatic driver_t iwn_driver = {
366220723Sbschmidt	"iwn",
367220723Sbschmidt	iwn_methods,
368220726Sbschmidt	sizeof(struct iwn_softc)
369178676Ssam};
370220723Sbschmidtstatic devclass_t iwn_devclass;
371178676Ssam
372260053SmariusDRIVER_MODULE(iwn, pci, iwn_driver, iwn_devclass, NULL, NULL);
373220726Sbschmidt
374222543SbschmidtMODULE_VERSION(iwn, 1);
375222543Sbschmidt
376220723SbschmidtMODULE_DEPEND(iwn, firmware, 1, 1, 1);
377220723SbschmidtMODULE_DEPEND(iwn, pci, 1, 1, 1);
378220723SbschmidtMODULE_DEPEND(iwn, wlan, 1, 1, 1);
379220723Sbschmidt
380287312Sadrianstatic d_ioctl_t iwn_cdev_ioctl;
381287312Sadrianstatic d_open_t iwn_cdev_open;
382287312Sadrianstatic d_close_t iwn_cdev_close;
383287312Sadrian
384287312Sadrianstatic struct cdevsw iwn_cdevsw = {
385287312Sadrian	.d_version = D_VERSION,
386287312Sadrian	.d_flags = 0,
387287312Sadrian	.d_open = iwn_cdev_open,
388287312Sadrian	.d_close = iwn_cdev_close,
389287312Sadrian	.d_ioctl = iwn_cdev_ioctl,
390287312Sadrian	.d_name = "iwn",
391287312Sadrian};
392287312Sadrian
393178676Ssamstatic int
394178676Ssamiwn_probe(device_t dev)
395178676Ssam{
396198429Srpaulo	const struct iwn_ident *ident;
397178676Ssam
398198429Srpaulo	for (ident = iwn_ident_table; ident->name != NULL; ident++) {
399198429Srpaulo		if (pci_get_vendor(dev) == ident->vendor &&
400198429Srpaulo		    pci_get_device(dev) == ident->device) {
401198429Srpaulo			device_set_desc(dev, ident->name);
402260086Smarius			return (BUS_PROBE_DEFAULT);
403198429Srpaulo		}
404198429Srpaulo	}
405198429Srpaulo	return ENXIO;
406178676Ssam}
407178676Ssam
408178676Ssamstatic int
409270738Sadrianiwn_is_3stream_device(struct iwn_softc *sc)
410270738Sadrian{
411270738Sadrian	/* XXX for now only 5300, until the 5350 can be tested */
412270738Sadrian	if (sc->hw_type == IWN_HW_REV_TYPE_5300)
413270738Sadrian		return (1);
414270738Sadrian	return (0);
415270738Sadrian}
416270738Sadrian
417270738Sadrianstatic int
418178676Ssamiwn_attach(device_t dev)
419178676Ssam{
420295788Skevlo	struct iwn_softc *sc = device_get_softc(dev);
421178676Ssam	struct ieee80211com *ic;
422260053Smarius	int i, error, rid;
423178676Ssam
424178676Ssam	sc->sc_dev = dev;
425178676Ssam
426253612Sadrian#ifdef	IWN_DEBUG
427253612Sadrian	error = resource_int_value(device_get_name(sc->sc_dev),
428253612Sadrian	    device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug));
429253612Sadrian	if (error != 0)
430253612Sadrian		sc->sc_debug = 0;
431253612Sadrian#else
432253612Sadrian	sc->sc_debug = 0;
433253612Sadrian#endif
434253612Sadrian
435253705Sadrian	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: begin\n",__func__);
436253705Sadrian
437198429Srpaulo	/*
438198429Srpaulo	 * Get the offset of the PCI Express Capability Structure in PCI
439198429Srpaulo	 * Configuration Space.
440198429Srpaulo	 */
441219902Sjhb	error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off);
442198429Srpaulo	if (error != 0) {
443198429Srpaulo		device_printf(dev, "PCIe capability structure not found!\n");
444198429Srpaulo		return error;
445178676Ssam	}
446178676Ssam
447198429Srpaulo	/* Clear device-specific "PCI retry timeout" register (41h). */
448178676Ssam	pci_write_config(dev, 0x41, 0, 1);
449178676Ssam
450198429Srpaulo	/* Enable bus-mastering. */
451178676Ssam	pci_enable_busmaster(dev);
452178676Ssam
453260053Smarius	rid = PCIR_BAR(0);
454260053Smarius	sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
455198429Srpaulo	    RF_ACTIVE);
456220726Sbschmidt	if (sc->mem == NULL) {
457220724Sbschmidt		device_printf(dev, "can't map mem space\n");
458198429Srpaulo		error = ENOMEM;
459178676Ssam		return error;
460178676Ssam	}
461178676Ssam	sc->sc_st = rman_get_bustag(sc->mem);
462178676Ssam	sc->sc_sh = rman_get_bushandle(sc->mem);
463220726Sbschmidt
464260053Smarius	i = 1;
465260053Smarius	rid = 0;
466260053Smarius	if (pci_alloc_msi(dev, &i) == 0)
467260053Smarius		rid = 1;
468220725Sbschmidt	/* Install interrupt handler. */
469260053Smarius	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
470260053Smarius	    (rid != 0 ? 0 : RF_SHAREABLE));
471178676Ssam	if (sc->irq == NULL) {
472220724Sbschmidt		device_printf(dev, "can't map interrupt\n");
473178676Ssam		error = ENOMEM;
474198429Srpaulo		goto fail;
475178676Ssam	}
476178676Ssam
477178676Ssam	IWN_LOCK_INIT(sc);
478178676Ssam
479220728Sbschmidt	/* Read hardware revision and attach. */
480253897Sadrian	sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT)
481253897Sadrian	    & IWN_HW_REV_TYPE_MASK;
482254204Sadrian	sc->subdevice_id = pci_get_subdevice(dev);
483266776Sgavin
484258035Sadrian	/*
485258035Sadrian	 * 4965 versus 5000 and later have different methods.
486258035Sadrian	 * Let's set those up first.
487258035Sadrian	 */
488220728Sbschmidt	if (sc->hw_type == IWN_HW_REV_TYPE_4965)
489343507Savos		iwn4965_attach(sc, pci_get_device(dev));
490220728Sbschmidt	else
491343507Savos		iwn5000_attach(sc, pci_get_device(dev));
492198429Srpaulo
493258035Sadrian	/*
494258035Sadrian	 * Next, let's setup the various parameters of each NIC.
495258035Sadrian	 */
496258035Sadrian	error = iwn_config_specific(sc, pci_get_device(dev));
497258035Sadrian	if (error != 0) {
498258035Sadrian		device_printf(dev, "could not attach device, error %d\n",
499258035Sadrian		    error);
500258035Sadrian		goto fail;
501258035Sadrian	}
502258035Sadrian
503220726Sbschmidt	if ((error = iwn_hw_prepare(sc)) != 0) {
504198429Srpaulo		device_printf(dev, "hardware not ready, error %d\n", error);
505178676Ssam		goto fail;
506178676Ssam	}
507178676Ssam
508198429Srpaulo	/* Allocate DMA memory for firmware transfers. */
509220726Sbschmidt	if ((error = iwn_alloc_fwmem(sc)) != 0) {
510178676Ssam		device_printf(dev,
511198429Srpaulo		    "could not allocate memory for firmware, error %d\n",
512198429Srpaulo		    error);
513178676Ssam		goto fail;
514178676Ssam	}
515178676Ssam
516198429Srpaulo	/* Allocate "Keep Warm" page. */
517220726Sbschmidt	if ((error = iwn_alloc_kw(sc)) != 0) {
518178676Ssam		device_printf(dev,
519220724Sbschmidt		    "could not allocate keep warm page, error %d\n", error);
520178676Ssam		goto fail;
521178676Ssam	}
522178676Ssam
523201209Srpaulo	/* Allocate ICT table for 5000 Series. */
524201209Srpaulo	if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
525201209Srpaulo	    (error = iwn_alloc_ict(sc)) != 0) {
526220724Sbschmidt		device_printf(dev, "could not allocate ICT table, error %d\n",
527220724Sbschmidt		    error);
528201209Srpaulo		goto fail;
529201209Srpaulo	}
530201209Srpaulo
531198429Srpaulo	/* Allocate TX scheduler "rings". */
532220726Sbschmidt	if ((error = iwn_alloc_sched(sc)) != 0) {
533178676Ssam		device_printf(dev,
534220726Sbschmidt		    "could not allocate TX scheduler rings, error %d\n", error);
535178676Ssam		goto fail;
536178676Ssam	}
537178676Ssam
538220725Sbschmidt	/* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */
539220728Sbschmidt	for (i = 0; i < sc->ntxqs; i++) {
540220726Sbschmidt		if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) {
541178676Ssam			device_printf(dev,
542220724Sbschmidt			    "could not allocate TX ring %d, error %d\n", i,
543220724Sbschmidt			    error);
544178676Ssam			goto fail;
545178676Ssam		}
546178676Ssam	}
547178676Ssam
548198429Srpaulo	/* Allocate RX ring. */
549220726Sbschmidt	if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) {
550220724Sbschmidt		device_printf(dev, "could not allocate RX ring, error %d\n",
551220724Sbschmidt		    error);
552178676Ssam		goto fail;
553178676Ssam	}
554178676Ssam
555198429Srpaulo	/* Clear pending interrupts. */
556198429Srpaulo	IWN_WRITE(sc, IWN_INT, 0xffffffff);
557198429Srpaulo
558287197Sglebius	ic = &sc->sc_ic;
559283532Sglebius	ic->ic_softc = sc;
560283527Sglebius	ic->ic_name = device_get_nameunit(dev);
561178676Ssam	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
562178676Ssam	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
563178676Ssam
564198429Srpaulo	/* Set device capabilities. */
565178676Ssam	ic->ic_caps =
566178957Ssam		  IEEE80211_C_STA		/* station mode supported */
567178957Ssam		| IEEE80211_C_MONITOR		/* monitor mode supported */
568283979Sadrian#if 0
569222679Sbschmidt		| IEEE80211_C_BGSCAN		/* background scanning */
570283979Sadrian#endif
571178676Ssam		| IEEE80211_C_TXPMGT		/* tx power management */
572178676Ssam		| IEEE80211_C_SHSLOT		/* short slot time supported */
573178676Ssam		| IEEE80211_C_WPA
574178676Ssam		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
575178676Ssam#if 0
576178676Ssam		| IEEE80211_C_IBSS		/* ibss/adhoc mode */
577178676Ssam#endif
578178676Ssam		| IEEE80211_C_WME		/* WME */
579252717Sadrian		| IEEE80211_C_PMGT		/* Station-side power mgmt */
580178676Ssam		;
581221640Sbschmidt
582221642Sbschmidt	/* Read MAC address, channels, etc from EEPROM. */
583287197Sglebius	if ((error = iwn_read_eeprom(sc, ic->ic_macaddr)) != 0) {
584221642Sbschmidt		device_printf(dev, "could not read EEPROM, error %d\n",
585221642Sbschmidt		    error);
586221642Sbschmidt		goto fail;
587221642Sbschmidt	}
588221642Sbschmidt
589221642Sbschmidt	/* Count the number of available chains. */
590221642Sbschmidt	sc->ntxchains =
591221642Sbschmidt	    ((sc->txchainmask >> 2) & 1) +
592221642Sbschmidt	    ((sc->txchainmask >> 1) & 1) +
593221642Sbschmidt	    ((sc->txchainmask >> 0) & 1);
594221642Sbschmidt	sc->nrxchains =
595221642Sbschmidt	    ((sc->rxchainmask >> 2) & 1) +
596221642Sbschmidt	    ((sc->rxchainmask >> 1) & 1) +
597221642Sbschmidt	    ((sc->rxchainmask >> 0) & 1);
598221642Sbschmidt	if (bootverbose) {
599221642Sbschmidt		device_printf(dev, "MIMO %dT%dR, %.4s, address %6D\n",
600221642Sbschmidt		    sc->ntxchains, sc->nrxchains, sc->eeprom_domain,
601287197Sglebius		    ic->ic_macaddr, ":");
602221642Sbschmidt	}
603221642Sbschmidt
604221657Sbschmidt	if (sc->sc_flags & IWN_FLAG_HAS_11N) {
605221657Sbschmidt		ic->ic_rxstream = sc->nrxchains;
606221657Sbschmidt		ic->ic_txstream = sc->ntxchains;
607254085Sadrian
608254085Sadrian		/*
609270738Sadrian		 * Some of the 3 antenna devices (ie, the 4965) only supports
610270738Sadrian		 * 2x2 operation.  So correct the number of streams if
611270738Sadrian		 * it's not a 3-stream device.
612254085Sadrian		 */
613270738Sadrian		if (! iwn_is_3stream_device(sc)) {
614270738Sadrian			if (ic->ic_rxstream > 2)
615270738Sadrian				ic->ic_rxstream = 2;
616270738Sadrian			if (ic->ic_txstream > 2)
617270738Sadrian				ic->ic_txstream = 2;
618270738Sadrian		}
619254085Sadrian
620221657Sbschmidt		ic->ic_htcaps =
621221657Sbschmidt			  IEEE80211_HTCAP_SMPS_OFF	/* SMPS mode disabled */
622221657Sbschmidt			| IEEE80211_HTCAP_SHORTGI20	/* short GI in 20MHz */
623221657Sbschmidt			| IEEE80211_HTCAP_CHWIDTH40	/* 40MHz channel width*/
624221657Sbschmidt			| IEEE80211_HTCAP_SHORTGI40	/* short GI in 40MHz */
625222687Sbschmidt#ifdef notyet
626221657Sbschmidt			| IEEE80211_HTCAP_GREENFIELD
627201209Srpaulo#if IWN_RBUF_SIZE == 8192
628221657Sbschmidt			| IEEE80211_HTCAP_MAXAMSDU_7935	/* max A-MSDU length */
629221657Sbschmidt#else
630221657Sbschmidt			| IEEE80211_HTCAP_MAXAMSDU_3839	/* max A-MSDU length */
631178678Ssam#endif
632201209Srpaulo#endif
633221657Sbschmidt			/* s/w capabilities */
634221657Sbschmidt			| IEEE80211_HTC_HT		/* HT operation */
635221657Sbschmidt			| IEEE80211_HTC_AMPDU		/* tx A-MPDU */
636221657Sbschmidt#ifdef notyet
637221657Sbschmidt			| IEEE80211_HTC_AMSDU		/* tx A-MSDU */
638201209Srpaulo#endif
639221657Sbschmidt			;
640221657Sbschmidt	}
641201209Srpaulo
642287197Sglebius	ieee80211_ifattach(ic);
643178676Ssam	ic->ic_vap_create = iwn_vap_create;
644287197Sglebius	ic->ic_ioctl = iwn_ioctl;
645287197Sglebius	ic->ic_parent = iwn_parent;
646178676Ssam	ic->ic_vap_delete = iwn_vap_delete;
647287197Sglebius	ic->ic_transmit = iwn_transmit;
648178676Ssam	ic->ic_raw_xmit = iwn_raw_xmit;
649178676Ssam	ic->ic_node_alloc = iwn_node_alloc;
650221650Sbschmidt	sc->sc_ampdu_rx_start = ic->ic_ampdu_rx_start;
651220723Sbschmidt	ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
652221650Sbschmidt	sc->sc_ampdu_rx_stop = ic->ic_ampdu_rx_stop;
653220723Sbschmidt	ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop;
654221651Sbschmidt	sc->sc_addba_request = ic->ic_addba_request;
655221651Sbschmidt	ic->ic_addba_request = iwn_addba_request;
656221651Sbschmidt	sc->sc_addba_response = ic->ic_addba_response;
657221651Sbschmidt	ic->ic_addba_response = iwn_addba_response;
658221651Sbschmidt	sc->sc_addba_stop = ic->ic_addba_stop;
659221651Sbschmidt	ic->ic_addba_stop = iwn_ampdu_tx_stop;
660220715Sbschmidt	ic->ic_newassoc = iwn_newassoc;
661220721Sbschmidt	ic->ic_wme.wme_update = iwn_updateedca;
662201209Srpaulo	ic->ic_update_mcast = iwn_update_mcast;
663198429Srpaulo	ic->ic_scan_start = iwn_scan_start;
664198429Srpaulo	ic->ic_scan_end = iwn_scan_end;
665198429Srpaulo	ic->ic_set_channel = iwn_set_channel;
666198429Srpaulo	ic->ic_scan_curchan = iwn_scan_curchan;
667198429Srpaulo	ic->ic_scan_mindwell = iwn_scan_mindwell;
668293716Savos	ic->ic_getradiocaps = iwn_getradiocaps;
669201209Srpaulo	ic->ic_setregdomain = iwn_setregdomain;
670178676Ssam
671198429Srpaulo	iwn_radiotap_attach(sc);
672220667Sbschmidt
673220667Sbschmidt	callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0);
674300732Savos	callout_init_mtx(&sc->scan_timeout, &sc->sc_mtx, 0);
675220667Sbschmidt	callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0);
676220726Sbschmidt	TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc);
677220726Sbschmidt	TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc);
678266546Strasz	TASK_INIT(&sc->sc_panic_task, 0, iwn_panicked, sc);
679284588Sadrian	TASK_INIT(&sc->sc_xmit_task, 0, iwn_xmit_task, sc);
680220667Sbschmidt
681284588Sadrian	mbufq_init(&sc->sc_xmit_queue, 1024);
682284588Sadrian
683266546Strasz	sc->sc_tq = taskqueue_create("iwn_taskq", M_WAITOK,
684266546Strasz	    taskqueue_thread_enqueue, &sc->sc_tq);
685266546Strasz	error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "iwn_taskq");
686266546Strasz	if (error != 0) {
687266546Strasz		device_printf(dev, "can't start threads, error %d\n", error);
688266546Strasz		goto fail;
689266546Strasz	}
690266546Strasz
691178676Ssam	iwn_sysctlattach(sc);
692178676Ssam
693198429Srpaulo	/*
694198429Srpaulo	 * Hook our interrupt after all initialization is complete.
695198429Srpaulo	 */
696198429Srpaulo	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
697178676Ssam	    NULL, iwn_intr, sc, &sc->sc_ih);
698198429Srpaulo	if (error != 0) {
699220724Sbschmidt		device_printf(dev, "can't establish interrupt, error %d\n",
700198429Srpaulo		    error);
701198429Srpaulo		goto fail;
702198429Srpaulo	}
703178676Ssam
704262729Sadrian#if 0
705262729Sadrian	device_printf(sc->sc_dev, "%s: rx_stats=%d, rx_stats_bt=%d\n",
706262729Sadrian	    __func__,
707262729Sadrian	    sizeof(struct iwn_stats),
708262729Sadrian	    sizeof(struct iwn_stats_bt));
709262729Sadrian#endif
710262729Sadrian
711220724Sbschmidt	if (bootverbose)
712220724Sbschmidt		ieee80211_announce(ic);
713253705Sadrian	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
714287312Sadrian
715287312Sadrian	/* Add debug ioctl right at the end */
716287312Sadrian	sc->sc_cdev = make_dev(&iwn_cdevsw, device_get_unit(dev),
717287312Sadrian	    UID_ROOT, GID_WHEEL, 0600, "%s", device_get_nameunit(dev));
718287312Sadrian	if (sc->sc_cdev == NULL) {
719287312Sadrian		device_printf(dev, "failed to create debug character device\n");
720287312Sadrian	} else {
721287312Sadrian		sc->sc_cdev->si_drv1 = sc;
722287312Sadrian	}
723178676Ssam	return 0;
724178676Ssamfail:
725220635Sbschmidt	iwn_detach(dev);
726253705Sadrian	DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__);
727178676Ssam	return error;
728178676Ssam}
729178676Ssam
730258035Sadrian/*
731258035Sadrian * Define specific configuration based on device id and subdevice id
732258035Sadrian * pid : PCI device id
733258035Sadrian */
734220728Sbschmidtstatic int
735258035Sadrianiwn_config_specific(struct iwn_softc *sc, uint16_t pid)
736258035Sadrian{
737258035Sadrian
738258035Sadrian	switch (pid) {
739258035Sadrian/* 4965 series */
740258035Sadrian	case IWN_DID_4965_1:
741258035Sadrian	case IWN_DID_4965_2:
742258035Sadrian	case IWN_DID_4965_3:
743258035Sadrian	case IWN_DID_4965_4:
744258035Sadrian		sc->base_params = &iwn4965_base_params;
745258035Sadrian		sc->limits = &iwn4965_sensitivity_limits;
746258035Sadrian		sc->fwname = "iwn4965fw";
747258035Sadrian		/* Override chains masks, ROM is known to be broken. */
748258035Sadrian		sc->txchainmask = IWN_ANT_AB;
749258035Sadrian		sc->rxchainmask = IWN_ANT_ABC;
750258035Sadrian		/* Enable normal btcoex */
751258035Sadrian		sc->sc_flags |= IWN_FLAG_BTCOEX;
752258035Sadrian		break;
753258035Sadrian/* 1000 Series */
754258035Sadrian	case IWN_DID_1000_1:
755258035Sadrian	case IWN_DID_1000_2:
756258035Sadrian		switch(sc->subdevice_id) {
757258035Sadrian			case	IWN_SDID_1000_1:
758258035Sadrian			case	IWN_SDID_1000_2:
759258035Sadrian			case	IWN_SDID_1000_3:
760258035Sadrian			case	IWN_SDID_1000_4:
761258035Sadrian			case	IWN_SDID_1000_5:
762258035Sadrian			case	IWN_SDID_1000_6:
763258035Sadrian			case	IWN_SDID_1000_7:
764258035Sadrian			case	IWN_SDID_1000_8:
765258035Sadrian			case	IWN_SDID_1000_9:
766258035Sadrian			case	IWN_SDID_1000_10:
767258035Sadrian			case	IWN_SDID_1000_11:
768258035Sadrian			case	IWN_SDID_1000_12:
769258035Sadrian				sc->limits = &iwn1000_sensitivity_limits;
770258035Sadrian				sc->base_params = &iwn1000_base_params;
771258035Sadrian				sc->fwname = "iwn1000fw";
772258035Sadrian				break;
773258035Sadrian			default:
774258035Sadrian				device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
775258035Sadrian				    "0x%04x rev %d not supported (subdevice)\n", pid,
776258035Sadrian				    sc->subdevice_id,sc->hw_type);
777258035Sadrian				return ENOTSUP;
778