1 | /* $NetBSD: if_wpi.c,v 1.74 2016/06/10 13:27:14 ozaki-r Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2006, 2007 |
5 | * Damien Bergamini <damien.bergamini@free.fr> |
6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. |
10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ |
19 | |
20 | #include <sys/cdefs.h> |
21 | __KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.74 2016/06/10 13:27:14 ozaki-r Exp $" ); |
22 | |
23 | /* |
24 | * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters. |
25 | */ |
26 | |
27 | |
28 | #include <sys/param.h> |
29 | #include <sys/sockio.h> |
30 | #include <sys/sysctl.h> |
31 | #include <sys/mbuf.h> |
32 | #include <sys/kernel.h> |
33 | #include <sys/socket.h> |
34 | #include <sys/systm.h> |
35 | #include <sys/malloc.h> |
36 | #include <sys/mutex.h> |
37 | #include <sys/once.h> |
38 | #include <sys/conf.h> |
39 | #include <sys/kauth.h> |
40 | #include <sys/callout.h> |
41 | #include <sys/proc.h> |
42 | #include <sys/kthread.h> |
43 | |
44 | #include <sys/bus.h> |
45 | #include <machine/endian.h> |
46 | #include <sys/intr.h> |
47 | |
48 | #include <dev/pci/pcireg.h> |
49 | #include <dev/pci/pcivar.h> |
50 | #include <dev/pci/pcidevs.h> |
51 | |
52 | #include <dev/sysmon/sysmonvar.h> |
53 | |
54 | #include <net/bpf.h> |
55 | #include <net/if.h> |
56 | #include <net/if_arp.h> |
57 | #include <net/if_dl.h> |
58 | #include <net/if_ether.h> |
59 | #include <net/if_media.h> |
60 | #include <net/if_types.h> |
61 | |
62 | #include <netinet/in.h> |
63 | #include <netinet/in_systm.h> |
64 | #include <netinet/in_var.h> |
65 | #include <netinet/ip.h> |
66 | |
67 | #include <net80211/ieee80211_var.h> |
68 | #include <net80211/ieee80211_amrr.h> |
69 | #include <net80211/ieee80211_radiotap.h> |
70 | |
71 | #include <dev/firmload.h> |
72 | |
73 | #include <dev/pci/if_wpireg.h> |
74 | #include <dev/pci/if_wpivar.h> |
75 | |
76 | static const char wpi_firmware_name[] = "iwlwifi-3945.ucode" ; |
77 | static once_t wpi_firmware_init; |
78 | static kmutex_t wpi_firmware_mutex; |
79 | static size_t wpi_firmware_users; |
80 | static uint8_t *wpi_firmware_image; |
81 | static size_t wpi_firmware_size; |
82 | |
83 | static int wpi_match(device_t, cfdata_t, void *); |
84 | static void wpi_attach(device_t, device_t, void *); |
85 | static int wpi_detach(device_t , int); |
86 | static int wpi_dma_contig_alloc(bus_dma_tag_t, struct wpi_dma_info *, |
87 | void **, bus_size_t, bus_size_t, int); |
88 | static void wpi_dma_contig_free(struct wpi_dma_info *); |
89 | static int wpi_alloc_shared(struct wpi_softc *); |
90 | static void wpi_free_shared(struct wpi_softc *); |
91 | static int wpi_alloc_fwmem(struct wpi_softc *); |
92 | static void wpi_free_fwmem(struct wpi_softc *); |
93 | static struct wpi_rbuf *wpi_alloc_rbuf(struct wpi_softc *); |
94 | static void wpi_free_rbuf(struct mbuf *, void *, size_t, void *); |
95 | static int wpi_alloc_rpool(struct wpi_softc *); |
96 | static void wpi_free_rpool(struct wpi_softc *); |
97 | static int wpi_alloc_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); |
98 | static void wpi_reset_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); |
99 | static void wpi_free_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); |
100 | static int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, |
101 | int, int); |
102 | static void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); |
103 | static void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); |
104 | static struct ieee80211_node * wpi_node_alloc(struct ieee80211_node_table *); |
105 | static void wpi_newassoc(struct ieee80211_node *, int); |
106 | static int wpi_media_change(struct ifnet *); |
107 | static int wpi_newstate(struct ieee80211com *, enum ieee80211_state, int); |
108 | static void wpi_mem_lock(struct wpi_softc *); |
109 | static void wpi_mem_unlock(struct wpi_softc *); |
110 | static uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); |
111 | static void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); |
112 | static void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, |
113 | const uint32_t *, int); |
114 | static int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); |
115 | static int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int); |
116 | static int wpi_cache_firmware(struct wpi_softc *); |
117 | static void wpi_release_firmware(void); |
118 | static int wpi_load_firmware(struct wpi_softc *); |
119 | static void wpi_calib_timeout(void *); |
120 | static void wpi_iter_func(void *, struct ieee80211_node *); |
121 | static void wpi_power_calibration(struct wpi_softc *, int); |
122 | static void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *, |
123 | struct wpi_rx_data *); |
124 | static void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *); |
125 | static void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *); |
126 | static void wpi_notif_intr(struct wpi_softc *); |
127 | static int wpi_intr(void *); |
128 | static void wpi_read_eeprom(struct wpi_softc *); |
129 | static void wpi_read_eeprom_channels(struct wpi_softc *, int); |
130 | static void wpi_read_eeprom_group(struct wpi_softc *, int); |
131 | static uint8_t wpi_plcp_signal(int); |
132 | static int wpi_tx_data(struct wpi_softc *, struct mbuf *, |
133 | struct ieee80211_node *, int); |
134 | static void wpi_start(struct ifnet *); |
135 | static void wpi_watchdog(struct ifnet *); |
136 | static int wpi_ioctl(struct ifnet *, u_long, void *); |
137 | static int wpi_cmd(struct wpi_softc *, int, const void *, int, int); |
138 | static int wpi_wme_update(struct ieee80211com *); |
139 | static int wpi_mrr_setup(struct wpi_softc *); |
140 | static void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); |
141 | static void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *); |
142 | static int wpi_set_txpower(struct wpi_softc *, |
143 | struct ieee80211_channel *, int); |
144 | static int wpi_get_power_index(struct wpi_softc *, |
145 | struct wpi_power_group *, struct ieee80211_channel *, int); |
146 | static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); |
147 | static int wpi_auth(struct wpi_softc *); |
148 | static int wpi_scan(struct wpi_softc *); |
149 | static int wpi_config(struct wpi_softc *); |
150 | static void wpi_stop_master(struct wpi_softc *); |
151 | static int wpi_power_up(struct wpi_softc *); |
152 | static int wpi_reset(struct wpi_softc *); |
153 | static void wpi_hw_config(struct wpi_softc *); |
154 | static int wpi_init(struct ifnet *); |
155 | static void wpi_stop(struct ifnet *, int); |
156 | static bool wpi_resume(device_t, const pmf_qual_t *); |
157 | static int wpi_getrfkill(struct wpi_softc *); |
158 | static void wpi_sysctlattach(struct wpi_softc *); |
159 | static void wpi_rsw_thread(void *); |
160 | |
161 | #ifdef WPI_DEBUG |
162 | #define DPRINTF(x) do { if (wpi_debug > 0) printf x; } while (0) |
163 | #define DPRINTFN(n, x) do { if (wpi_debug >= (n)) printf x; } while (0) |
164 | int wpi_debug = 1; |
165 | #else |
166 | #define DPRINTF(x) |
167 | #define DPRINTFN(n, x) |
168 | #endif |
169 | |
170 | CFATTACH_DECL_NEW(wpi, sizeof (struct wpi_softc), wpi_match, wpi_attach, |
171 | wpi_detach, NULL); |
172 | |
173 | static int |
174 | wpi_match(device_t parent, cfdata_t match __unused, void *aux) |
175 | { |
176 | struct pci_attach_args *pa = aux; |
177 | |
178 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) |
179 | return 0; |
180 | |
181 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_PRO_WL_3945ABG_1 || |
182 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_PRO_WL_3945ABG_2) |
183 | return 1; |
184 | |
185 | return 0; |
186 | } |
187 | |
188 | /* Base Address Register */ |
189 | #define WPI_PCI_BAR0 0x10 |
190 | |
191 | static int |
192 | wpi_attach_once(void) |
193 | { |
194 | |
195 | mutex_init(&wpi_firmware_mutex, MUTEX_DEFAULT, IPL_NONE); |
196 | return 0; |
197 | } |
198 | |
199 | static void |
200 | wpi_attach(device_t parent __unused, device_t self, void *aux) |
201 | { |
202 | struct wpi_softc *sc = device_private(self); |
203 | struct ieee80211com *ic = &sc->sc_ic; |
204 | struct ifnet *ifp = &sc->sc_ec.ec_if; |
205 | struct pci_attach_args *pa = aux; |
206 | const char *intrstr; |
207 | bus_space_tag_t memt; |
208 | bus_space_handle_t memh; |
209 | pci_intr_handle_t ih; |
210 | pcireg_t data; |
211 | int ac, error; |
212 | char intrbuf[PCI_INTRSTR_LEN]; |
213 | |
214 | RUN_ONCE(&wpi_firmware_init, wpi_attach_once); |
215 | sc->fw_used = false; |
216 | |
217 | sc->sc_dev = self; |
218 | sc->sc_pct = pa->pa_pc; |
219 | sc->sc_pcitag = pa->pa_tag; |
220 | |
221 | sc->sc_rsw_status = WPI_RSW_UNKNOWN; |
222 | sc->sc_rsw.smpsw_name = device_xname(self); |
223 | sc->sc_rsw.smpsw_type = PSWITCH_TYPE_RADIO; |
224 | error = sysmon_pswitch_register(&sc->sc_rsw); |
225 | if (error) { |
226 | aprint_error_dev(self, |
227 | "unable to register radio switch with sysmon\n" ); |
228 | return; |
229 | } |
230 | mutex_init(&sc->sc_rsw_mtx, MUTEX_DEFAULT, IPL_NONE); |
231 | cv_init(&sc->sc_rsw_cv, "wpirsw" ); |
232 | if (kthread_create(PRI_NONE, 0, NULL, |
233 | wpi_rsw_thread, sc, &sc->sc_rsw_lwp, "%s" , device_xname(self))) { |
234 | aprint_error_dev(self, "couldn't create switch thread\n" ); |
235 | } |
236 | |
237 | callout_init(&sc->calib_to, 0); |
238 | callout_setfunc(&sc->calib_to, wpi_calib_timeout, sc); |
239 | |
240 | pci_aprint_devinfo(pa, NULL); |
241 | |
242 | /* enable bus-mastering */ |
243 | data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); |
244 | data |= PCI_COMMAND_MASTER_ENABLE; |
245 | pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, data); |
246 | |
247 | /* map the register window */ |
248 | error = pci_mapreg_map(pa, WPI_PCI_BAR0, PCI_MAPREG_TYPE_MEM | |
249 | PCI_MAPREG_MEM_TYPE_32BIT, 0, &memt, &memh, NULL, &sc->sc_sz); |
250 | if (error != 0) { |
251 | aprint_error_dev(self, "could not map memory space\n" ); |
252 | return; |
253 | } |
254 | |
255 | sc->sc_st = memt; |
256 | sc->sc_sh = memh; |
257 | sc->sc_dmat = pa->pa_dmat; |
258 | |
259 | if (pci_intr_map(pa, &ih) != 0) { |
260 | aprint_error_dev(self, "could not map interrupt\n" ); |
261 | return; |
262 | } |
263 | |
264 | intrstr = pci_intr_string(sc->sc_pct, ih, intrbuf, sizeof(intrbuf)); |
265 | sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, wpi_intr, sc); |
266 | if (sc->sc_ih == NULL) { |
267 | aprint_error_dev(self, "could not establish interrupt" ); |
268 | if (intrstr != NULL) |
269 | aprint_error(" at %s" , intrstr); |
270 | aprint_error("\n" ); |
271 | return; |
272 | } |
273 | aprint_normal_dev(self, "interrupting at %s\n" , intrstr); |
274 | |
275 | /* |
276 | * Put adapter into a known state. |
277 | */ |
278 | if ((error = wpi_reset(sc)) != 0) { |
279 | aprint_error_dev(self, "could not reset adapter\n" ); |
280 | return; |
281 | } |
282 | |
283 | /* |
284 | * Allocate DMA memory for firmware transfers. |
285 | */ |
286 | if ((error = wpi_alloc_fwmem(sc)) != 0) { |
287 | aprint_error_dev(self, "could not allocate firmware memory\n" ); |
288 | return; |
289 | } |
290 | |
291 | /* |
292 | * Allocate shared page and Tx/Rx rings. |
293 | */ |
294 | if ((error = wpi_alloc_shared(sc)) != 0) { |
295 | aprint_error_dev(self, "could not allocate shared area\n" ); |
296 | goto fail1; |
297 | } |
298 | |
299 | if ((error = wpi_alloc_rpool(sc)) != 0) { |
300 | aprint_error_dev(self, "could not allocate Rx buffers\n" ); |
301 | goto fail2; |
302 | } |
303 | |
304 | for (ac = 0; ac < 4; ac++) { |
305 | error = wpi_alloc_tx_ring(sc, &sc->txq[ac], WPI_TX_RING_COUNT, |
306 | ac); |
307 | if (error != 0) { |
308 | aprint_error_dev(self, |
309 | "could not allocate Tx ring %d\n" , ac); |
310 | goto fail3; |
311 | } |
312 | } |
313 | |
314 | error = wpi_alloc_tx_ring(sc, &sc->cmdq, WPI_CMD_RING_COUNT, 4); |
315 | if (error != 0) { |
316 | aprint_error_dev(self, "could not allocate command ring\n" ); |
317 | goto fail3; |
318 | } |
319 | |
320 | error = wpi_alloc_rx_ring(sc, &sc->rxq); |
321 | if (error != 0) { |
322 | aprint_error_dev(self, "could not allocate Rx ring\n" ); |
323 | goto fail4; |
324 | } |
325 | |
326 | ic->ic_ifp = ifp; |
327 | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ |
328 | ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ |
329 | ic->ic_state = IEEE80211_S_INIT; |
330 | |
331 | /* set device capabilities */ |
332 | ic->ic_caps = |
333 | IEEE80211_C_WPA | /* 802.11i */ |
334 | IEEE80211_C_MONITOR | /* monitor mode supported */ |
335 | IEEE80211_C_TXPMGT | /* tx power management */ |
336 | IEEE80211_C_SHSLOT | /* short slot time supported */ |
337 | IEEE80211_C_SHPREAMBLE | /* short preamble supported */ |
338 | IEEE80211_C_WME; /* 802.11e */ |
339 | |
340 | /* read supported channels and MAC address from EEPROM */ |
341 | wpi_read_eeprom(sc); |
342 | |
343 | /* set supported .11a, .11b and .11g rates */ |
344 | ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; |
345 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; |
346 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; |
347 | |
348 | /* IBSS channel undefined for now */ |
349 | ic->ic_ibss_chan = &ic->ic_channels[0]; |
350 | |
351 | ifp->if_softc = sc; |
352 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
353 | ifp->if_init = wpi_init; |
354 | ifp->if_stop = wpi_stop; |
355 | ifp->if_ioctl = wpi_ioctl; |
356 | ifp->if_start = wpi_start; |
357 | ifp->if_watchdog = wpi_watchdog; |
358 | IFQ_SET_READY(&ifp->if_snd); |
359 | memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); |
360 | |
361 | if_attach(ifp); |
362 | ieee80211_ifattach(ic); |
363 | /* override default methods */ |
364 | ic->ic_node_alloc = wpi_node_alloc; |
365 | ic->ic_newassoc = wpi_newassoc; |
366 | ic->ic_wme.wme_update = wpi_wme_update; |
367 | |
368 | /* override state transition machine */ |
369 | sc->sc_newstate = ic->ic_newstate; |
370 | ic->ic_newstate = wpi_newstate; |
371 | ieee80211_media_init(ic, wpi_media_change, ieee80211_media_status); |
372 | |
373 | sc->amrr.amrr_min_success_threshold = 1; |
374 | sc->amrr.amrr_max_success_threshold = 15; |
375 | |
376 | wpi_sysctlattach(sc); |
377 | |
378 | if (pmf_device_register(self, NULL, wpi_resume)) |
379 | pmf_class_network_register(self, ifp); |
380 | else |
381 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
382 | |
383 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, |
384 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, |
385 | &sc->sc_drvbpf); |
386 | |
387 | sc->sc_rxtap_len = sizeof sc->sc_rxtapu; |
388 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); |
389 | sc->sc_rxtap.wr_ihdr.it_present = htole32(WPI_RX_RADIOTAP_PRESENT); |
390 | |
391 | sc->sc_txtap_len = sizeof sc->sc_txtapu; |
392 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); |
393 | sc->sc_txtap.wt_ihdr.it_present = htole32(WPI_TX_RADIOTAP_PRESENT); |
394 | |
395 | ieee80211_announce(ic); |
396 | |
397 | return; |
398 | |
399 | /* free allocated memory if something failed during attachment */ |
400 | fail4: wpi_free_tx_ring(sc, &sc->cmdq); |
401 | fail3: while (--ac >= 0) |
402 | wpi_free_tx_ring(sc, &sc->txq[ac]); |
403 | wpi_free_rpool(sc); |
404 | fail2: wpi_free_shared(sc); |
405 | fail1: wpi_free_fwmem(sc); |
406 | } |
407 | |
408 | static int |
409 | wpi_detach(device_t self, int flags __unused) |
410 | { |
411 | struct wpi_softc *sc = device_private(self); |
412 | struct ifnet *ifp = sc->sc_ic.ic_ifp; |
413 | int ac; |
414 | |
415 | wpi_stop(ifp, 1); |
416 | |
417 | if (ifp != NULL) |
418 | bpf_detach(ifp); |
419 | ieee80211_ifdetach(&sc->sc_ic); |
420 | if (ifp != NULL) |
421 | if_detach(ifp); |
422 | |
423 | for (ac = 0; ac < 4; ac++) |
424 | wpi_free_tx_ring(sc, &sc->txq[ac]); |
425 | wpi_free_tx_ring(sc, &sc->cmdq); |
426 | wpi_free_rx_ring(sc, &sc->rxq); |
427 | wpi_free_rpool(sc); |
428 | wpi_free_shared(sc); |
429 | |
430 | if (sc->sc_ih != NULL) { |
431 | pci_intr_disestablish(sc->sc_pct, sc->sc_ih); |
432 | sc->sc_ih = NULL; |
433 | } |
434 | mutex_enter(&sc->sc_rsw_mtx); |
435 | sc->sc_dying = 1; |
436 | cv_signal(&sc->sc_rsw_cv); |
437 | while (sc->sc_rsw_lwp != NULL) |
438 | cv_wait(&sc->sc_rsw_cv, &sc->sc_rsw_mtx); |
439 | mutex_exit(&sc->sc_rsw_mtx); |
440 | sysmon_pswitch_unregister(&sc->sc_rsw); |
441 | |
442 | bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz); |
443 | |
444 | if (sc->fw_used) { |
445 | sc->fw_used = false; |
446 | wpi_release_firmware(); |
447 | } |
448 | cv_destroy(&sc->sc_rsw_cv); |
449 | mutex_destroy(&sc->sc_rsw_mtx); |
450 | return 0; |
451 | } |
452 | |
453 | static int |
454 | wpi_dma_contig_alloc(bus_dma_tag_t tag, struct wpi_dma_info *dma, void **kvap, |
455 | bus_size_t size, bus_size_t alignment, int flags) |
456 | { |
457 | int nsegs, error; |
458 | |
459 | dma->tag = tag; |
460 | dma->size = size; |
461 | |
462 | error = bus_dmamap_create(tag, size, 1, size, 0, flags, &dma->map); |
463 | if (error != 0) |
464 | goto fail; |
465 | |
466 | error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs, |
467 | flags); |
468 | if (error != 0) |
469 | goto fail; |
470 | |
471 | error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr, flags); |
472 | if (error != 0) |
473 | goto fail; |
474 | |
475 | error = bus_dmamap_load(tag, dma->map, dma->vaddr, size, NULL, flags); |
476 | if (error != 0) |
477 | goto fail; |
478 | |
479 | memset(dma->vaddr, 0, size); |
480 | bus_dmamap_sync(dma->tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE); |
481 | |
482 | dma->paddr = dma->map->dm_segs[0].ds_addr; |
483 | if (kvap != NULL) |
484 | *kvap = dma->vaddr; |
485 | |
486 | return 0; |
487 | |
488 | fail: wpi_dma_contig_free(dma); |
489 | return error; |
490 | } |
491 | |
492 | static void |
493 | wpi_dma_contig_free(struct wpi_dma_info *dma) |
494 | { |
495 | if (dma->map != NULL) { |
496 | if (dma->vaddr != NULL) { |
497 | bus_dmamap_unload(dma->tag, dma->map); |
498 | bus_dmamem_unmap(dma->tag, dma->vaddr, dma->size); |
499 | bus_dmamem_free(dma->tag, &dma->seg, 1); |
500 | dma->vaddr = NULL; |
501 | } |
502 | bus_dmamap_destroy(dma->tag, dma->map); |
503 | dma->map = NULL; |
504 | } |
505 | } |
506 | |
507 | /* |
508 | * Allocate a shared page between host and NIC. |
509 | */ |
510 | static int |
511 | wpi_alloc_shared(struct wpi_softc *sc) |
512 | { |
513 | int error; |
514 | |
515 | /* must be aligned on a 4K-page boundary */ |
516 | error = wpi_dma_contig_alloc(sc->sc_dmat, &sc->shared_dma, |
517 | (void **)&sc->shared, sizeof (struct wpi_shared), WPI_BUF_ALIGN, |
518 | BUS_DMA_NOWAIT); |
519 | if (error != 0) |
520 | aprint_error_dev(sc->sc_dev, |
521 | "could not allocate shared area DMA memory\n" ); |
522 | |
523 | return error; |
524 | } |
525 | |
526 | static void |
527 | wpi_free_shared(struct wpi_softc *sc) |
528 | { |
529 | wpi_dma_contig_free(&sc->shared_dma); |
530 | } |
531 | |
532 | /* |
533 | * Allocate DMA-safe memory for firmware transfer. |
534 | */ |
535 | static int |
536 | wpi_alloc_fwmem(struct wpi_softc *sc) |
537 | { |
538 | int error; |
539 | |
540 | /* allocate enough contiguous space to store text and data */ |
541 | error = wpi_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, NULL, |
542 | WPI_FW_MAIN_TEXT_MAXSZ + WPI_FW_MAIN_DATA_MAXSZ, 0, |
543 | BUS_DMA_NOWAIT); |
544 | |
545 | if (error != 0) |
546 | aprint_error_dev(sc->sc_dev, |
547 | "could not allocate firmware transfer area DMA memory\n" ); |
548 | return error; |
549 | } |
550 | |
551 | static void |
552 | wpi_free_fwmem(struct wpi_softc *sc) |
553 | { |
554 | wpi_dma_contig_free(&sc->fw_dma); |
555 | } |
556 | |
557 | static struct wpi_rbuf * |
558 | wpi_alloc_rbuf(struct wpi_softc *sc) |
559 | { |
560 | struct wpi_rbuf *rbuf; |
561 | |
562 | mutex_enter(&sc->rxq.freelist_mtx); |
563 | rbuf = SLIST_FIRST(&sc->rxq.freelist); |
564 | if (rbuf != NULL) { |
565 | SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); |
566 | } |
567 | mutex_exit(&sc->rxq.freelist_mtx); |
568 | |
569 | return rbuf; |
570 | } |
571 | |
572 | /* |
573 | * This is called automatically by the network stack when the mbuf to which our |
574 | * Rx buffer is attached is freed. |
575 | */ |
576 | static void |
577 | wpi_free_rbuf(struct mbuf* m, void *buf, size_t size, void *arg) |
578 | { |
579 | struct wpi_rbuf *rbuf = arg; |
580 | struct wpi_softc *sc = rbuf->sc; |
581 | |
582 | /* put the buffer back in the free list */ |
583 | |
584 | mutex_enter(&sc->rxq.freelist_mtx); |
585 | SLIST_INSERT_HEAD(&sc->rxq.freelist, rbuf, next); |
586 | mutex_exit(&sc->rxq.freelist_mtx); |
587 | |
588 | if (__predict_true(m != NULL)) |
589 | pool_cache_put(mb_cache, m); |
590 | } |
591 | |
592 | static int |
593 | wpi_alloc_rpool(struct wpi_softc *sc) |
594 | { |
595 | struct wpi_rx_ring *ring = &sc->rxq; |
596 | int i, error; |
597 | |
598 | /* allocate a big chunk of DMA'able memory.. */ |
599 | error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->buf_dma, NULL, |
600 | WPI_RBUF_COUNT * WPI_RBUF_SIZE, WPI_BUF_ALIGN, BUS_DMA_NOWAIT); |
601 | if (error != 0) { |
602 | aprint_normal_dev(sc->sc_dev, |
603 | "could not allocate Rx buffers DMA memory\n" ); |
604 | return error; |
605 | } |
606 | |
607 | /* ..and split it into 3KB chunks */ |
608 | mutex_init(&ring->freelist_mtx, MUTEX_DEFAULT, IPL_NET); |
609 | SLIST_INIT(&ring->freelist); |
610 | for (i = 0; i < WPI_RBUF_COUNT; i++) { |
611 | struct wpi_rbuf *rbuf = &ring->rbuf[i]; |
612 | |
613 | rbuf->sc = sc; /* backpointer for callbacks */ |
614 | rbuf->vaddr = (char *)ring->buf_dma.vaddr + i * WPI_RBUF_SIZE; |
615 | rbuf->paddr = ring->buf_dma.paddr + i * WPI_RBUF_SIZE; |
616 | |
617 | SLIST_INSERT_HEAD(&ring->freelist, rbuf, next); |
618 | } |
619 | |
620 | return 0; |
621 | } |
622 | |
623 | static void |
624 | wpi_free_rpool(struct wpi_softc *sc) |
625 | { |
626 | wpi_dma_contig_free(&sc->rxq.buf_dma); |
627 | } |
628 | |
629 | static int |
630 | wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) |
631 | { |
632 | bus_size_t size; |
633 | int i, error; |
634 | |
635 | ring->cur = 0; |
636 | |
637 | size = WPI_RX_RING_COUNT * sizeof (uint32_t); |
638 | error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, |
639 | (void **)&ring->desc, size, |
640 | WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); |
641 | if (error != 0) { |
642 | aprint_error_dev(sc->sc_dev, |
643 | "could not allocate rx ring DMA memory\n" ); |
644 | goto fail; |
645 | } |
646 | |
647 | /* |
648 | * Setup Rx buffers. |
649 | */ |
650 | for (i = 0; i < WPI_RX_RING_COUNT; i++) { |
651 | struct wpi_rx_data *data = &ring->data[i]; |
652 | struct wpi_rbuf *rbuf; |
653 | |
654 | error = bus_dmamap_create(sc->sc_dmat, WPI_RBUF_SIZE, 1, |
655 | WPI_RBUF_SIZE, 0, BUS_DMA_NOWAIT, &data->map); |
656 | if (error) { |
657 | aprint_error_dev(sc->sc_dev, |
658 | "could not allocate rx dma map\n" ); |
659 | goto fail; |
660 | } |
661 | |
662 | MGETHDR(data->m, M_DONTWAIT, MT_DATA); |
663 | if (data->m == NULL) { |
664 | aprint_error_dev(sc->sc_dev, |
665 | "could not allocate rx mbuf\n" ); |
666 | error = ENOMEM; |
667 | goto fail; |
668 | } |
669 | if ((rbuf = wpi_alloc_rbuf(sc)) == NULL) { |
670 | m_freem(data->m); |
671 | data->m = NULL; |
672 | aprint_error_dev(sc->sc_dev, |
673 | "could not allocate rx cluster\n" ); |
674 | error = ENOMEM; |
675 | goto fail; |
676 | } |
677 | /* attach Rx buffer to mbuf */ |
678 | MEXTADD(data->m, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, |
679 | rbuf); |
680 | data->m->m_flags |= M_EXT_RW; |
681 | |
682 | error = bus_dmamap_load(sc->sc_dmat, data->map, |
683 | mtod(data->m, void *), WPI_RBUF_SIZE, NULL, |
684 | BUS_DMA_NOWAIT | BUS_DMA_READ); |
685 | if (error) { |
686 | aprint_error_dev(sc->sc_dev, |
687 | "could not load mbuf: %d\n" , error); |
688 | goto fail; |
689 | } |
690 | |
691 | ring->desc[i] = htole32(rbuf->paddr); |
692 | } |
693 | |
694 | bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, size, |
695 | BUS_DMASYNC_PREWRITE); |
696 | |
697 | return 0; |
698 | |
699 | fail: wpi_free_rx_ring(sc, ring); |
700 | return error; |
701 | } |
702 | |
703 | static void |
704 | wpi_reset_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) |
705 | { |
706 | int ntries; |
707 | |
708 | wpi_mem_lock(sc); |
709 | |
710 | WPI_WRITE(sc, WPI_RX_CONFIG, 0); |
711 | for (ntries = 0; ntries < 100; ntries++) { |
712 | if (WPI_READ(sc, WPI_RX_STATUS) & WPI_RX_IDLE) |
713 | break; |
714 | DELAY(10); |
715 | } |
716 | #ifdef WPI_DEBUG |
717 | if (ntries == 100 && wpi_debug > 0) |
718 | aprint_error_dev(sc->sc_dev, "timeout resetting Rx ring\n" ); |
719 | #endif |
720 | wpi_mem_unlock(sc); |
721 | |
722 | ring->cur = 0; |
723 | } |
724 | |
725 | static void |
726 | wpi_free_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) |
727 | { |
728 | int i; |
729 | |
730 | wpi_dma_contig_free(&ring->desc_dma); |
731 | |
732 | for (i = 0; i < WPI_RX_RING_COUNT; i++) { |
733 | if (ring->data[i].m != NULL) { |
734 | bus_dmamap_unload(sc->sc_dmat, ring->data[i].map); |
735 | m_freem(ring->data[i].m); |
736 | } |
737 | if (ring->data[i].map != NULL) { |
738 | bus_dmamap_destroy(sc->sc_dmat, ring->data[i].map); |
739 | } |
740 | } |
741 | } |
742 | |
743 | static int |
744 | wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int count, |
745 | int qid) |
746 | { |
747 | int i, error; |
748 | |
749 | ring->qid = qid; |
750 | ring->count = count; |
751 | ring->queued = 0; |
752 | ring->cur = 0; |
753 | |
754 | error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, |
755 | (void **)&ring->desc, count * sizeof (struct wpi_tx_desc), |
756 | WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); |
757 | if (error != 0) { |
758 | aprint_error_dev(sc->sc_dev, |
759 | "could not allocate tx ring DMA memory\n" ); |
760 | goto fail; |
761 | } |
762 | |
763 | /* update shared page with ring's base address */ |
764 | sc->shared->txbase[qid] = htole32(ring->desc_dma.paddr); |
765 | bus_dmamap_sync(sc->sc_dmat, sc->shared_dma.map, 0, |
766 | sizeof(struct wpi_shared), BUS_DMASYNC_PREWRITE); |
767 | |
768 | error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, |
769 | (void **)&ring->cmd, count * sizeof (struct wpi_tx_cmd), 4, |
770 | BUS_DMA_NOWAIT); |
771 | if (error != 0) { |
772 | aprint_error_dev(sc->sc_dev, |
773 | "could not allocate tx cmd DMA memory\n" ); |
774 | goto fail; |
775 | } |
776 | |
777 | ring->data = malloc(count * sizeof (struct wpi_tx_data), M_DEVBUF, |
778 | M_NOWAIT | M_ZERO); |
779 | if (ring->data == NULL) { |
780 | aprint_error_dev(sc->sc_dev, |
781 | "could not allocate tx data slots\n" ); |
782 | goto fail; |
783 | } |
784 | |
785 | for (i = 0; i < count; i++) { |
786 | struct wpi_tx_data *data = &ring->data[i]; |
787 | |
788 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, |
789 | WPI_MAX_SCATTER - 1, MCLBYTES, 0, BUS_DMA_NOWAIT, |
790 | &data->map); |
791 | if (error != 0) { |
792 | aprint_error_dev(sc->sc_dev, |
793 | "could not create tx buf DMA map\n" ); |
794 | goto fail; |
795 | } |
796 | } |
797 | |
798 | return 0; |
799 | |
800 | fail: wpi_free_tx_ring(sc, ring); |
801 | return error; |
802 | } |
803 | |
804 | static void |
805 | wpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) |
806 | { |
807 | int i, ntries; |
808 | |
809 | wpi_mem_lock(sc); |
810 | |
811 | WPI_WRITE(sc, WPI_TX_CONFIG(ring->qid), 0); |
812 | for (ntries = 0; ntries < 100; ntries++) { |
813 | if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(ring->qid)) |
814 | break; |
815 | DELAY(10); |
816 | } |
817 | #ifdef WPI_DEBUG |
818 | if (ntries == 100 && wpi_debug > 0) { |
819 | aprint_error_dev(sc->sc_dev, "timeout resetting Tx ring %d\n" , |
820 | ring->qid); |
821 | } |
822 | #endif |
823 | wpi_mem_unlock(sc); |
824 | |
825 | for (i = 0; i < ring->count; i++) { |
826 | struct wpi_tx_data *data = &ring->data[i]; |
827 | |
828 | if (data->m != NULL) { |
829 | bus_dmamap_unload(sc->sc_dmat, data->map); |
830 | m_freem(data->m); |
831 | data->m = NULL; |
832 | } |
833 | } |
834 | |
835 | ring->queued = 0; |
836 | ring->cur = 0; |
837 | } |
838 | |
839 | static void |
840 | wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) |
841 | { |
842 | int i; |
843 | |
844 | wpi_dma_contig_free(&ring->desc_dma); |
845 | wpi_dma_contig_free(&ring->cmd_dma); |
846 | |
847 | if (ring->data != NULL) { |
848 | for (i = 0; i < ring->count; i++) { |
849 | struct wpi_tx_data *data = &ring->data[i]; |
850 | |
851 | if (data->m != NULL) { |
852 | bus_dmamap_unload(sc->sc_dmat, data->map); |
853 | m_freem(data->m); |
854 | } |
855 | } |
856 | free(ring->data, M_DEVBUF); |
857 | } |
858 | } |
859 | |
860 | /*ARGUSED*/ |
861 | static struct ieee80211_node * |
862 | wpi_node_alloc(struct ieee80211_node_table *nt __unused) |
863 | { |
864 | struct wpi_node *wn; |
865 | |
866 | wn = malloc(sizeof (struct wpi_node), M_80211_NODE, M_NOWAIT | M_ZERO); |
867 | |
868 | return (struct ieee80211_node *)wn; |
869 | } |
870 | |
871 | static void |
872 | wpi_newassoc(struct ieee80211_node *ni, int isnew) |
873 | { |
874 | struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; |
875 | int i; |
876 | |
877 | ieee80211_amrr_node_init(&sc->amrr, &((struct wpi_node *)ni)->amn); |
878 | |
879 | /* set rate to some reasonable initial value */ |
880 | for (i = ni->ni_rates.rs_nrates - 1; |
881 | i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; |
882 | i--); |
883 | ni->ni_txrate = i; |
884 | } |
885 | |
886 | static int |
887 | wpi_media_change(struct ifnet *ifp) |
888 | { |
889 | int error; |
890 | |
891 | error = ieee80211_media_change(ifp); |
892 | if (error != ENETRESET) |
893 | return error; |
894 | |
895 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) |
896 | wpi_init(ifp); |
897 | |
898 | return 0; |
899 | } |
900 | |
901 | static int |
902 | wpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) |
903 | { |
904 | struct ifnet *ifp = ic->ic_ifp; |
905 | struct wpi_softc *sc = ifp->if_softc; |
906 | struct ieee80211_node *ni; |
907 | enum ieee80211_state ostate = ic->ic_state; |
908 | int error; |
909 | |
910 | callout_stop(&sc->calib_to); |
911 | |
912 | switch (nstate) { |
913 | case IEEE80211_S_SCAN: |
914 | |
915 | if (sc->is_scanning) |
916 | break; |
917 | |
918 | sc->is_scanning = true; |
919 | |
920 | if (ostate != IEEE80211_S_SCAN) { |
921 | /* make the link LED blink while we're scanning */ |
922 | wpi_set_led(sc, WPI_LED_LINK, 20, 2); |
923 | } |
924 | |
925 | if ((error = wpi_scan(sc)) != 0) { |
926 | aprint_error_dev(sc->sc_dev, |
927 | "could not initiate scan\n" ); |
928 | return error; |
929 | } |
930 | break; |
931 | |
932 | case IEEE80211_S_ASSOC: |
933 | if (ic->ic_state != IEEE80211_S_RUN) |
934 | break; |
935 | /* FALLTHROUGH */ |
936 | case IEEE80211_S_AUTH: |
937 | /* reset state to handle reassociations correctly */ |
938 | sc->config.associd = 0; |
939 | sc->config.filter &= ~htole32(WPI_FILTER_BSS); |
940 | |
941 | if ((error = wpi_auth(sc)) != 0) { |
942 | aprint_error_dev(sc->sc_dev, |
943 | "could not send authentication request\n" ); |
944 | return error; |
945 | } |
946 | break; |
947 | |
948 | case IEEE80211_S_RUN: |
949 | if (ic->ic_opmode == IEEE80211_M_MONITOR) { |
950 | /* link LED blinks while monitoring */ |
951 | wpi_set_led(sc, WPI_LED_LINK, 5, 5); |
952 | break; |
953 | } |
954 | ni = ic->ic_bss; |
955 | |
956 | if (ic->ic_opmode != IEEE80211_M_STA) { |
957 | (void) wpi_auth(sc); /* XXX */ |
958 | wpi_setup_beacon(sc, ni); |
959 | } |
960 | |
961 | wpi_enable_tsf(sc, ni); |
962 | |
963 | /* update adapter's configuration */ |
964 | sc->config.associd = htole16(ni->ni_associd & ~0xc000); |
965 | /* short preamble/slot time are negotiated when associating */ |
966 | sc->config.flags &= ~htole32(WPI_CONFIG_SHPREAMBLE | |
967 | WPI_CONFIG_SHSLOT); |
968 | if (ic->ic_flags & IEEE80211_F_SHSLOT) |
969 | sc->config.flags |= htole32(WPI_CONFIG_SHSLOT); |
970 | if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) |
971 | sc->config.flags |= htole32(WPI_CONFIG_SHPREAMBLE); |
972 | sc->config.filter |= htole32(WPI_FILTER_BSS); |
973 | if (ic->ic_opmode != IEEE80211_M_STA) |
974 | sc->config.filter |= htole32(WPI_FILTER_BEACON); |
975 | |
976 | /* XXX put somewhere HC_QOS_SUPPORT_ASSOC + HC_IBSS_START */ |
977 | |
978 | DPRINTF(("config chan %d flags %x\n" , sc->config.chan, |
979 | sc->config.flags)); |
980 | error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, |
981 | sizeof (struct wpi_config), 1); |
982 | if (error != 0) { |
983 | aprint_error_dev(sc->sc_dev, |
984 | "could not update configuration\n" ); |
985 | return error; |
986 | } |
987 | |
988 | /* configuration has changed, set Tx power accordingly */ |
989 | if ((error = wpi_set_txpower(sc, ic->ic_curchan, 1)) != 0) { |
990 | aprint_error_dev(sc->sc_dev, |
991 | "could not set Tx power\n" ); |
992 | return error; |
993 | } |
994 | |
995 | if (ic->ic_opmode == IEEE80211_M_STA) { |
996 | /* fake a join to init the tx rate */ |
997 | wpi_newassoc(ni, 1); |
998 | } |
999 | |
1000 | /* start periodic calibration timer */ |
1001 | sc->calib_cnt = 0; |
1002 | callout_schedule(&sc->calib_to, hz/2); |
1003 | |
1004 | /* link LED always on while associated */ |
1005 | wpi_set_led(sc, WPI_LED_LINK, 0, 1); |
1006 | break; |
1007 | |
1008 | case IEEE80211_S_INIT: |
1009 | sc->is_scanning = false; |
1010 | break; |
1011 | } |
1012 | |
1013 | return sc->sc_newstate(ic, nstate, arg); |
1014 | } |
1015 | |
1016 | /* |
1017 | * Grab exclusive access to NIC memory. |
1018 | */ |
1019 | static void |
1020 | wpi_mem_lock(struct wpi_softc *sc) |
1021 | { |
1022 | uint32_t tmp; |
1023 | int ntries; |
1024 | |
1025 | tmp = WPI_READ(sc, WPI_GPIO_CTL); |
1026 | WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_MAC); |
1027 | |
1028 | /* spin until we actually get the lock */ |
1029 | for (ntries = 0; ntries < 1000; ntries++) { |
1030 | if ((WPI_READ(sc, WPI_GPIO_CTL) & |
1031 | (WPI_GPIO_CLOCK | WPI_GPIO_SLEEP)) == WPI_GPIO_CLOCK) |
1032 | break; |
1033 | DELAY(10); |
1034 | } |
1035 | if (ntries == 1000) |
1036 | aprint_error_dev(sc->sc_dev, "could not lock memory\n" ); |
1037 | } |
1038 | |
1039 | /* |
1040 | * Release lock on NIC memory. |
1041 | */ |
1042 | static void |
1043 | wpi_mem_unlock(struct wpi_softc *sc) |
1044 | { |
1045 | uint32_t tmp = WPI_READ(sc, WPI_GPIO_CTL); |
1046 | WPI_WRITE(sc, WPI_GPIO_CTL, tmp & ~WPI_GPIO_MAC); |
1047 | } |
1048 | |
1049 | static uint32_t |
1050 | wpi_mem_read(struct wpi_softc *sc, uint16_t addr) |
1051 | { |
1052 | WPI_WRITE(sc, WPI_READ_MEM_ADDR, WPI_MEM_4 | addr); |
1053 | return WPI_READ(sc, WPI_READ_MEM_DATA); |
1054 | } |
1055 | |
1056 | static void |
1057 | wpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data) |
1058 | { |
1059 | WPI_WRITE(sc, WPI_WRITE_MEM_ADDR, WPI_MEM_4 | addr); |
1060 | WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); |
1061 | } |
1062 | |
1063 | static void |
1064 | wpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr, |
1065 | const uint32_t *data, int wlen) |
1066 | { |
1067 | for (; wlen > 0; wlen--, data++, addr += 4) |
1068 | wpi_mem_write(sc, addr, *data); |
1069 | } |
1070 | |
1071 | /* |
1072 | * Read `len' bytes from the EEPROM. We access the EEPROM through the MAC |
1073 | * instead of using the traditional bit-bang method. |
1074 | */ |
1075 | static int |
1076 | wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) |
1077 | { |
1078 | uint8_t *out = data; |
1079 | uint32_t val; |
1080 | int ntries; |
1081 | |
1082 | wpi_mem_lock(sc); |
1083 | for (; len > 0; len -= 2, addr++) { |
1084 | WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2); |
1085 | |
1086 | for (ntries = 0; ntries < 10; ntries++) { |
1087 | if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) & |
1088 | WPI_EEPROM_READY) |
1089 | break; |
1090 | DELAY(5); |
1091 | } |
1092 | if (ntries == 10) { |
1093 | aprint_error_dev(sc->sc_dev, "could not read EEPROM\n" ); |
1094 | return ETIMEDOUT; |
1095 | } |
1096 | *out++ = val >> 16; |
1097 | if (len > 1) |
1098 | *out++ = val >> 24; |
1099 | } |
1100 | wpi_mem_unlock(sc); |
1101 | |
1102 | return 0; |
1103 | } |
1104 | |
1105 | /* |
1106 | * The firmware boot code is small and is intended to be copied directly into |
1107 | * the NIC internal memory. |
1108 | */ |
1109 | int |
1110 | wpi_load_microcode(struct wpi_softc *sc, const uint8_t *ucode, int size) |
1111 | { |
1112 | int ntries; |
1113 | |
1114 | size /= sizeof (uint32_t); |
1115 | |
1116 | wpi_mem_lock(sc); |
1117 | |
1118 | /* copy microcode image into NIC memory */ |
1119 | wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, |
1120 | (const uint32_t *)ucode, size); |
1121 | |
1122 | wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0); |
1123 | wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT); |
1124 | wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size); |
1125 | |
1126 | /* run microcode */ |
1127 | wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); |
1128 | |
1129 | /* wait for transfer to complete */ |
1130 | for (ntries = 0; ntries < 1000; ntries++) { |
1131 | if (!(wpi_mem_read(sc, WPI_MEM_UCODE_CTL) & WPI_UC_RUN)) |
1132 | break; |
1133 | DELAY(10); |
1134 | } |
1135 | if (ntries == 1000) { |
1136 | wpi_mem_unlock(sc); |
1137 | aprint_error_dev(sc->sc_dev, "could not load boot firmware\n" ); |
1138 | return ETIMEDOUT; |
1139 | } |
1140 | wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_ENABLE); |
1141 | |
1142 | wpi_mem_unlock(sc); |
1143 | |
1144 | return 0; |
1145 | } |
1146 | |
1147 | static int |
1148 | wpi_cache_firmware(struct wpi_softc *sc) |
1149 | { |
1150 | const char *const fwname = wpi_firmware_name; |
1151 | firmware_handle_t fw; |
1152 | int error; |
1153 | |
1154 | /* sc is used here only to report error messages. */ |
1155 | |
1156 | mutex_enter(&wpi_firmware_mutex); |
1157 | |
1158 | if (wpi_firmware_users == SIZE_MAX) { |
1159 | mutex_exit(&wpi_firmware_mutex); |
1160 | return ENFILE; /* Too many of something in the system... */ |
1161 | } |
1162 | if (wpi_firmware_users++) { |
1163 | KASSERT(wpi_firmware_image != NULL); |
1164 | KASSERT(wpi_firmware_size > 0); |
1165 | mutex_exit(&wpi_firmware_mutex); |
1166 | return 0; /* Already good to go. */ |
1167 | } |
1168 | |
1169 | KASSERT(wpi_firmware_image == NULL); |
1170 | KASSERT(wpi_firmware_size == 0); |
1171 | |
1172 | /* load firmware image from disk */ |
1173 | if ((error = firmware_open("if_wpi" , fwname, &fw)) != 0) { |
1174 | aprint_error_dev(sc->sc_dev, |
1175 | "could not open firmware file %s: %d\n" , fwname, error); |
1176 | goto fail0; |
1177 | } |
1178 | |
1179 | wpi_firmware_size = firmware_get_size(fw); |
1180 | |
1181 | if (wpi_firmware_size > sizeof (struct wpi_firmware_hdr) + |
1182 | WPI_FW_MAIN_TEXT_MAXSZ + WPI_FW_MAIN_DATA_MAXSZ + |
1183 | WPI_FW_INIT_TEXT_MAXSZ + WPI_FW_INIT_DATA_MAXSZ + |
1184 | WPI_FW_BOOT_TEXT_MAXSZ) { |
1185 | aprint_error_dev(sc->sc_dev, |
1186 | "firmware file %s too large: %zu bytes\n" , |
1187 | fwname, wpi_firmware_size); |
1188 | error = EFBIG; |
1189 | goto fail1; |
1190 | } |
1191 | |
1192 | if (wpi_firmware_size < sizeof (struct wpi_firmware_hdr)) { |
1193 | aprint_error_dev(sc->sc_dev, |
1194 | "firmware file %s too small: %zu bytes\n" , |
1195 | fwname, wpi_firmware_size); |
1196 | error = EINVAL; |
1197 | goto fail1; |
1198 | } |
1199 | |
1200 | wpi_firmware_image = firmware_malloc(wpi_firmware_size); |
1201 | if (wpi_firmware_image == NULL) { |
1202 | aprint_error_dev(sc->sc_dev, |
1203 | "not enough memory for firmware file %s\n" , fwname); |
1204 | error = ENOMEM; |
1205 | goto fail1; |
1206 | } |
1207 | |
1208 | error = firmware_read(fw, 0, wpi_firmware_image, wpi_firmware_size); |
1209 | if (error != 0) { |
1210 | aprint_error_dev(sc->sc_dev, |
1211 | "error reading firmware file %s: %d\n" , fwname, error); |
1212 | goto fail2; |
1213 | } |
1214 | |
1215 | /* Success! */ |
1216 | firmware_close(fw); |
1217 | mutex_exit(&wpi_firmware_mutex); |
1218 | return 0; |
1219 | |
1220 | fail2: |
1221 | firmware_free(wpi_firmware_image, wpi_firmware_size); |
1222 | wpi_firmware_image = NULL; |
1223 | fail1: |
1224 | wpi_firmware_size = 0; |
1225 | firmware_close(fw); |
1226 | fail0: |
1227 | KASSERT(wpi_firmware_users == 1); |
1228 | wpi_firmware_users = 0; |
1229 | KASSERT(wpi_firmware_image == NULL); |
1230 | KASSERT(wpi_firmware_size == 0); |
1231 | |
1232 | mutex_exit(&wpi_firmware_mutex); |
1233 | return error; |
1234 | } |
1235 | |
1236 | static void |
1237 | wpi_release_firmware(void) |
1238 | { |
1239 | |
1240 | mutex_enter(&wpi_firmware_mutex); |
1241 | |
1242 | KASSERT(wpi_firmware_users > 0); |
1243 | KASSERT(wpi_firmware_image != NULL); |
1244 | KASSERT(wpi_firmware_size != 0); |
1245 | |
1246 | if (--wpi_firmware_users == 0) { |
1247 | firmware_free(wpi_firmware_image, wpi_firmware_size); |
1248 | wpi_firmware_image = NULL; |
1249 | wpi_firmware_size = 0; |
1250 | } |
1251 | |
1252 | mutex_exit(&wpi_firmware_mutex); |
1253 | } |
1254 | |
1255 | static int |
1256 | wpi_load_firmware(struct wpi_softc *sc) |
1257 | { |
1258 | struct wpi_dma_info *dma = &sc->fw_dma; |
1259 | struct wpi_firmware_hdr hdr; |
1260 | const uint8_t *init_text, *init_data, *main_text, *main_data; |
1261 | const uint8_t *boot_text; |
1262 | uint32_t init_textsz, init_datasz, main_textsz, main_datasz; |
1263 | uint32_t boot_textsz; |
1264 | size_t size; |
1265 | int error; |
1266 | |
1267 | if (!sc->fw_used) { |
1268 | if ((error = wpi_cache_firmware(sc)) != 0) |
1269 | return error; |
1270 | sc->fw_used = true; |
1271 | } |
1272 | |
1273 | KASSERT(sc->fw_used); |
1274 | KASSERT(wpi_firmware_image != NULL); |
1275 | KASSERT(wpi_firmware_size > sizeof(hdr)); |
1276 | |
1277 | memcpy(&hdr, wpi_firmware_image, sizeof(hdr)); |
1278 | |
1279 | main_textsz = le32toh(hdr.main_textsz); |
1280 | main_datasz = le32toh(hdr.main_datasz); |
1281 | init_textsz = le32toh(hdr.init_textsz); |
1282 | init_datasz = le32toh(hdr.init_datasz); |
1283 | boot_textsz = le32toh(hdr.boot_textsz); |
1284 | |
1285 | /* sanity-check firmware segments sizes */ |
1286 | if (main_textsz > WPI_FW_MAIN_TEXT_MAXSZ || |
1287 | main_datasz > WPI_FW_MAIN_DATA_MAXSZ || |
1288 | init_textsz > WPI_FW_INIT_TEXT_MAXSZ || |
1289 | init_datasz > WPI_FW_INIT_DATA_MAXSZ || |
1290 | boot_textsz > WPI_FW_BOOT_TEXT_MAXSZ || |
1291 | (boot_textsz & 3) != 0) { |
1292 | aprint_error_dev(sc->sc_dev, "invalid firmware header\n" ); |
1293 | error = EINVAL; |
1294 | goto free_firmware; |
1295 | } |
1296 | |
1297 | /* check that all firmware segments are present */ |
1298 | size = sizeof (struct wpi_firmware_hdr) + main_textsz + |
1299 | main_datasz + init_textsz + init_datasz + boot_textsz; |
1300 | if (wpi_firmware_size < size) { |
1301 | aprint_error_dev(sc->sc_dev, |
1302 | "firmware file truncated: %zu bytes, expected %zu bytes\n" , |
1303 | wpi_firmware_size, size); |
1304 | error = EINVAL; |
1305 | goto free_firmware; |
1306 | } |
1307 | |
1308 | /* get pointers to firmware segments */ |
1309 | main_text = wpi_firmware_image + sizeof (struct wpi_firmware_hdr); |
1310 | main_data = main_text + main_textsz; |
1311 | init_text = main_data + main_datasz; |
1312 | init_data = init_text + init_textsz; |
1313 | boot_text = init_data + init_datasz; |
1314 | |
1315 | /* copy initialization images into pre-allocated DMA-safe memory */ |
1316 | memcpy(dma->vaddr, init_data, init_datasz); |
1317 | memcpy((char *)dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, init_text, |
1318 | init_textsz); |
1319 | |
1320 | bus_dmamap_sync(dma->tag, dma->map, 0, dma->size, BUS_DMASYNC_PREWRITE); |
1321 | |
1322 | /* tell adapter where to find initialization images */ |
1323 | wpi_mem_lock(sc); |
1324 | wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); |
1325 | wpi_mem_write(sc, WPI_MEM_DATA_SIZE, init_datasz); |
1326 | wpi_mem_write(sc, WPI_MEM_TEXT_BASE, |
1327 | dma->paddr + WPI_FW_INIT_DATA_MAXSZ); |
1328 | wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, init_textsz); |
1329 | wpi_mem_unlock(sc); |
1330 | |
1331 | /* load firmware boot code */ |
1332 | if ((error = wpi_load_microcode(sc, boot_text, boot_textsz)) != 0) { |
1333 | aprint_error_dev(sc->sc_dev, "could not load boot firmware\n" ); |
1334 | return error; |
1335 | } |
1336 | |
1337 | /* now press "execute" ;-) */ |
1338 | WPI_WRITE(sc, WPI_RESET, 0); |
1339 | |
1340 | /* wait at most one second for first alive notification */ |
1341 | if ((error = tsleep(sc, PCATCH, "wpiinit" , hz)) != 0) { |
1342 | /* this isn't what was supposed to happen.. */ |
1343 | aprint_error_dev(sc->sc_dev, |
1344 | "timeout waiting for adapter to initialize\n" ); |
1345 | } |
1346 | |
1347 | /* copy runtime images into pre-allocated DMA-safe memory */ |
1348 | memcpy(dma->vaddr, main_data, main_datasz); |
1349 | memcpy((char *)dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, main_text, |
1350 | main_textsz); |
1351 | |
1352 | bus_dmamap_sync(dma->tag, dma->map, 0, dma->size, BUS_DMASYNC_PREWRITE); |
1353 | |
1354 | /* tell adapter where to find runtime images */ |
1355 | wpi_mem_lock(sc); |
1356 | wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); |
1357 | wpi_mem_write(sc, WPI_MEM_DATA_SIZE, main_datasz); |
1358 | wpi_mem_write(sc, WPI_MEM_TEXT_BASE, |
1359 | dma->paddr + WPI_FW_MAIN_DATA_MAXSZ); |
1360 | wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, WPI_FW_UPDATED | main_textsz); |
1361 | wpi_mem_unlock(sc); |
1362 | |
1363 | /* wait at most one second for second alive notification */ |
1364 | if ((error = tsleep(sc, PCATCH, "wpiinit" , hz)) != 0) { |
1365 | /* this isn't what was supposed to happen.. */ |
1366 | aprint_error_dev(sc->sc_dev, |
1367 | "timeout waiting for adapter to initialize\n" ); |
1368 | } |
1369 | |
1370 | return error; |
1371 | |
1372 | free_firmware: |
1373 | sc->fw_used = false; |
1374 | wpi_release_firmware(); |
1375 | return error; |
1376 | } |
1377 | |
1378 | static void |
1379 | wpi_calib_timeout(void *arg) |
1380 | { |
1381 | struct wpi_softc *sc = arg; |
1382 | struct ieee80211com *ic = &sc->sc_ic; |
1383 | int temp, s; |
1384 | |
1385 | /* automatic rate control triggered every 500ms */ |
1386 | if (ic->ic_fixed_rate == -1) { |
1387 | s = splnet(); |
1388 | if (ic->ic_opmode == IEEE80211_M_STA) |
1389 | wpi_iter_func(sc, ic->ic_bss); |
1390 | else |
1391 | ieee80211_iterate_nodes(&ic->ic_sta, wpi_iter_func, sc); |
1392 | splx(s); |
1393 | } |
1394 | |
1395 | /* update sensor data */ |
1396 | temp = (int)WPI_READ(sc, WPI_TEMPERATURE); |
1397 | |
1398 | /* automatic power calibration every 60s */ |
1399 | if (++sc->calib_cnt >= 120) { |
1400 | wpi_power_calibration(sc, temp); |
1401 | sc->calib_cnt = 0; |
1402 | } |
1403 | |
1404 | callout_schedule(&sc->calib_to, hz/2); |
1405 | } |
1406 | |
1407 | static void |
1408 | wpi_iter_func(void *arg, struct ieee80211_node *ni) |
1409 | { |
1410 | struct wpi_softc *sc = arg; |
1411 | struct wpi_node *wn = (struct wpi_node *)ni; |
1412 | |
1413 | ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn); |
1414 | } |
1415 | |
1416 | /* |
1417 | * This function is called periodically (every 60 seconds) to adjust output |
1418 | * power to temperature changes. |
1419 | */ |
1420 | void |
1421 | wpi_power_calibration(struct wpi_softc *sc, int temp) |
1422 | { |
1423 | /* sanity-check read value */ |
1424 | if (temp < -260 || temp > 25) { |
1425 | /* this can't be correct, ignore */ |
1426 | DPRINTF(("out-of-range temperature reported: %d\n" , temp)); |
1427 | return; |
1428 | } |
1429 | |
1430 | DPRINTF(("temperature %d->%d\n" , sc->temp, temp)); |
1431 | |
1432 | /* adjust Tx power if need be */ |
1433 | if (abs(temp - sc->temp) <= 6) |
1434 | return; |
1435 | |
1436 | sc->temp = temp; |
1437 | |
1438 | if (wpi_set_txpower(sc, sc->sc_ic.ic_curchan, 1) != 0) { |
1439 | /* just warn, too bad for the automatic calibration... */ |
1440 | aprint_error_dev(sc->sc_dev, "could not adjust Tx power\n" ); |
1441 | } |
1442 | } |
1443 | |
1444 | static void |
1445 | wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc, |
1446 | struct wpi_rx_data *data) |
1447 | { |
1448 | struct ieee80211com *ic = &sc->sc_ic; |
1449 | struct ifnet *ifp = ic->ic_ifp; |
1450 | struct wpi_rx_ring *ring = &sc->rxq; |
1451 | struct wpi_rx_stat *stat; |
1452 | struct wpi_rx_head *head; |
1453 | struct wpi_rx_tail *tail; |
1454 | struct wpi_rbuf *rbuf; |
1455 | struct ieee80211_frame *wh; |
1456 | struct ieee80211_node *ni; |
1457 | struct mbuf *m, *mnew; |
1458 | int data_off, error; |
1459 | |
1460 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, |
1461 | BUS_DMASYNC_POSTREAD); |
1462 | stat = (struct wpi_rx_stat *)(desc + 1); |
1463 | |
1464 | if (stat->len > WPI_STAT_MAXLEN) { |
1465 | aprint_error_dev(sc->sc_dev, "invalid rx statistic header\n" ); |
1466 | ifp->if_ierrors++; |
1467 | return; |
1468 | } |
1469 | |
1470 | head = (struct wpi_rx_head *)((char *)(stat + 1) + stat->len); |
1471 | tail = (struct wpi_rx_tail *)((char *)(head + 1) + le16toh(head->len)); |
1472 | |
1473 | DPRINTFN(4, ("rx intr: idx=%d len=%d stat len=%d rssi=%d rate=%x " |
1474 | "chan=%d tstamp=%" PRIu64 "\n" , ring->cur, le32toh(desc->len), |
1475 | le16toh(head->len), (int8_t)stat->rssi, head->rate, head->chan, |
1476 | le64toh(tail->tstamp))); |
1477 | |
1478 | /* |
1479 | * Discard Rx frames with bad CRC early (XXX we may want to pass them |
1480 | * to radiotap in monitor mode). |
1481 | */ |
1482 | if ((le32toh(tail->flags) & WPI_RX_NOERROR) != WPI_RX_NOERROR) { |
1483 | DPRINTF(("rx tail flags error %x\n" , |
1484 | le32toh(tail->flags))); |
1485 | ifp->if_ierrors++; |
1486 | return; |
1487 | } |
1488 | |
1489 | /* Compute where are the useful datas */ |
1490 | data_off = (char*)(head + 1) - mtod(data->m, char*); |
1491 | |
1492 | MGETHDR(mnew, M_DONTWAIT, MT_DATA); |
1493 | if (mnew == NULL) { |
1494 | ifp->if_ierrors++; |
1495 | return; |
1496 | } |
1497 | |
1498 | rbuf = wpi_alloc_rbuf(sc); |
1499 | if (rbuf == NULL) { |
1500 | m_freem(mnew); |
1501 | ifp->if_ierrors++; |
1502 | return; |
1503 | } |
1504 | |
1505 | /* attach Rx buffer to mbuf */ |
1506 | MEXTADD(mnew, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, |
1507 | rbuf); |
1508 | mnew->m_flags |= M_EXT_RW; |
1509 | |
1510 | bus_dmamap_unload(sc->sc_dmat, data->map); |
1511 | |
1512 | error = bus_dmamap_load(sc->sc_dmat, data->map, |
1513 | mtod(mnew, void *), WPI_RBUF_SIZE, NULL, |
1514 | BUS_DMA_NOWAIT | BUS_DMA_READ); |
1515 | if (error) { |
1516 | device_printf(sc->sc_dev, |
1517 | "couldn't load rx mbuf: %d\n" , error); |
1518 | m_freem(mnew); |
1519 | ifp->if_ierrors++; |
1520 | |
1521 | error = bus_dmamap_load(sc->sc_dmat, data->map, |
1522 | mtod(data->m, void *), WPI_RBUF_SIZE, NULL, |
1523 | BUS_DMA_NOWAIT | BUS_DMA_READ); |
1524 | if (error) |
1525 | panic("%s: bus_dmamap_load failed: %d\n" , |
1526 | device_xname(sc->sc_dev), error); |
1527 | return; |
1528 | } |
1529 | |
1530 | /* new mbuf loaded successfully */ |
1531 | m = data->m; |
1532 | data->m = mnew; |
1533 | |
1534 | /* update Rx descriptor */ |
1535 | ring->desc[ring->cur] = htole32(rbuf->paddr); |
1536 | bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, |
1537 | ring->desc_dma.size, |
1538 | BUS_DMASYNC_PREWRITE); |
1539 | |
1540 | m->m_data = (char*)m->m_data + data_off; |
1541 | m->m_pkthdr.len = m->m_len = le16toh(head->len); |
1542 | |
1543 | /* finalize mbuf */ |
1544 | m_set_rcvif(m, ifp); |
1545 | |
1546 | if (sc->sc_drvbpf != NULL) { |
1547 | struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; |
1548 | |
1549 | tap->wr_flags = 0; |
1550 | tap->wr_chan_freq = |
1551 | htole16(ic->ic_channels[head->chan].ic_freq); |
1552 | tap->wr_chan_flags = |
1553 | htole16(ic->ic_channels[head->chan].ic_flags); |
1554 | tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET); |
1555 | tap->wr_dbm_antnoise = (int8_t)le16toh(stat->noise); |
1556 | tap->wr_tsft = tail->tstamp; |
1557 | tap->wr_antenna = (le16toh(head->flags) >> 4) & 0xf; |
1558 | switch (head->rate) { |
1559 | /* CCK rates */ |
1560 | case 10: tap->wr_rate = 2; break; |
1561 | case 20: tap->wr_rate = 4; break; |
1562 | case 55: tap->wr_rate = 11; break; |
1563 | case 110: tap->wr_rate = 22; break; |
1564 | /* OFDM rates */ |
1565 | case 0xd: tap->wr_rate = 12; break; |
1566 | case 0xf: tap->wr_rate = 18; break; |
1567 | case 0x5: tap->wr_rate = 24; break; |
1568 | case 0x7: tap->wr_rate = 36; break; |
1569 | case 0x9: tap->wr_rate = 48; break; |
1570 | case 0xb: tap->wr_rate = 72; break; |
1571 | case 0x1: tap->wr_rate = 96; break; |
1572 | case 0x3: tap->wr_rate = 108; break; |
1573 | /* unknown rate: should not happen */ |
1574 | default: tap->wr_rate = 0; |
1575 | } |
1576 | if (le16toh(head->flags) & 0x4) |
1577 | tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; |
1578 | |
1579 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); |
1580 | } |
1581 | |
1582 | /* grab a reference to the source node */ |
1583 | wh = mtod(m, struct ieee80211_frame *); |
1584 | ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); |
1585 | |
1586 | /* send the frame to the 802.11 layer */ |
1587 | ieee80211_input(ic, m, ni, stat->rssi, 0); |
1588 | |
1589 | /* release node reference */ |
1590 | ieee80211_free_node(ni); |
1591 | } |
1592 | |
1593 | static void |
1594 | wpi_tx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) |
1595 | { |
1596 | struct ifnet *ifp = sc->sc_ic.ic_ifp; |
1597 | struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; |
1598 | struct wpi_tx_data *data = &ring->data[desc->idx]; |
1599 | struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); |
1600 | struct wpi_node *wn = (struct wpi_node *)data->ni; |
1601 | |
1602 | DPRINTFN(4, ("tx done: qid=%d idx=%d retries=%d nkill=%d rate=%x " |
1603 | "duration=%d status=%x\n" , desc->qid, desc->idx, stat->ntries, |
1604 | stat->nkill, stat->rate, le32toh(stat->duration), |
1605 | le32toh(stat->status))); |
1606 | |
1607 | /* |
1608 | * Update rate control statistics for the node. |
1609 | * XXX we should not count mgmt frames since they're always sent at |
1610 | * the lowest available bit-rate. |
1611 | */ |
1612 | wn->amn.amn_txcnt++; |
1613 | if (stat->ntries > 0) { |
1614 | DPRINTFN(3, ("tx intr ntries %d\n" , stat->ntries)); |
1615 | wn->amn.amn_retrycnt++; |
1616 | } |
1617 | |
1618 | if ((le32toh(stat->status) & 0xff) != 1) |
1619 | ifp->if_oerrors++; |
1620 | else |
1621 | ifp->if_opackets++; |
1622 | |
1623 | bus_dmamap_unload(sc->sc_dmat, data->map); |
1624 | m_freem(data->m); |
1625 | data->m = NULL; |
1626 | ieee80211_free_node(data->ni); |
1627 | data->ni = NULL; |
1628 | |
1629 | ring->queued--; |
1630 | |
1631 | sc->sc_tx_timer = 0; |
1632 | ifp->if_flags &= ~IFF_OACTIVE; |
1633 | wpi_start(ifp); |
1634 | } |
1635 | |
1636 | static void |
1637 | wpi_cmd_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) |
1638 | { |
1639 | struct wpi_tx_ring *ring = &sc->cmdq; |
1640 | struct wpi_tx_data *data; |
1641 | |
1642 | if ((desc->qid & 7) != 4) |
1643 | return; /* not a command ack */ |
1644 | |
1645 | data = &ring->data[desc->idx]; |
1646 | |
1647 | /* if the command was mapped in a mbuf, free it */ |
1648 | if (data->m != NULL) { |
1649 | bus_dmamap_unload(sc->sc_dmat, data->map); |
1650 | m_freem(data->m); |
1651 | data->m = NULL; |
1652 | } |
1653 | |
1654 | wakeup(&ring->cmd[desc->idx]); |
1655 | } |
1656 | |
1657 | static void |
1658 | wpi_notif_intr(struct wpi_softc *sc) |
1659 | { |
1660 | struct ieee80211com *ic = &sc->sc_ic; |
1661 | struct ifnet *ifp = ic->ic_ifp; |
1662 | uint32_t hw; |
1663 | |
1664 | bus_dmamap_sync(sc->sc_dmat, sc->shared_dma.map, 0, |
1665 | sizeof(struct wpi_shared), BUS_DMASYNC_POSTREAD); |
1666 | |
1667 | hw = le32toh(sc->shared->next); |
1668 | while (sc->rxq.cur != hw) { |
1669 | struct wpi_rx_data *data = &sc->rxq.data[sc->rxq.cur]; |
1670 | struct wpi_rx_desc *desc; |
1671 | |
1672 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, |
1673 | BUS_DMASYNC_POSTREAD); |
1674 | desc = mtod(data->m, struct wpi_rx_desc *); |
1675 | |
1676 | DPRINTFN(4, ("rx notification qid=%x idx=%d flags=%x type=%d " |
1677 | "len=%d\n" , desc->qid, desc->idx, desc->flags, |
1678 | desc->type, le32toh(desc->len))); |
1679 | |
1680 | if (!(desc->qid & 0x80)) /* reply to a command */ |
1681 | wpi_cmd_intr(sc, desc); |
1682 | |
1683 | switch (desc->type) { |
1684 | case WPI_RX_DONE: |
1685 | /* a 802.11 frame was received */ |
1686 | wpi_rx_intr(sc, desc, data); |
1687 | break; |
1688 | |
1689 | case WPI_TX_DONE: |
1690 | /* a 802.11 frame has been transmitted */ |
1691 | wpi_tx_intr(sc, desc); |
1692 | break; |
1693 | |
1694 | case WPI_UC_READY: |
1695 | { |
1696 | struct wpi_ucode_info *uc = |
1697 | (struct wpi_ucode_info *)(desc + 1); |
1698 | |
1699 | /* the microcontroller is ready */ |
1700 | DPRINTF(("microcode alive notification version %x " |
1701 | "alive %x\n" , le32toh(uc->version), |
1702 | le32toh(uc->valid))); |
1703 | |
1704 | if (le32toh(uc->valid) != 1) { |
1705 | aprint_error_dev(sc->sc_dev, |
1706 | "microcontroller initialization failed\n" ); |
1707 | } |
1708 | break; |
1709 | } |
1710 | case WPI_STATE_CHANGED: |
1711 | { |
1712 | uint32_t *status = (uint32_t *)(desc + 1); |
1713 | |
1714 | /* enabled/disabled notification */ |
1715 | DPRINTF(("state changed to %x\n" , le32toh(*status))); |
1716 | |
1717 | if (le32toh(*status) & 1) { |
1718 | /* the radio button has to be pushed */ |
1719 | /* wake up thread to signal powerd */ |
1720 | cv_signal(&sc->sc_rsw_cv); |
1721 | aprint_error_dev(sc->sc_dev, |
1722 | "Radio transmitter is off\n" ); |
1723 | /* turn the interface down */ |
1724 | ifp->if_flags &= ~IFF_UP; |
1725 | wpi_stop(ifp, 1); |
1726 | return; /* no further processing */ |
1727 | } |
1728 | break; |
1729 | } |
1730 | case WPI_START_SCAN: |
1731 | { |
1732 | #if 0 |
1733 | struct wpi_start_scan *scan = |
1734 | (struct wpi_start_scan *)(desc + 1); |
1735 | |
1736 | DPRINTFN(2, ("scanning channel %d status %x\n" , |
1737 | scan->chan, le32toh(scan->status))); |
1738 | |
1739 | /* fix current channel */ |
1740 | ic->ic_curchan = &ic->ic_channels[scan->chan]; |
1741 | #endif |
1742 | break; |
1743 | } |
1744 | case WPI_STOP_SCAN: |
1745 | { |
1746 | #ifdef WPI_DEBUG |
1747 | struct wpi_stop_scan *scan = |
1748 | (struct wpi_stop_scan *)(desc + 1); |
1749 | #endif |
1750 | |
1751 | DPRINTF(("scan finished nchan=%d status=%d chan=%d\n" , |
1752 | scan->nchan, scan->status, scan->chan)); |
1753 | |
1754 | sc->is_scanning = false; |
1755 | if (ic->ic_state == IEEE80211_S_SCAN) |
1756 | ieee80211_next_scan(ic); |
1757 | |
1758 | break; |
1759 | } |
1760 | } |
1761 | |
1762 | sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT; |
1763 | } |
1764 | |
1765 | /* tell the firmware what we have processed */ |
1766 | hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; |
1767 | WPI_WRITE(sc, WPI_RX_WIDX, hw & ~7); |
1768 | } |
1769 | |
1770 | static int |
1771 | wpi_intr(void *arg) |
1772 | { |
1773 | struct wpi_softc *sc = arg; |
1774 | struct ifnet *ifp = sc->sc_ic.ic_ifp; |
1775 | uint32_t r; |
1776 | |
1777 | r = WPI_READ(sc, WPI_INTR); |
1778 | if (r == 0 || r == 0xffffffff) |
1779 | return 0; /* not for us */ |
1780 | |
1781 | DPRINTFN(6, ("interrupt reg %x\n" , r)); |
1782 | |
1783 | /* disable interrupts */ |
1784 | WPI_WRITE(sc, WPI_MASK, 0); |
1785 | /* ack interrupts */ |
1786 | WPI_WRITE(sc, WPI_INTR, r); |
1787 | |
1788 | if (r & (WPI_SW_ERROR | WPI_HW_ERROR)) { |
1789 | /* SYSTEM FAILURE, SYSTEM FAILURE */ |
1790 | aprint_error_dev(sc->sc_dev, "fatal firmware error\n" ); |
1791 | ifp->if_flags &= ~IFF_UP; |
1792 | wpi_stop(ifp, 1); |
1793 | return 1; |
1794 | } |
1795 | |
1796 | if (r & WPI_RX_INTR) |
1797 | wpi_notif_intr(sc); |
1798 | |
1799 | if (r & WPI_ALIVE_INTR) /* firmware initialized */ |
1800 | wakeup(sc); |
1801 | |
1802 | /* re-enable interrupts */ |
1803 | if (ifp->if_flags & IFF_UP) |
1804 | WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); |
1805 | |
1806 | return 1; |
1807 | } |
1808 | |
1809 | static uint8_t |
1810 | wpi_plcp_signal(int rate) |
1811 | { |
1812 | switch (rate) { |
1813 | /* CCK rates (returned values are device-dependent) */ |
1814 | case 2: return 10; |
1815 | case 4: return 20; |
1816 | case 11: return 55; |
1817 | case 22: return 110; |
1818 | |
1819 | /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ |
1820 | /* R1-R4, (u)ral is R4-R1 */ |
1821 | case 12: return 0xd; |
1822 | case 18: return 0xf; |
1823 | case 24: return 0x5; |
1824 | case 36: return 0x7; |
1825 | case 48: return 0x9; |
1826 | case 72: return 0xb; |
1827 | case 96: return 0x1; |
1828 | case 108: return 0x3; |
1829 | |
1830 | /* unsupported rates (should not get there) */ |
1831 | default: return 0; |
1832 | } |
1833 | } |
1834 | |
1835 | /* quickly determine if a given rate is CCK or OFDM */ |
1836 | #define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) |
1837 | |
1838 | static int |
1839 | wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, |
1840 | int ac) |
1841 | { |
1842 | struct ieee80211com *ic = &sc->sc_ic; |
1843 | struct wpi_tx_ring *ring = &sc->txq[ac]; |
1844 | struct wpi_tx_desc *desc; |
1845 | struct wpi_tx_data *data; |
1846 | struct wpi_tx_cmd *cmd; |
1847 | struct wpi_cmd_data *tx; |
1848 | struct ieee80211_frame *wh; |
1849 | struct ieee80211_key *k; |
1850 | const struct chanAccParams *cap; |
1851 | struct mbuf *mnew; |
1852 | int i, rate, error, hdrlen, noack = 0; |
1853 | |
1854 | desc = &ring->desc[ring->cur]; |
1855 | data = &ring->data[ring->cur]; |
1856 | |
1857 | wh = mtod(m0, struct ieee80211_frame *); |
1858 | |
1859 | if (ieee80211_has_qos(wh)) { |
1860 | cap = &ic->ic_wme.wme_chanParams; |
1861 | noack = cap->cap_wmeParams[ac].wmep_noackPolicy; |
1862 | } |
1863 | |
1864 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { |
1865 | k = ieee80211_crypto_encap(ic, ni, m0); |
1866 | if (k == NULL) { |
1867 | m_freem(m0); |
1868 | return ENOBUFS; |
1869 | } |
1870 | |
1871 | /* packet header may have moved, reset our local pointer */ |
1872 | wh = mtod(m0, struct ieee80211_frame *); |
1873 | } |
1874 | |
1875 | hdrlen = ieee80211_anyhdrsize(wh); |
1876 | |
1877 | /* pickup a rate */ |
1878 | if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == |
1879 | IEEE80211_FC0_TYPE_MGT) { |
1880 | /* mgmt frames are sent at the lowest available bit-rate */ |
1881 | rate = ni->ni_rates.rs_rates[0]; |
1882 | } else { |
1883 | if (ic->ic_fixed_rate != -1) { |
1884 | rate = ic->ic_sup_rates[ic->ic_curmode]. |
1885 | rs_rates[ic->ic_fixed_rate]; |
1886 | } else |
1887 | rate = ni->ni_rates.rs_rates[ni->ni_txrate]; |
1888 | } |
1889 | rate &= IEEE80211_RATE_VAL; |
1890 | |
1891 | if (sc->sc_drvbpf != NULL) { |
1892 | struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; |
1893 | |
1894 | tap->wt_flags = 0; |
1895 | tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); |
1896 | tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); |
1897 | tap->wt_rate = rate; |
1898 | tap->wt_hwqueue = ac; |
1899 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) |
1900 | tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; |
1901 | |
1902 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); |
1903 | } |
1904 | |
1905 | cmd = &ring->cmd[ring->cur]; |
1906 | cmd->code = WPI_CMD_TX_DATA; |
1907 | cmd->flags = 0; |
1908 | cmd->qid = ring->qid; |
1909 | cmd->idx = ring->cur; |
1910 | |
1911 | tx = (struct wpi_cmd_data *)cmd->data; |
1912 | /* no need to zero tx, all fields are reinitialized here */ |
1913 | tx->flags = 0; |
1914 | |
1915 | if (!noack && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { |
1916 | tx->flags |= htole32(WPI_TX_NEED_ACK); |
1917 | } else if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) |
1918 | tx->flags |= htole32(WPI_TX_NEED_RTS | WPI_TX_FULL_TXOP); |
1919 | |
1920 | tx->flags |= htole32(WPI_TX_AUTO_SEQ); |
1921 | |
1922 | /* retrieve destination node's id */ |
1923 | tx->id = IEEE80211_IS_MULTICAST(wh->i_addr1) ? WPI_ID_BROADCAST : |
1924 | WPI_ID_BSS; |
1925 | |
1926 | if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == |
1927 | IEEE80211_FC0_TYPE_MGT) { |
1928 | /* tell h/w to set timestamp in probe responses */ |
1929 | if ((wh->i_fc[0] & |
1930 | (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == |
1931 | (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) |
1932 | tx->flags |= htole32(WPI_TX_INSERT_TSTAMP); |
1933 | |
1934 | if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == |
1935 | IEEE80211_FC0_SUBTYPE_ASSOC_REQ) || |
1936 | ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == |
1937 | IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) |
1938 | tx->timeout = htole16(3); |
1939 | else |
1940 | tx->timeout = htole16(2); |
1941 | } else |
1942 | tx->timeout = htole16(0); |
1943 | |
1944 | tx->rate = wpi_plcp_signal(rate); |
1945 | |
1946 | /* be very persistant at sending frames out */ |
1947 | tx->rts_ntries = 7; |
1948 | tx->data_ntries = 15; |
1949 | |
1950 | tx->ofdm_mask = 0xff; |
1951 | tx->cck_mask = 0x0f; |
1952 | tx->lifetime = htole32(WPI_LIFETIME_INFINITE); |
1953 | |
1954 | tx->len = htole16(m0->m_pkthdr.len); |
1955 | |
1956 | /* save and trim IEEE802.11 header */ |
1957 | memcpy((uint8_t *)(tx + 1), wh, hdrlen); |
1958 | m_adj(m0, hdrlen); |
1959 | |
1960 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, |
1961 | BUS_DMA_WRITE | BUS_DMA_NOWAIT); |
1962 | if (error != 0 && error != EFBIG) { |
1963 | aprint_error_dev(sc->sc_dev, "could not map mbuf (error %d)\n" , |
1964 | error); |
1965 | m_freem(m0); |
1966 | return error; |
1967 | } |
1968 | if (error != 0) { |
1969 | /* too many fragments, linearize */ |
1970 | |
1971 | MGETHDR(mnew, M_DONTWAIT, MT_DATA); |
1972 | if (mnew == NULL) { |
1973 | m_freem(m0); |
1974 | return ENOMEM; |
1975 | } |
1976 | M_COPY_PKTHDR(mnew, m0); |
1977 | if (m0->m_pkthdr.len > MHLEN) { |
1978 | MCLGET(mnew, M_DONTWAIT); |
1979 | if (!(mnew->m_flags & M_EXT)) { |
1980 | m_freem(m0); |
1981 | m_freem(mnew); |
1982 | return ENOMEM; |
1983 | } |
1984 | } |
1985 | |
1986 | m_copydata(m0, 0, m0->m_pkthdr.len, mtod(mnew, void *)); |
1987 | m_freem(m0); |
1988 | mnew->m_len = mnew->m_pkthdr.len; |
1989 | m0 = mnew; |
1990 | |
1991 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, |
1992 | BUS_DMA_WRITE | BUS_DMA_NOWAIT); |
1993 | if (error != 0) { |
1994 | aprint_error_dev(sc->sc_dev, |
1995 | "could not map mbuf (error %d)\n" , error); |
1996 | m_freem(m0); |
1997 | return error; |
1998 | } |
1999 | } |
2000 | |
2001 | data->m = m0; |
2002 | data->ni = ni; |
2003 | |
2004 | DPRINTFN(4, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n" , |
2005 | ring->qid, ring->cur, m0->m_pkthdr.len, data->map->dm_nsegs)); |
2006 | |
2007 | /* first scatter/gather segment is used by the tx data command */ |
2008 | desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | |
2009 | (1 + data->map->dm_nsegs) << 24); |
2010 | desc->segs[0].addr = htole32(ring->cmd_dma.paddr + |
2011 | ring->cur * sizeof (struct wpi_tx_cmd)); |
2012 | desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_data) + |
2013 | ((hdrlen + 3) & ~3)); |
2014 | for (i = 1; i <= data->map->dm_nsegs; i++) { |
2015 | desc->segs[i].addr = |
2016 | htole32(data->map->dm_segs[i - 1].ds_addr); |
2017 | desc->segs[i].len = |
2018 | htole32(data->map->dm_segs[i - 1].ds_len); |
2019 | } |
2020 | |
2021 | ring->queued++; |
2022 | |
2023 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, |
2024 | data->map->dm_mapsize, |
2025 | BUS_DMASYNC_PREWRITE); |
2026 | bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, 0, |
2027 | ring->cmd_dma.size, |
2028 | BUS_DMASYNC_PREWRITE); |
2029 | bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, |
2030 | ring->desc_dma.size, |
2031 | BUS_DMASYNC_PREWRITE); |
2032 | |
2033 | /* kick ring */ |
2034 | ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; |
2035 | WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); |
2036 | |
2037 | return 0; |
2038 | } |
2039 | |
2040 | static void |
2041 | wpi_start(struct ifnet *ifp) |
2042 | { |
2043 | struct wpi_softc *sc = ifp->if_softc; |
2044 | struct ieee80211com *ic = &sc->sc_ic; |
2045 | struct ieee80211_node *ni; |
2046 | struct ether_header *eh; |
2047 | struct mbuf *m0; |
2048 | int ac; |
2049 | |
2050 | /* |
2051 | * net80211 may still try to send management frames even if the |
2052 | * IFF_RUNNING flag is not set... |
2053 | */ |
2054 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) |
2055 | return; |
2056 | |
2057 | for (;;) { |
2058 | IF_DEQUEUE(&ic->ic_mgtq, m0); |
2059 | if (m0 != NULL) { |
2060 | |
2061 | ni = M_GETCTX(m0, struct ieee80211_node *); |
2062 | M_CLEARCTX(m0); |
2063 | |
2064 | /* management frames go into ring 0 */ |
2065 | if (sc->txq[0].queued > sc->txq[0].count - 8) { |
2066 | ifp->if_oerrors++; |
2067 | continue; |
2068 | } |
2069 | bpf_mtap3(ic->ic_rawbpf, m0); |
2070 | if (wpi_tx_data(sc, m0, ni, 0) != 0) { |
2071 | ifp->if_oerrors++; |
2072 | break; |
2073 | } |
2074 | } else { |
2075 | if (ic->ic_state != IEEE80211_S_RUN) |
2076 | break; |
2077 | IFQ_POLL(&ifp->if_snd, m0); |
2078 | if (m0 == NULL) |
2079 | break; |
2080 | |
2081 | if (m0->m_len < sizeof (*eh) && |
2082 | (m0 = m_pullup(m0, sizeof (*eh))) == NULL) { |
2083 | ifp->if_oerrors++; |
2084 | continue; |
2085 | } |
2086 | eh = mtod(m0, struct ether_header *); |
2087 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); |
2088 | if (ni == NULL) { |
2089 | m_freem(m0); |
2090 | ifp->if_oerrors++; |
2091 | continue; |
2092 | } |
2093 | |
2094 | /* classify mbuf so we can find which tx ring to use */ |
2095 | if (ieee80211_classify(ic, m0, ni) != 0) { |
2096 | m_freem(m0); |
2097 | ieee80211_free_node(ni); |
2098 | ifp->if_oerrors++; |
2099 | continue; |
2100 | } |
2101 | |
2102 | /* no QoS encapsulation for EAPOL frames */ |
2103 | ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? |
2104 | M_WME_GETAC(m0) : WME_AC_BE; |
2105 | |
2106 | if (sc->txq[ac].queued > sc->txq[ac].count - 8) { |
2107 | /* there is no place left in this ring */ |
2108 | ifp->if_flags |= IFF_OACTIVE; |
2109 | break; |
2110 | } |
2111 | IFQ_DEQUEUE(&ifp->if_snd, m0); |
2112 | bpf_mtap(ifp, m0); |
2113 | m0 = ieee80211_encap(ic, m0, ni); |
2114 | if (m0 == NULL) { |
2115 | ieee80211_free_node(ni); |
2116 | ifp->if_oerrors++; |
2117 | continue; |
2118 | } |
2119 | bpf_mtap3(ic->ic_rawbpf, m0); |
2120 | if (wpi_tx_data(sc, m0, ni, ac) != 0) { |
2121 | ieee80211_free_node(ni); |
2122 | ifp->if_oerrors++; |
2123 | break; |
2124 | } |
2125 | } |
2126 | |
2127 | sc->sc_tx_timer = 5; |
2128 | ifp->if_timer = 1; |
2129 | } |
2130 | } |
2131 | |
2132 | static void |
2133 | wpi_watchdog(struct ifnet *ifp) |
2134 | { |
2135 | struct wpi_softc *sc = ifp->if_softc; |
2136 | |
2137 | ifp->if_timer = 0; |
2138 | |
2139 | if (sc->sc_tx_timer > 0) { |
2140 | if (--sc->sc_tx_timer == 0) { |
2141 | aprint_error_dev(sc->sc_dev, "device timeout\n" ); |
2142 | ifp->if_flags &= ~IFF_UP; |
2143 | wpi_stop(ifp, 1); |
2144 | ifp->if_oerrors++; |
2145 | return; |
2146 | } |
2147 | ifp->if_timer = 1; |
2148 | } |
2149 | |
2150 | ieee80211_watchdog(&sc->sc_ic); |
2151 | } |
2152 | |
2153 | static int |
2154 | wpi_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
2155 | { |
2156 | #define IS_RUNNING(ifp) \ |
2157 | ((ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) |
2158 | |
2159 | struct wpi_softc *sc = ifp->if_softc; |
2160 | struct ieee80211com *ic = &sc->sc_ic; |
2161 | int s, error = 0; |
2162 | |
2163 | s = splnet(); |
2164 | |
2165 | switch (cmd) { |
2166 | case SIOCSIFFLAGS: |
2167 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
2168 | break; |
2169 | if (ifp->if_flags & IFF_UP) { |
2170 | if (!(ifp->if_flags & IFF_RUNNING)) |
2171 | wpi_init(ifp); |
2172 | } else { |
2173 | if (ifp->if_flags & IFF_RUNNING) |
2174 | wpi_stop(ifp, 1); |
2175 | } |
2176 | break; |
2177 | |
2178 | case SIOCADDMULTI: |
2179 | case SIOCDELMULTI: |
2180 | /* XXX no h/w multicast filter? --dyoung */ |
2181 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { |
2182 | /* setup multicast filter, etc */ |
2183 | error = 0; |
2184 | } |
2185 | break; |
2186 | |
2187 | default: |
2188 | error = ieee80211_ioctl(ic, cmd, data); |
2189 | } |
2190 | |
2191 | if (error == ENETRESET) { |
2192 | if (IS_RUNNING(ifp) && |
2193 | (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)) |
2194 | wpi_init(ifp); |
2195 | error = 0; |
2196 | } |
2197 | |
2198 | splx(s); |
2199 | return error; |
2200 | |
2201 | #undef IS_RUNNING |
2202 | } |
2203 | |
2204 | /* |
2205 | * Extract various information from EEPROM. |
2206 | */ |
2207 | static void |
2208 | wpi_read_eeprom(struct wpi_softc *sc) |
2209 | { |
2210 | struct ieee80211com *ic = &sc->sc_ic; |
2211 | char domain[4]; |
2212 | int i; |
2213 | |
2214 | wpi_read_prom_data(sc, WPI_EEPROM_CAPABILITIES, &sc->cap, 1); |
2215 | wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev, 2); |
2216 | wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, 1); |
2217 | |
2218 | DPRINTF(("cap=%x rev=%x type=%x\n" , sc->cap, le16toh(sc->rev), |
2219 | sc->type)); |
2220 | |
2221 | /* read and print regulatory domain */ |
2222 | wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, domain, 4); |
2223 | aprint_normal_dev(sc->sc_dev, "%.4s" , domain); |
2224 | |
2225 | /* read and print MAC address */ |
2226 | wpi_read_prom_data(sc, WPI_EEPROM_MAC, ic->ic_myaddr, 6); |
2227 | aprint_normal(", address %s\n" , ether_sprintf(ic->ic_myaddr)); |
2228 | |
2229 | /* read the list of authorized channels */ |
2230 | for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++) |
2231 | wpi_read_eeprom_channels(sc, i); |
2232 | |
2233 | /* read the list of power groups */ |
2234 | for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++) |
2235 | wpi_read_eeprom_group(sc, i); |
2236 | } |
2237 | |
2238 | static void |
2239 | wpi_read_eeprom_channels(struct wpi_softc *sc, int n) |
2240 | { |
2241 | struct ieee80211com *ic = &sc->sc_ic; |
2242 | const struct wpi_chan_band *band = &wpi_bands[n]; |
2243 | struct wpi_eeprom_chan channels[WPI_MAX_CHAN_PER_BAND]; |
2244 | int chan, i; |
2245 | |
2246 | wpi_read_prom_data(sc, band->addr, channels, |
2247 | band->nchan * sizeof (struct wpi_eeprom_chan)); |
2248 | |
2249 | for (i = 0; i < band->nchan; i++) { |
2250 | if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) |
2251 | continue; |
2252 | |
2253 | chan = band->chan[i]; |
2254 | |
2255 | if (n == 0) { /* 2GHz band */ |
2256 | ic->ic_channels[chan].ic_freq = |
2257 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); |
2258 | ic->ic_channels[chan].ic_flags = |
2259 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | |
2260 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; |
2261 | |
2262 | } else { /* 5GHz band */ |
2263 | /* |
2264 | * Some 3945ABG adapters support channels 7, 8, 11 |
2265 | * and 12 in the 2GHz *and* 5GHz bands. |
2266 | * Because of limitations in our net80211(9) stack, |
2267 | * we can't support these channels in 5GHz band. |
2268 | */ |
2269 | if (chan <= 14) |
2270 | continue; |
2271 | |
2272 | ic->ic_channels[chan].ic_freq = |
2273 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); |
2274 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; |
2275 | } |
2276 | |
2277 | /* is active scan allowed on this channel? */ |
2278 | if (!(channels[i].flags & WPI_EEPROM_CHAN_ACTIVE)) { |
2279 | ic->ic_channels[chan].ic_flags |= |
2280 | IEEE80211_CHAN_PASSIVE; |
2281 | } |
2282 | |
2283 | /* save maximum allowed power for this channel */ |
2284 | sc->maxpwr[chan] = channels[i].maxpwr; |
2285 | |
2286 | DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n" , |
2287 | chan, channels[i].flags, sc->maxpwr[chan])); |
2288 | } |
2289 | } |
2290 | |
2291 | static void |
2292 | wpi_read_eeprom_group(struct wpi_softc *sc, int n) |
2293 | { |
2294 | struct wpi_power_group *group = &sc->groups[n]; |
2295 | struct wpi_eeprom_group rgroup; |
2296 | int i; |
2297 | |
2298 | wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, &rgroup, |
2299 | sizeof rgroup); |
2300 | |
2301 | /* save power group information */ |
2302 | group->chan = rgroup.chan; |
2303 | group->maxpwr = rgroup.maxpwr; |
2304 | /* temperature at which the samples were taken */ |
2305 | group->temp = (int16_t)le16toh(rgroup.temp); |
2306 | |
2307 | DPRINTF(("power group %d: chan=%d maxpwr=%d temp=%d\n" , n, |
2308 | group->chan, group->maxpwr, group->temp)); |
2309 | |
2310 | for (i = 0; i < WPI_SAMPLES_COUNT; i++) { |
2311 | group->samples[i].index = rgroup.samples[i].index; |
2312 | group->samples[i].power = rgroup.samples[i].power; |
2313 | |
2314 | DPRINTF(("\tsample %d: index=%d power=%d\n" , i, |
2315 | group->samples[i].index, group->samples[i].power)); |
2316 | } |
2317 | } |
2318 | |
2319 | /* |
2320 | * Send a command to the firmware. |
2321 | */ |
2322 | static int |
2323 | wpi_cmd(struct wpi_softc *sc, int code, const void *buf, int size, int async) |
2324 | { |
2325 | struct wpi_tx_ring *ring = &sc->cmdq; |
2326 | struct wpi_tx_desc *desc; |
2327 | struct wpi_tx_cmd *cmd; |
2328 | struct wpi_dma_info *dma; |
2329 | |
2330 | KASSERT(size <= sizeof cmd->data); |
2331 | |
2332 | desc = &ring->desc[ring->cur]; |
2333 | cmd = &ring->cmd[ring->cur]; |
2334 | |
2335 | cmd->code = code; |
2336 | cmd->flags = 0; |
2337 | cmd->qid = ring->qid; |
2338 | cmd->idx = ring->cur; |
2339 | memcpy(cmd->data, buf, size); |
2340 | |
2341 | dma = &ring->cmd_dma; |
2342 | bus_dmamap_sync(dma->tag, dma->map, 0, dma->size, BUS_DMASYNC_PREWRITE); |
2343 | |
2344 | desc->flags = htole32(WPI_PAD32(size) << 28 | 1 << 24); |
2345 | desc->segs[0].addr = htole32(ring->cmd_dma.paddr + |
2346 | ring->cur * sizeof (struct wpi_tx_cmd)); |
2347 | desc->segs[0].len = htole32(4 + size); |
2348 | |
2349 | dma = &ring->desc_dma; |
2350 | bus_dmamap_sync(dma->tag, dma->map, 0, dma->size, BUS_DMASYNC_PREWRITE); |
2351 | |
2352 | /* kick cmd ring */ |
2353 | ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; |
2354 | WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); |
2355 | |
2356 | return async ? 0 : tsleep(cmd, PCATCH, "wpicmd" , hz); |
2357 | } |
2358 | |
2359 | static int |
2360 | wpi_wme_update(struct ieee80211com *ic) |
2361 | { |
2362 | #define WPI_EXP2(v) htole16((1 << (v)) - 1) |
2363 | #define WPI_USEC(v) htole16(IEEE80211_TXOP_TO_US(v)) |
2364 | struct wpi_softc *sc = ic->ic_ifp->if_softc; |
2365 | const struct wmeParams *wmep; |
2366 | struct wpi_wme_setup wme; |
2367 | int ac; |
2368 | |
2369 | /* don't override default WME values if WME is not actually enabled */ |
2370 | if (!(ic->ic_flags & IEEE80211_F_WME)) |
2371 | return 0; |
2372 | |
2373 | wme.flags = 0; |
2374 | for (ac = 0; ac < WME_NUM_AC; ac++) { |
2375 | wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; |
2376 | wme.ac[ac].aifsn = wmep->wmep_aifsn; |
2377 | wme.ac[ac].cwmin = WPI_EXP2(wmep->wmep_logcwmin); |
2378 | wme.ac[ac].cwmax = WPI_EXP2(wmep->wmep_logcwmax); |
2379 | wme.ac[ac].txop = WPI_USEC(wmep->wmep_txopLimit); |
2380 | |
2381 | DPRINTF(("setting WME for queue %d aifsn=%d cwmin=%d cwmax=%d " |
2382 | "txop=%d\n" , ac, wme.ac[ac].aifsn, wme.ac[ac].cwmin, |
2383 | wme.ac[ac].cwmax, wme.ac[ac].txop)); |
2384 | } |
2385 | |
2386 | return wpi_cmd(sc, WPI_CMD_SET_WME, &wme, sizeof wme, 1); |
2387 | #undef WPI_USEC |
2388 | #undef WPI_EXP2 |
2389 | } |
2390 | |
2391 | /* |
2392 | * Configure h/w multi-rate retries. |
2393 | */ |
2394 | static int |
2395 | wpi_mrr_setup(struct wpi_softc *sc) |
2396 | { |
2397 | struct ieee80211com *ic = &sc->sc_ic; |
2398 | struct wpi_mrr_setup mrr; |
2399 | int i, error; |
2400 | |
2401 | /* CCK rates (not used with 802.11a) */ |
2402 | for (i = WPI_CCK1; i <= WPI_CCK11; i++) { |
2403 | mrr.rates[i].flags = 0; |
2404 | mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; |
2405 | /* fallback to the immediate lower CCK rate (if any) */ |
2406 | mrr.rates[i].next = (i == WPI_CCK1) ? WPI_CCK1 : i - 1; |
2407 | /* try one time at this rate before falling back to "next" */ |
2408 | mrr.rates[i].ntries = 1; |
2409 | } |
2410 | |
2411 | /* OFDM rates (not used with 802.11b) */ |
2412 | for (i = WPI_OFDM6; i <= WPI_OFDM54; i++) { |
2413 | mrr.rates[i].flags = 0; |
2414 | mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; |
2415 | /* fallback to the immediate lower rate (if any) */ |
2416 | /* we allow fallback from OFDM/6 to CCK/2 in 11b/g mode */ |
2417 | mrr.rates[i].next = (i == WPI_OFDM6) ? |
2418 | ((ic->ic_curmode == IEEE80211_MODE_11A) ? |
2419 | WPI_OFDM6 : WPI_CCK2) : |
2420 | i - 1; |
2421 | /* try one time at this rate before falling back to "next" */ |
2422 | mrr.rates[i].ntries = 1; |
2423 | } |
2424 | |
2425 | /* setup MRR for control frames */ |
2426 | mrr.which = htole32(WPI_MRR_CTL); |
2427 | error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); |
2428 | if (error != 0) { |
2429 | aprint_error_dev(sc->sc_dev, |
2430 | "could not setup MRR for control frames\n" ); |
2431 | return error; |
2432 | } |
2433 | |
2434 | /* setup MRR for data frames */ |
2435 | mrr.which = htole32(WPI_MRR_DATA); |
2436 | error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); |
2437 | if (error != 0) { |
2438 | aprint_error_dev(sc->sc_dev, |
2439 | "could not setup MRR for data frames\n" ); |
2440 | return error; |
2441 | } |
2442 | |
2443 | return 0; |
2444 | } |
2445 | |
2446 | static void |
2447 | wpi_set_led(struct wpi_softc *sc, uint8_t which, uint8_t off, uint8_t on) |
2448 | { |
2449 | struct wpi_cmd_led led; |
2450 | |
2451 | led.which = which; |
2452 | led.unit = htole32(100000); /* on/off in unit of 100ms */ |
2453 | led.off = off; |
2454 | led.on = on; |
2455 | |
2456 | (void)wpi_cmd(sc, WPI_CMD_SET_LED, &led, sizeof led, 1); |
2457 | } |
2458 | |
2459 | static void |
2460 | wpi_enable_tsf(struct wpi_softc *sc, struct ieee80211_node *ni) |
2461 | { |
2462 | struct wpi_cmd_tsf tsf; |
2463 | uint64_t val, mod; |
2464 | |
2465 | memset(&tsf, 0, sizeof tsf); |
2466 | memcpy(&tsf.tstamp, ni->ni_tstamp.data, sizeof (uint64_t)); |
2467 | tsf.bintval = htole16(ni->ni_intval); |
2468 | tsf.lintval = htole16(10); |
2469 | |
2470 | /* compute remaining time until next beacon */ |
2471 | val = (uint64_t)ni->ni_intval * 1024; /* msecs -> usecs */ |
2472 | mod = le64toh(tsf.tstamp) % val; |
2473 | tsf.binitval = htole32((uint32_t)(val - mod)); |
2474 | |
2475 | DPRINTF(("TSF bintval=%u tstamp=%" PRIu64 ", init=%u\n" , |
2476 | ni->ni_intval, le64toh(tsf.tstamp), (uint32_t)(val - mod))); |
2477 | |
2478 | if (wpi_cmd(sc, WPI_CMD_TSF, &tsf, sizeof tsf, 1) != 0) |
2479 | aprint_error_dev(sc->sc_dev, "could not enable TSF\n" ); |
2480 | } |
2481 | |
2482 | /* |
2483 | * Update Tx power to match what is defined for channel `c'. |
2484 | */ |
2485 | static int |
2486 | wpi_set_txpower(struct wpi_softc *sc, struct ieee80211_channel *c, int async) |
2487 | { |
2488 | struct ieee80211com *ic = &sc->sc_ic; |
2489 | struct wpi_power_group *group; |
2490 | struct wpi_cmd_txpower txpower; |
2491 | u_int chan; |
2492 | int i; |
2493 | |
2494 | /* get channel number */ |
2495 | chan = ieee80211_chan2ieee(ic, c); |
2496 | |
2497 | /* find the power group to which this channel belongs */ |
2498 | if (IEEE80211_IS_CHAN_5GHZ(c)) { |
2499 | for (group = &sc->groups[1]; group < &sc->groups[4]; group++) |
2500 | if (chan <= group->chan) |
2501 | break; |
2502 | } else |
2503 | group = &sc->groups[0]; |
2504 | |
2505 | memset(&txpower, 0, sizeof txpower); |
2506 | txpower.band = IEEE80211_IS_CHAN_5GHZ(c) ? 0 : 1; |
2507 | txpower.chan = htole16(chan); |
2508 | |
2509 | /* set Tx power for all OFDM and CCK rates */ |
2510 | for (i = 0; i <= 11 ; i++) { |
2511 | /* retrieve Tx power for this channel/rate combination */ |
2512 | int idx = wpi_get_power_index(sc, group, c, |
2513 | wpi_ridx_to_rate[i]); |
2514 | |
2515 | txpower.rates[i].plcp = wpi_ridx_to_plcp[i]; |
2516 | |
2517 | if (IEEE80211_IS_CHAN_5GHZ(c)) { |
2518 | txpower.rates[i].rf_gain = wpi_rf_gain_5ghz[idx]; |
2519 | txpower.rates[i].dsp_gain = wpi_dsp_gain_5ghz[idx]; |
2520 | } else { |
2521 | txpower.rates[i].rf_gain = wpi_rf_gain_2ghz[idx]; |
2522 | txpower.rates[i].dsp_gain = wpi_dsp_gain_2ghz[idx]; |
2523 | } |
2524 | DPRINTF(("chan %d/rate %d: power index %d\n" , chan, |
2525 | wpi_ridx_to_rate[i], idx)); |
2526 | } |
2527 | |
2528 | return wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof txpower, async); |
2529 | } |
2530 | |
2531 | /* |
2532 | * Determine Tx power index for a given channel/rate combination. |
2533 | * This takes into account the regulatory information from EEPROM and the |
2534 | * current temperature. |
2535 | */ |
2536 | static int |
2537 | wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group, |
2538 | struct ieee80211_channel *c, int rate) |
2539 | { |
2540 | /* fixed-point arithmetic division using a n-bit fractional part */ |
2541 | #define fdivround(a, b, n) \ |
2542 | ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) |
2543 | |
2544 | /* linear interpolation */ |
2545 | #define interpolate(x, x1, y1, x2, y2, n) \ |
2546 | ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) |
2547 | |
2548 | struct ieee80211com *ic = &sc->sc_ic; |
2549 | struct wpi_power_sample *sample; |
2550 | int pwr, idx; |
2551 | u_int chan; |
2552 | |
2553 | /* get channel number */ |
2554 | chan = ieee80211_chan2ieee(ic, c); |
2555 | |
2556 | /* default power is group's maximum power - 3dB */ |
2557 | pwr = group->maxpwr / 2; |
2558 | |
2559 | /* decrease power for highest OFDM rates to reduce distortion */ |
2560 | switch (rate) { |
2561 | case 72: /* 36Mb/s */ |
2562 | pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5; |
2563 | break; |
2564 | case 96: /* 48Mb/s */ |
2565 | pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10; |
2566 | break; |
2567 | case 108: /* 54Mb/s */ |
2568 | pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12; |
2569 | break; |
2570 | } |
2571 | |
2572 | /* never exceed channel's maximum allowed Tx power */ |
2573 | pwr = min(pwr, sc->maxpwr[chan]); |
2574 | |
2575 | /* retrieve power index into gain tables from samples */ |
2576 | for (sample = group->samples; sample < &group->samples[3]; sample++) |
2577 | if (pwr > sample[1].power) |
2578 | break; |
2579 | /* fixed-point linear interpolation using a 19-bit fractional part */ |
2580 | idx = interpolate(pwr, sample[0].power, sample[0].index, |
2581 | sample[1].power, sample[1].index, 19); |
2582 | |
2583 | /*- |
2584 | * Adjust power index based on current temperature: |
2585 | * - if cooler than factory-calibrated: decrease output power |
2586 | * - if warmer than factory-calibrated: increase output power |
2587 | */ |
2588 | idx -= (sc->temp - group->temp) * 11 / 100; |
2589 | |
2590 | /* decrease power for CCK rates (-5dB) */ |
2591 | if (!WPI_RATE_IS_OFDM(rate)) |
2592 | idx += 10; |
2593 | |
2594 | /* keep power index in a valid range */ |
2595 | if (idx < 0) |
2596 | return 0; |
2597 | if (idx > WPI_MAX_PWR_INDEX) |
2598 | return WPI_MAX_PWR_INDEX; |
2599 | return idx; |
2600 | |
2601 | #undef interpolate |
2602 | #undef fdivround |
2603 | } |
2604 | |
2605 | /* |
2606 | * Build a beacon frame that the firmware will broadcast periodically in |
2607 | * IBSS or HostAP modes. |
2608 | */ |
2609 | static int |
2610 | wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) |
2611 | { |
2612 | struct ieee80211com *ic = &sc->sc_ic; |
2613 | struct wpi_tx_ring *ring = &sc->cmdq; |
2614 | struct wpi_tx_desc *desc; |
2615 | struct wpi_tx_data *data; |
2616 | struct wpi_tx_cmd *cmd; |
2617 | struct wpi_cmd_beacon *bcn; |
2618 | struct ieee80211_beacon_offsets bo; |
2619 | struct mbuf *m0; |
2620 | int error; |
2621 | |
2622 | desc = &ring->desc[ring->cur]; |
2623 | data = &ring->data[ring->cur]; |
2624 | |
2625 | m0 = ieee80211_beacon_alloc(ic, ni, &bo); |
2626 | if (m0 == NULL) { |
2627 | aprint_error_dev(sc->sc_dev, |
2628 | "could not allocate beacon frame\n" ); |
2629 | return ENOMEM; |
2630 | } |
2631 | |
2632 | cmd = &ring->cmd[ring->cur]; |
2633 | cmd->code = WPI_CMD_SET_BEACON; |
2634 | cmd->flags = 0; |
2635 | cmd->qid = ring->qid; |
2636 | cmd->idx = ring->cur; |
2637 | |
2638 | bcn = (struct wpi_cmd_beacon *)cmd->data; |
2639 | memset(bcn, 0, sizeof (struct wpi_cmd_beacon)); |
2640 | bcn->id = WPI_ID_BROADCAST; |
2641 | bcn->ofdm_mask = 0xff; |
2642 | bcn->cck_mask = 0x0f; |
2643 | bcn->lifetime = htole32(WPI_LIFETIME_INFINITE); |
2644 | bcn->len = htole16(m0->m_pkthdr.len); |
2645 | bcn->rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? |
2646 | wpi_plcp_signal(12) : wpi_plcp_signal(2); |
2647 | bcn->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); |
2648 | |
2649 | /* save and trim IEEE802.11 header */ |
2650 | m_copydata(m0, 0, sizeof (struct ieee80211_frame), (void *)&bcn->wh); |
2651 | m_adj(m0, sizeof (struct ieee80211_frame)); |
2652 | |
2653 | /* assume beacon frame is contiguous */ |
2654 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, |
2655 | BUS_DMA_READ | BUS_DMA_NOWAIT); |
2656 | if (error != 0) { |
2657 | aprint_error_dev(sc->sc_dev, "could not map beacon\n" ); |
2658 | m_freem(m0); |
2659 | return error; |
2660 | } |
2661 | |
2662 | data->m = m0; |
2663 | |
2664 | /* first scatter/gather segment is used by the beacon command */ |
2665 | desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | 2 << 24); |
2666 | desc->segs[0].addr = htole32(ring->cmd_dma.paddr + |
2667 | ring->cur * sizeof (struct wpi_tx_cmd)); |
2668 | desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_beacon)); |
2669 | desc->segs[1].addr = htole32(data->map->dm_segs[0].ds_addr); |
2670 | desc->segs[1].len = htole32(data->map->dm_segs[0].ds_len); |
2671 | |
2672 | bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, |
2673 | ring->desc_dma.map->dm_mapsize, BUS_DMASYNC_PREWRITE); |
2674 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, |
2675 | BUS_DMASYNC_PREWRITE); |
2676 | |
2677 | /* kick cmd ring */ |
2678 | ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; |
2679 | WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); |
2680 | |
2681 | return 0; |
2682 | } |
2683 | |
2684 | static int |
2685 | wpi_auth(struct wpi_softc *sc) |
2686 | { |
2687 | struct ieee80211com *ic = &sc->sc_ic; |
2688 | struct ieee80211_node *ni = ic->ic_bss; |
2689 | struct wpi_node_info node; |
2690 | int error; |
2691 | |
2692 | /* update adapter's configuration */ |
2693 | IEEE80211_ADDR_COPY(sc->config.bssid, ni->ni_bssid); |
2694 | sc->config.chan = ieee80211_chan2ieee(ic, ni->ni_chan); |
2695 | sc->config.flags = htole32(WPI_CONFIG_TSF); |
2696 | if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { |
2697 | sc->config.flags |= htole32(WPI_CONFIG_AUTO | |
2698 | WPI_CONFIG_24GHZ); |
2699 | } |
2700 | switch (ic->ic_curmode) { |
2701 | case IEEE80211_MODE_11A: |
2702 | sc->config.cck_mask = 0; |
2703 | sc->config.ofdm_mask = 0x15; |
2704 | break; |
2705 | case IEEE80211_MODE_11B: |
2706 | sc->config.cck_mask = 0x03; |
2707 | sc->config.ofdm_mask = 0; |
2708 | break; |
2709 | default: /* assume 802.11b/g */ |
2710 | sc->config.cck_mask = 0x0f; |
2711 | sc->config.ofdm_mask = 0x15; |
2712 | } |
2713 | DPRINTF(("config chan %d flags %x cck %x ofdm %x\n" , sc->config.chan, |
2714 | sc->config.flags, sc->config.cck_mask, sc->config.ofdm_mask)); |
2715 | error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, |
2716 | sizeof (struct wpi_config), 1); |
2717 | if (error != 0) { |
2718 | aprint_error_dev(sc->sc_dev, "could not configure\n" ); |
2719 | return error; |
2720 | } |
2721 | |
2722 | /* configuration has changed, set Tx power accordingly */ |
2723 | if ((error = wpi_set_txpower(sc, ni->ni_chan, 1)) != 0) { |
2724 | aprint_error_dev(sc->sc_dev, "could not set Tx power\n" ); |
2725 | return error; |
2726 | } |
2727 | |
2728 | /* add default node */ |
2729 | memset(&node, 0, sizeof node); |
2730 | IEEE80211_ADDR_COPY(node.bssid, ni->ni_bssid); |
2731 | node.id = WPI_ID_BSS; |
2732 | node.rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? |
2733 | wpi_plcp_signal(12) : wpi_plcp_signal(2); |
2734 | node.action = htole32(WPI_ACTION_SET_RATE); |
2735 | node.antenna = WPI_ANTENNA_BOTH; |
2736 | error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); |
2737 | if (error != 0) { |
2738 | aprint_error_dev(sc->sc_dev, "could not add BSS node\n" ); |
2739 | return error; |
2740 | } |
2741 | |
2742 | return 0; |
2743 | } |
2744 | |
2745 | /* |
2746 | * Send a scan request to the firmware. Since this command is huge, we map it |
2747 | * into a mbuf instead of using the pre-allocated set of commands. |
2748 | */ |
2749 | static int |
2750 | wpi_scan(struct wpi_softc *sc) |
2751 | { |
2752 | struct ieee80211com *ic = &sc->sc_ic; |
2753 | struct wpi_tx_ring *ring = &sc->cmdq; |
2754 | struct wpi_tx_desc *desc; |
2755 | struct wpi_tx_data *data; |
2756 | struct wpi_tx_cmd *cmd; |
2757 | struct wpi_scan_hdr *hdr; |
2758 | struct wpi_scan_chan *chan; |
2759 | struct ieee80211_frame *wh; |
2760 | struct ieee80211_rateset *rs; |
2761 | struct ieee80211_channel *c; |
2762 | uint8_t *frm; |
2763 | int pktlen, error, nrates; |
2764 | |
2765 | if (ic->ic_curchan == NULL) |
2766 | return EIO; |
2767 | |
2768 | desc = &ring->desc[ring->cur]; |
2769 | data = &ring->data[ring->cur]; |
2770 | |
2771 | MGETHDR(data->m, M_DONTWAIT, MT_DATA); |
2772 | if (data->m == NULL) { |
2773 | aprint_error_dev(sc->sc_dev, |
2774 | "could not allocate mbuf for scan command\n" ); |
2775 | return ENOMEM; |
2776 | } |
2777 | MCLGET(data->m, M_DONTWAIT); |
2778 | if (!(data->m->m_flags & M_EXT)) { |
2779 | m_freem(data->m); |
2780 | data->m = NULL; |
2781 | aprint_error_dev(sc->sc_dev, |
2782 | "could not allocate mbuf for scan command\n" ); |
2783 | return ENOMEM; |
2784 | } |
2785 | |
2786 | cmd = mtod(data->m, struct wpi_tx_cmd *); |
2787 | cmd->code = WPI_CMD_SCAN; |
2788 | cmd->flags = 0; |
2789 | cmd->qid = ring->qid; |
2790 | cmd->idx = ring->cur; |
2791 | |
2792 | hdr = (struct wpi_scan_hdr *)cmd->data; |
2793 | memset(hdr, 0, sizeof (struct wpi_scan_hdr)); |
2794 | hdr->cmd.flags = htole32(WPI_TX_AUTO_SEQ); |
2795 | hdr->cmd.id = WPI_ID_BROADCAST; |
2796 | hdr->cmd.lifetime = htole32(WPI_LIFETIME_INFINITE); |
2797 | /* |
2798 | * Move to the next channel if no packets are received within 5 msecs |
2799 | * after sending the probe request (this helps to reduce the duration |
2800 | * of active scans). |
2801 | */ |
2802 | hdr->quiet = htole16(5); /* timeout in milliseconds */ |
2803 | hdr->plcp_threshold = htole16(1); /* min # of packets */ |
2804 | |
2805 | if (ic->ic_curchan->ic_flags & IEEE80211_CHAN_5GHZ) { |
2806 | hdr->crc_threshold = htole16(1); |
2807 | /* send probe requests at 6Mbps */ |
2808 | hdr->cmd.rate = wpi_plcp_signal(12); |
2809 | rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; |
2810 | } else { |
2811 | hdr->flags = htole32(WPI_CONFIG_24GHZ | WPI_CONFIG_AUTO); |
2812 | /* send probe requests at 1Mbps */ |
2813 | hdr->cmd.rate = wpi_plcp_signal(2); |
2814 | rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; |
2815 | } |
2816 | |
2817 | /* for directed scans, firmware inserts the essid IE itself */ |
2818 | if (ic->ic_des_esslen != 0) { |
2819 | hdr->essid[0].id = IEEE80211_ELEMID_SSID; |
2820 | hdr->essid[0].len = ic->ic_des_esslen; |
2821 | memcpy(hdr->essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); |
2822 | } |
2823 | |
2824 | /* |
2825 | * Build a probe request frame. Most of the following code is a |
2826 | * copy & paste of what is done in net80211. |
2827 | */ |
2828 | wh = (struct ieee80211_frame *)(hdr + 1); |
2829 | wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | |
2830 | IEEE80211_FC0_SUBTYPE_PROBE_REQ; |
2831 | wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; |
2832 | IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); |
2833 | IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); |
2834 | IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr); |
2835 | *(u_int16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ |
2836 | *(u_int16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ |
2837 | |
2838 | frm = (uint8_t *)(wh + 1); |
2839 | |
2840 | /* add empty essid IE (firmware generates it for directed scans) */ |
2841 | *frm++ = IEEE80211_ELEMID_SSID; |
2842 | *frm++ = 0; |
2843 | |
2844 | /* add supported rates IE */ |
2845 | *frm++ = IEEE80211_ELEMID_RATES; |
2846 | nrates = rs->rs_nrates; |
2847 | if (nrates > IEEE80211_RATE_SIZE) |
2848 | nrates = IEEE80211_RATE_SIZE; |
2849 | *frm++ = nrates; |
2850 | memcpy(frm, rs->rs_rates, nrates); |
2851 | frm += nrates; |
2852 | |
2853 | /* add supported xrates IE */ |
2854 | if (rs->rs_nrates > IEEE80211_RATE_SIZE) { |
2855 | nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; |
2856 | *frm++ = IEEE80211_ELEMID_XRATES; |
2857 | *frm++ = nrates; |
2858 | memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); |
2859 | frm += nrates; |
2860 | } |
2861 | |
2862 | /* setup length of probe request */ |
2863 | hdr->cmd.len = htole16(frm - (uint8_t *)wh); |
2864 | |
2865 | chan = (struct wpi_scan_chan *)frm; |
2866 | c = ic->ic_curchan; |
2867 | |
2868 | chan->chan = ieee80211_chan2ieee(ic, c); |
2869 | chan->flags = 0; |
2870 | if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { |
2871 | chan->flags |= WPI_CHAN_ACTIVE; |
2872 | if (ic->ic_des_esslen != 0) |
2873 | chan->flags |= WPI_CHAN_DIRECT; |
2874 | } |
2875 | chan->dsp_gain = 0x6e; |
2876 | if (IEEE80211_IS_CHAN_5GHZ(c)) { |
2877 | chan->rf_gain = 0x3b; |
2878 | chan->active = htole16(10); |
2879 | chan->passive = htole16(110); |
2880 | } else { |
2881 | chan->rf_gain = 0x28; |
2882 | chan->active = htole16(20); |
2883 | chan->passive = htole16(120); |
2884 | } |
2885 | hdr->nchan++; |
2886 | chan++; |
2887 | |
2888 | frm += sizeof (struct wpi_scan_chan); |
2889 | |
2890 | hdr->len = htole16(frm - (uint8_t *)hdr); |
2891 | pktlen = frm - (uint8_t *)cmd; |
2892 | |
2893 | error = bus_dmamap_load(sc->sc_dmat, data->map, cmd, pktlen, NULL, |
2894 | BUS_DMA_NOWAIT); |
2895 | if (error != 0) { |
2896 | aprint_error_dev(sc->sc_dev, "could not map scan command\n" ); |
2897 | m_freem(data->m); |
2898 | data->m = NULL; |
2899 | return error; |
2900 | } |
2901 | |
2902 | desc->flags = htole32(WPI_PAD32(pktlen) << 28 | 1 << 24); |
2903 | desc->segs[0].addr = htole32(data->map->dm_segs[0].ds_addr); |
2904 | desc->segs[0].len = htole32(data->map->dm_segs[0].ds_len); |
2905 | |
2906 | bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, |
2907 | ring->desc_dma.map->dm_mapsize, BUS_DMASYNC_PREWRITE); |
2908 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, |
2909 | BUS_DMASYNC_PREWRITE); |
2910 | |
2911 | /* kick cmd ring */ |
2912 | ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; |
2913 | WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); |
2914 | |
2915 | return 0; /* will be notified async. of failure/success */ |
2916 | } |
2917 | |
2918 | static int |
2919 | wpi_config(struct wpi_softc *sc) |
2920 | { |
2921 | struct ieee80211com *ic = &sc->sc_ic; |
2922 | struct ifnet *ifp = ic->ic_ifp; |
2923 | struct wpi_power power; |
2924 | struct wpi_bluetooth bluetooth; |
2925 | struct wpi_node_info node; |
2926 | int error; |
2927 | |
2928 | memset(&power, 0, sizeof power); |
2929 | power.flags = htole32(WPI_POWER_CAM | 0x8); |
2930 | error = wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &power, sizeof power, 0); |
2931 | if (error != 0) { |
2932 | aprint_error_dev(sc->sc_dev, "could not set power mode\n" ); |
2933 | return error; |
2934 | } |
2935 | |
2936 | /* configure bluetooth coexistence */ |
2937 | memset(&bluetooth, 0, sizeof bluetooth); |
2938 | bluetooth.flags = 3; |
2939 | bluetooth.lead = 0xaa; |
2940 | bluetooth.kill = 1; |
2941 | error = wpi_cmd(sc, WPI_CMD_BLUETOOTH, &bluetooth, sizeof bluetooth, |
2942 | 0); |
2943 | if (error != 0) { |
2944 | aprint_error_dev(sc->sc_dev, |
2945 | "could not configure bluetooth coexistence\n" ); |
2946 | return error; |
2947 | } |
2948 | |
2949 | /* configure adapter */ |
2950 | memset(&sc->config, 0, sizeof (struct wpi_config)); |
2951 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); |
2952 | IEEE80211_ADDR_COPY(sc->config.myaddr, ic->ic_myaddr); |
2953 | /* set default channel */ |
2954 | sc->config.chan = ieee80211_chan2ieee(ic, ic->ic_curchan); |
2955 | sc->config.flags = htole32(WPI_CONFIG_TSF); |
2956 | if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { |
2957 | sc->config.flags |= htole32(WPI_CONFIG_AUTO | |
2958 | WPI_CONFIG_24GHZ); |
2959 | } |
2960 | sc->config.filter = 0; |
2961 | switch (ic->ic_opmode) { |
2962 | case IEEE80211_M_STA: |
2963 | sc->config.mode = WPI_MODE_STA; |
2964 | sc->config.filter |= htole32(WPI_FILTER_MULTICAST); |
2965 | break; |
2966 | case IEEE80211_M_IBSS: |
2967 | case IEEE80211_M_AHDEMO: |
2968 | sc->config.mode = WPI_MODE_IBSS; |
2969 | break; |
2970 | case IEEE80211_M_HOSTAP: |
2971 | sc->config.mode = WPI_MODE_HOSTAP; |
2972 | break; |
2973 | case IEEE80211_M_MONITOR: |
2974 | sc->config.mode = WPI_MODE_MONITOR; |
2975 | sc->config.filter |= htole32(WPI_FILTER_MULTICAST | |
2976 | WPI_FILTER_CTL | WPI_FILTER_PROMISC); |
2977 | break; |
2978 | } |
2979 | sc->config.cck_mask = 0x0f; /* not yet negotiated */ |
2980 | sc->config.ofdm_mask = 0xff; /* not yet negotiated */ |
2981 | error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, |
2982 | sizeof (struct wpi_config), 0); |
2983 | if (error != 0) { |
2984 | aprint_error_dev(sc->sc_dev, "configure command failed\n" ); |
2985 | return error; |
2986 | } |
2987 | |
2988 | /* configuration has changed, set Tx power accordingly */ |
2989 | if ((error = wpi_set_txpower(sc, ic->ic_curchan, 0)) != 0) { |
2990 | aprint_error_dev(sc->sc_dev, "could not set Tx power\n" ); |
2991 | return error; |
2992 | } |
2993 | |
2994 | /* add broadcast node */ |
2995 | memset(&node, 0, sizeof node); |
2996 | IEEE80211_ADDR_COPY(node.bssid, etherbroadcastaddr); |
2997 | node.id = WPI_ID_BROADCAST; |
2998 | node.rate = wpi_plcp_signal(2); |
2999 | node.action = htole32(WPI_ACTION_SET_RATE); |
3000 | node.antenna = WPI_ANTENNA_BOTH; |
3001 | error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 0); |
3002 | if (error != 0) { |
3003 | aprint_error_dev(sc->sc_dev, "could not add broadcast node\n" ); |
3004 | return error; |
3005 | } |
3006 | |
3007 | if ((error = wpi_mrr_setup(sc)) != 0) { |
3008 | aprint_error_dev(sc->sc_dev, "could not setup MRR\n" ); |
3009 | return error; |
3010 | } |
3011 | |
3012 | return 0; |
3013 | } |
3014 | |
3015 | static void |
3016 | wpi_stop_master(struct wpi_softc *sc) |
3017 | { |
3018 | uint32_t tmp; |
3019 | int ntries; |
3020 | |
3021 | tmp = WPI_READ(sc, WPI_RESET); |
3022 | WPI_WRITE(sc, WPI_RESET, tmp | WPI_STOP_MASTER); |
3023 | |
3024 | tmp = WPI_READ(sc, WPI_GPIO_CTL); |
3025 | if ((tmp & WPI_GPIO_PWR_STATUS) == WPI_GPIO_PWR_SLEEP) |
3026 | return; /* already asleep */ |
3027 | |
3028 | for (ntries = 0; ntries < 100; ntries++) { |
3029 | if (WPI_READ(sc, WPI_RESET) & WPI_MASTER_DISABLED) |
3030 | break; |
3031 | DELAY(10); |
3032 | } |
3033 | if (ntries == 100) { |
3034 | aprint_error_dev(sc->sc_dev, "timeout waiting for master\n" ); |
3035 | } |
3036 | } |
3037 | |
3038 | static int |
3039 | wpi_power_up(struct wpi_softc *sc) |
3040 | { |
3041 | uint32_t tmp; |
3042 | int ntries; |
3043 | |
3044 | wpi_mem_lock(sc); |
3045 | tmp = wpi_mem_read(sc, WPI_MEM_POWER); |
3046 | wpi_mem_write(sc, WPI_MEM_POWER, tmp & ~0x03000000); |
3047 | wpi_mem_unlock(sc); |
3048 | |
3049 | for (ntries = 0; ntries < 5000; ntries++) { |
3050 | if (WPI_READ(sc, WPI_GPIO_STATUS) & WPI_POWERED) |
3051 | break; |
3052 | DELAY(10); |
3053 | } |
3054 | if (ntries == 5000) { |
3055 | aprint_error_dev(sc->sc_dev, |
3056 | "timeout waiting for NIC to power up\n" ); |
3057 | return ETIMEDOUT; |
3058 | } |
3059 | return 0; |
3060 | } |
3061 | |
3062 | static int |
3063 | wpi_reset(struct wpi_softc *sc) |
3064 | { |
3065 | uint32_t tmp; |
3066 | int ntries; |
3067 | |
3068 | /* clear any pending interrupts */ |
3069 | WPI_WRITE(sc, WPI_INTR, 0xffffffff); |
3070 | |
3071 | tmp = WPI_READ(sc, WPI_PLL_CTL); |
3072 | WPI_WRITE(sc, WPI_PLL_CTL, tmp | WPI_PLL_INIT); |
3073 | |
3074 | tmp = WPI_READ(sc, WPI_CHICKEN); |
3075 | WPI_WRITE(sc, WPI_CHICKEN, tmp | WPI_CHICKEN_RXNOLOS); |
3076 | |
3077 | tmp = WPI_READ(sc, WPI_GPIO_CTL); |
3078 | WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_INIT); |
3079 | |
3080 | /* wait for clock stabilization */ |
3081 | for (ntries = 0; ntries < 1000; ntries++) { |
3082 | if (WPI_READ(sc, WPI_GPIO_CTL) & WPI_GPIO_CLOCK) |
3083 | break; |
3084 | DELAY(10); |
3085 | } |
3086 | if (ntries == 1000) { |
3087 | aprint_error_dev(sc->sc_dev, |
3088 | "timeout waiting for clock stabilization\n" ); |
3089 | return ETIMEDOUT; |
3090 | } |
3091 | |
3092 | /* initialize EEPROM */ |
3093 | tmp = WPI_READ(sc, WPI_EEPROM_STATUS); |
3094 | if ((tmp & WPI_EEPROM_VERSION) == 0) { |
3095 | aprint_error_dev(sc->sc_dev, "EEPROM not found\n" ); |
3096 | return EIO; |
3097 | } |
3098 | WPI_WRITE(sc, WPI_EEPROM_STATUS, tmp & ~WPI_EEPROM_LOCKED); |
3099 | |
3100 | return 0; |
3101 | } |
3102 | |
3103 | static void |
3104 | wpi_hw_config(struct wpi_softc *sc) |
3105 | { |
3106 | uint32_t rev, hw; |
3107 | |
3108 | /* voodoo from the reference driver */ |
3109 | hw = WPI_READ(sc, WPI_HWCONFIG); |
3110 | |
3111 | rev = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_CLASS_REG); |
3112 | rev = PCI_REVISION(rev); |
3113 | if ((rev & 0xc0) == 0x40) |
3114 | hw |= WPI_HW_ALM_MB; |
3115 | else if (!(rev & 0x80)) |
3116 | hw |= WPI_HW_ALM_MM; |
3117 | |
3118 | if (sc->cap == 0x80) |
3119 | hw |= WPI_HW_SKU_MRC; |
3120 | |
3121 | hw &= ~WPI_HW_REV_D; |
3122 | if ((le16toh(sc->rev) & 0xf0) == 0xd0) |
3123 | hw |= WPI_HW_REV_D; |
3124 | |
3125 | if (sc->type > 1) |
3126 | hw |= WPI_HW_TYPE_B; |
3127 | |
3128 | DPRINTF(("setting h/w config %x\n" , hw)); |
3129 | WPI_WRITE(sc, WPI_HWCONFIG, hw); |
3130 | } |
3131 | |
3132 | static int |
3133 | wpi_init(struct ifnet *ifp) |
3134 | { |
3135 | struct wpi_softc *sc = ifp->if_softc; |
3136 | struct ieee80211com *ic = &sc->sc_ic; |
3137 | uint32_t tmp; |
3138 | int qid, ntries, error; |
3139 | |
3140 | wpi_stop(ifp,1); |
3141 | (void)wpi_reset(sc); |
3142 | |
3143 | wpi_mem_lock(sc); |
3144 | wpi_mem_write(sc, WPI_MEM_CLOCK1, 0xa00); |
3145 | DELAY(20); |
3146 | tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); |
3147 | wpi_mem_write(sc, WPI_MEM_PCIDEV, tmp | 0x800); |
3148 | wpi_mem_unlock(sc); |
3149 | |
3150 | (void)wpi_power_up(sc); |
3151 | wpi_hw_config(sc); |
3152 | |
3153 | /* init Rx ring */ |
3154 | wpi_mem_lock(sc); |
3155 | WPI_WRITE(sc, WPI_RX_BASE, sc->rxq.desc_dma.paddr); |
3156 | WPI_WRITE(sc, WPI_RX_RIDX_PTR, sc->shared_dma.paddr + |
3157 | offsetof(struct wpi_shared, next)); |
3158 | WPI_WRITE(sc, WPI_RX_WIDX, (WPI_RX_RING_COUNT - 1) & ~7); |
3159 | WPI_WRITE(sc, WPI_RX_CONFIG, 0xa9601010); |
3160 | wpi_mem_unlock(sc); |
3161 | |
3162 | /* init Tx rings */ |
3163 | wpi_mem_lock(sc); |
3164 | wpi_mem_write(sc, WPI_MEM_MODE, 2); /* bypass mode */ |
3165 | wpi_mem_write(sc, WPI_MEM_RA, 1); /* enable RA0 */ |
3166 | wpi_mem_write(sc, WPI_MEM_TXCFG, 0x3f); /* enable all 6 Tx rings */ |
3167 | wpi_mem_write(sc, WPI_MEM_BYPASS1, 0x10000); |
3168 | wpi_mem_write(sc, WPI_MEM_BYPASS2, 0x30002); |
3169 | wpi_mem_write(sc, WPI_MEM_MAGIC4, 4); |
3170 | wpi_mem_write(sc, WPI_MEM_MAGIC5, 5); |
3171 | |
3172 | WPI_WRITE(sc, WPI_TX_BASE_PTR, sc->shared_dma.paddr); |
3173 | WPI_WRITE(sc, WPI_MSG_CONFIG, 0xffff05a5); |
3174 | |
3175 | for (qid = 0; qid < 6; qid++) { |
3176 | WPI_WRITE(sc, WPI_TX_CTL(qid), 0); |
3177 | WPI_WRITE(sc, WPI_TX_BASE(qid), 0); |
3178 | WPI_WRITE(sc, WPI_TX_CONFIG(qid), 0x80200008); |
3179 | } |
3180 | wpi_mem_unlock(sc); |
3181 | |
3182 | /* clear "radio off" and "disable command" bits (reversed logic) */ |
3183 | WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); |
3184 | WPI_WRITE(sc, WPI_UCODE_CLR, WPI_DISABLE_CMD); |
3185 | |
3186 | /* clear any pending interrupts */ |
3187 | WPI_WRITE(sc, WPI_INTR, 0xffffffff); |
3188 | /* enable interrupts */ |
3189 | WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); |
3190 | |
3191 | /* not sure why/if this is necessary... */ |
3192 | WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); |
3193 | WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); |
3194 | |
3195 | if ((error = wpi_load_firmware(sc)) != 0) |
3196 | /* wpi_load_firmware prints error messages for us. */ |
3197 | goto fail1; |
3198 | |
3199 | /* Check the status of the radio switch */ |
3200 | mutex_enter(&sc->sc_rsw_mtx); |
3201 | if (wpi_getrfkill(sc)) { |
3202 | mutex_exit(&sc->sc_rsw_mtx); |
3203 | aprint_error_dev(sc->sc_dev, |
3204 | "radio is disabled by hardware switch\n" ); |
3205 | ifp->if_flags &= ~IFF_UP; |
3206 | error = EBUSY; |
3207 | goto fail1; |
3208 | } |
3209 | mutex_exit(&sc->sc_rsw_mtx); |
3210 | |
3211 | /* wait for thermal sensors to calibrate */ |
3212 | for (ntries = 0; ntries < 1000; ntries++) { |
3213 | if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0) |
3214 | break; |
3215 | DELAY(10); |
3216 | } |
3217 | if (ntries == 1000) { |
3218 | aprint_error_dev(sc->sc_dev, |
3219 | "timeout waiting for thermal sensors calibration\n" ); |
3220 | error = ETIMEDOUT; |
3221 | goto fail1; |
3222 | } |
3223 | DPRINTF(("temperature %d\n" , sc->temp)); |
3224 | |
3225 | if ((error = wpi_config(sc)) != 0) { |
3226 | aprint_error_dev(sc->sc_dev, "could not configure device\n" ); |
3227 | goto fail1; |
3228 | } |
3229 | |
3230 | ifp->if_flags &= ~IFF_OACTIVE; |
3231 | ifp->if_flags |= IFF_RUNNING; |
3232 | |
3233 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { |
3234 | if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) |
3235 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); |
3236 | } |
3237 | else |
3238 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); |
3239 | |
3240 | return 0; |
3241 | |
3242 | fail1: wpi_stop(ifp, 1); |
3243 | return error; |
3244 | } |
3245 | |
3246 | static void |
3247 | wpi_stop(struct ifnet *ifp, int disable) |
3248 | { |
3249 | struct wpi_softc *sc = ifp->if_softc; |
3250 | struct ieee80211com *ic = &sc->sc_ic; |
3251 | uint32_t tmp; |
3252 | int ac; |
3253 | |
3254 | ifp->if_timer = sc->sc_tx_timer = 0; |
3255 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
3256 | |
3257 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); |
3258 | |
3259 | /* disable interrupts */ |
3260 | WPI_WRITE(sc, WPI_MASK, 0); |
3261 | WPI_WRITE(sc, WPI_INTR, WPI_INTR_MASK); |
3262 | WPI_WRITE(sc, WPI_INTR_STATUS, 0xff); |
3263 | WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000); |
3264 | |
3265 | wpi_mem_lock(sc); |
3266 | wpi_mem_write(sc, WPI_MEM_MODE, 0); |
3267 | wpi_mem_unlock(sc); |
3268 | |
3269 | /* reset all Tx rings */ |
3270 | for (ac = 0; ac < 4; ac++) |
3271 | wpi_reset_tx_ring(sc, &sc->txq[ac]); |
3272 | wpi_reset_tx_ring(sc, &sc->cmdq); |
3273 | |
3274 | /* reset Rx ring */ |
3275 | wpi_reset_rx_ring(sc, &sc->rxq); |
3276 | |
3277 | wpi_mem_lock(sc); |
3278 | wpi_mem_write(sc, WPI_MEM_CLOCK2, 0x200); |
3279 | wpi_mem_unlock(sc); |
3280 | |
3281 | DELAY(5); |
3282 | |
3283 | wpi_stop_master(sc); |
3284 | |
3285 | tmp = WPI_READ(sc, WPI_RESET); |
3286 | WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET); |
3287 | } |
3288 | |
3289 | static bool |
3290 | wpi_resume(device_t dv, const pmf_qual_t *qual) |
3291 | { |
3292 | struct wpi_softc *sc = device_private(dv); |
3293 | |
3294 | (void)wpi_reset(sc); |
3295 | |
3296 | return true; |
3297 | } |
3298 | |
3299 | /* |
3300 | * Return whether or not the radio is enabled in hardware |
3301 | * (i.e. the rfkill switch is "off"). |
3302 | */ |
3303 | static int |
3304 | wpi_getrfkill(struct wpi_softc *sc) |
3305 | { |
3306 | uint32_t tmp; |
3307 | |
3308 | wpi_mem_lock(sc); |
3309 | tmp = wpi_mem_read(sc, WPI_MEM_RFKILL); |
3310 | wpi_mem_unlock(sc); |
3311 | |
3312 | KASSERT(mutex_owned(&sc->sc_rsw_mtx)); |
3313 | if (tmp & 0x01) { |
3314 | /* switch is on */ |
3315 | if (sc->sc_rsw_status != WPI_RSW_ON) { |
3316 | sc->sc_rsw_status = WPI_RSW_ON; |
3317 | sysmon_pswitch_event(&sc->sc_rsw, |
3318 | PSWITCH_EVENT_PRESSED); |
3319 | } |
3320 | } else { |
3321 | /* switch is off */ |
3322 | if (sc->sc_rsw_status != WPI_RSW_OFF) { |
3323 | sc->sc_rsw_status = WPI_RSW_OFF; |
3324 | sysmon_pswitch_event(&sc->sc_rsw, |
3325 | PSWITCH_EVENT_RELEASED); |
3326 | } |
3327 | } |
3328 | |
3329 | return !(tmp & 0x01); |
3330 | } |
3331 | |
3332 | static int |
3333 | wpi_sysctl_radio(SYSCTLFN_ARGS) |
3334 | { |
3335 | struct sysctlnode node; |
3336 | struct wpi_softc *sc; |
3337 | int val, error; |
3338 | |
3339 | node = *rnode; |
3340 | sc = (struct wpi_softc *)node.sysctl_data; |
3341 | |
3342 | mutex_enter(&sc->sc_rsw_mtx); |
3343 | val = !wpi_getrfkill(sc); |
3344 | mutex_exit(&sc->sc_rsw_mtx); |
3345 | |
3346 | node.sysctl_data = &val; |
3347 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); |
3348 | |
3349 | if (error || newp == NULL) |
3350 | return error; |
3351 | |
3352 | return 0; |
3353 | } |
3354 | |
3355 | static void |
3356 | wpi_sysctlattach(struct wpi_softc *sc) |
3357 | { |
3358 | int rc; |
3359 | const struct sysctlnode *rnode; |
3360 | const struct sysctlnode *cnode; |
3361 | |
3362 | struct sysctllog **clog = &sc->sc_sysctllog; |
3363 | |
3364 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, |
3365 | CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(sc->sc_dev), |
3366 | SYSCTL_DESCR("wpi controls and statistics" ), |
3367 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) |
3368 | goto err; |
3369 | |
3370 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, |
3371 | CTLFLAG_PERMANENT, CTLTYPE_INT, "radio" , |
3372 | SYSCTL_DESCR("radio transmitter switch state (0=off, 1=on)" ), |
3373 | wpi_sysctl_radio, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL)) != 0) |
3374 | goto err; |
3375 | |
3376 | #ifdef WPI_DEBUG |
3377 | /* control debugging printfs */ |
3378 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, |
3379 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
3380 | "debug" , SYSCTL_DESCR("Enable debugging output" ), |
3381 | NULL, 0, &wpi_debug, 0, CTL_CREATE, CTL_EOL)) != 0) |
3382 | goto err; |
3383 | #endif |
3384 | |
3385 | return; |
3386 | err: |
3387 | aprint_error("%s: sysctl_createv failed (rc = %d)\n" , __func__, rc); |
3388 | } |
3389 | |
3390 | static void |
3391 | wpi_rsw_thread(void *arg) |
3392 | { |
3393 | struct wpi_softc *sc = (struct wpi_softc *)arg; |
3394 | |
3395 | mutex_enter(&sc->sc_rsw_mtx); |
3396 | for (;;) { |
3397 | cv_timedwait(&sc->sc_rsw_cv, &sc->sc_rsw_mtx, hz); |
3398 | if (sc->sc_dying) { |
3399 | sc->sc_rsw_lwp = NULL; |
3400 | cv_broadcast(&sc->sc_rsw_cv); |
3401 | mutex_exit(&sc->sc_rsw_mtx); |
3402 | kthread_exit(0); |
3403 | } |
3404 | wpi_getrfkill(sc); |
3405 | } |
3406 | } |
3407 | |
3408 | |