Annotation of sys/dev/ic/pgt.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pgt.c,v 1.43 2007/07/18 18:10:31 damien Exp $ */
2:
3: /*
4: * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5: * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org>
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: /*
21: * Copyright (c) 2004 Fujitsu Laboratories of America, Inc.
22: * Copyright (c) 2004 Brian Fundakowski Feldman
23: * All rights reserved.
24: *
25: * Redistribution and use in source and binary forms, with or without
26: * modification, are permitted provided that the following conditions
27: * are met:
28: * 1. Redistributions of source code must retain the above copyright
29: * notice, this list of conditions and the following disclaimer.
30: * 2. Redistributions in binary form must reproduce the above copyright
31: * notice, this list of conditions and the following disclaimer in the
32: * documentation and/or other materials provided with the distribution.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
35: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
38: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: * SUCH DAMAGE.
45: */
46:
47: #include <sys/cdefs.h>
48: #include "bpfilter.h"
49:
50: #include <sys/param.h>
51: #include <sys/systm.h>
52: #include <sys/kernel.h>
53: #include <sys/malloc.h>
54: #include <sys/socket.h>
55: #include <sys/mbuf.h>
56: #include <sys/endian.h>
57: #include <sys/sockio.h>
58: #include <sys/sysctl.h>
59: #include <sys/kthread.h>
60: #include <sys/time.h>
61: #include <sys/ioctl.h>
62: #include <sys/device.h>
63:
64: #include <machine/bus.h>
65: #include <machine/endian.h>
66: #include <machine/intr.h>
67:
68: #include <net/if.h>
69: #include <net/if_arp.h>
70: #include <net/if_dl.h>
71: #include <net/if_llc.h>
72: #include <net/if_media.h>
73: #include <net/if_types.h>
74:
75: #if NBPFILTER > 0
76: #include <net/bpf.h>
77: #endif
78:
79: #ifdef INET
80: #include <netinet/in.h>
81: #include <netinet/in_systm.h>
82: #include <netinet/in_var.h>
83: #include <netinet/if_ether.h>
84: #include <netinet/ip.h>
85: #endif
86:
87: #include <net80211/ieee80211_var.h>
88: #include <net80211/ieee80211_radiotap.h>
89:
90: #include <dev/ic/pgtreg.h>
91: #include <dev/ic/pgtvar.h>
92:
93: #include <dev/ic/if_wireg.h>
94: #include <dev/ic/if_wi_ieee.h>
95: #include <dev/ic/if_wivar.h>
96:
97: #ifdef PGT_DEBUG
98: #define DPRINTF(x) do { printf x; } while (0)
99: #else
100: #define DPRINTF(x)
101: #endif
102:
103: #define SETOID(oid, var, size) { \
104: if (pgt_oid_set(sc, oid, var, size) != 0) \
105: break; \
106: }
107:
108: /*
109: * This is a driver for the Intersil Prism family of 802.11g network cards,
110: * based upon version 1.2 of the Linux driver and firmware found at
111: * http://www.prism54.org/.
112: */
113:
114: #define SCAN_TIMEOUT 5 /* 5 seconds */
115:
116: struct cfdriver pgt_cd = {
117: NULL, "pgt", DV_IFNET
118: };
119:
120: void pgt_media_status(struct ifnet *ifp, struct ifmediareq *imr);
121: int pgt_media_change(struct ifnet *ifp);
122: void pgt_write_memory_barrier(struct pgt_softc *);
123: uint32_t pgt_read_4(struct pgt_softc *, uint16_t);
124: void pgt_write_4(struct pgt_softc *, uint16_t, uint32_t);
125: void pgt_write_4_flush(struct pgt_softc *, uint16_t, uint32_t);
126: void pgt_debug_events(struct pgt_softc *, const char *);
127: uint32_t pgt_queue_frags_pending(struct pgt_softc *, enum pgt_queue);
128: void pgt_reinit_rx_desc_frag(struct pgt_softc *, struct pgt_desc *);
129: int pgt_load_tx_desc_frag(struct pgt_softc *, enum pgt_queue,
130: struct pgt_desc *);
131: void pgt_unload_tx_desc_frag(struct pgt_softc *, struct pgt_desc *);
132: int pgt_load_firmware(struct pgt_softc *);
133: void pgt_cleanup_queue(struct pgt_softc *, enum pgt_queue,
134: struct pgt_frag []);
135: int pgt_reset(struct pgt_softc *);
136: void pgt_stop(struct pgt_softc *, unsigned int);
137: void pgt_reboot(struct pgt_softc *);
138: void pgt_init_intr(struct pgt_softc *);
139: void pgt_update_intr(struct pgt_softc *, int);
140: struct mbuf
141: *pgt_ieee80211_encap(struct pgt_softc *, struct ether_header *,
142: struct mbuf *, struct ieee80211_node **);
143: void pgt_input_frames(struct pgt_softc *, struct mbuf *);
144: void pgt_wakeup_intr(struct pgt_softc *);
145: void pgt_sleep_intr(struct pgt_softc *);
146: void pgt_empty_traps(struct pgt_softc_kthread *);
147: void pgt_per_device_kthread(void *);
148: void pgt_async_reset(struct pgt_softc *);
149: void pgt_async_update(struct pgt_softc *);
150: void pgt_txdone(struct pgt_softc *, enum pgt_queue);
151: void pgt_rxdone(struct pgt_softc *, enum pgt_queue);
152: void pgt_trap_received(struct pgt_softc *, uint32_t, void *, size_t);
153: void pgt_mgmtrx_completion(struct pgt_softc *, struct pgt_mgmt_desc *);
154: struct mbuf
155: *pgt_datarx_completion(struct pgt_softc *, enum pgt_queue);
156: int pgt_oid_get(struct pgt_softc *, enum pgt_oid, void *, size_t);
157: int pgt_oid_retrieve(struct pgt_softc *, enum pgt_oid, void *, size_t);
158: int pgt_oid_set(struct pgt_softc *, enum pgt_oid, const void *, size_t);
159: void pgt_state_dump(struct pgt_softc *);
160: int pgt_mgmt_request(struct pgt_softc *, struct pgt_mgmt_desc *);
161: void pgt_desc_transmit(struct pgt_softc *, enum pgt_queue,
162: struct pgt_desc *, uint16_t, int);
163: void pgt_maybe_trigger(struct pgt_softc *, enum pgt_queue);
164: struct ieee80211_node
165: *pgt_ieee80211_node_alloc(struct ieee80211com *);
166: void pgt_ieee80211_newassoc(struct ieee80211com *,
167: struct ieee80211_node *, int);
168: void pgt_ieee80211_node_free(struct ieee80211com *,
169: struct ieee80211_node *);
170: void pgt_ieee80211_node_copy(struct ieee80211com *,
171: struct ieee80211_node *,
172: const struct ieee80211_node *);
173: int pgt_ieee80211_send_mgmt(struct ieee80211com *,
174: struct ieee80211_node *, int, int);
175: int pgt_net_attach(struct pgt_softc *);
176: void pgt_start(struct ifnet *);
177: int pgt_ioctl(struct ifnet *, u_long, caddr_t);
178: void pgt_obj_bss2scanres(struct pgt_softc *,
179: struct pgt_obj_bss *, struct wi_scan_res *, uint32_t);
180: void node_mark_active_ap(void *, struct ieee80211_node *);
181: void node_mark_active_adhoc(void *, struct ieee80211_node *);
182: void pgt_watchdog(struct ifnet *);
183: int pgt_init(struct ifnet *);
184: void pgt_update_hw_from_sw(struct pgt_softc *, int, int);
185: void pgt_hostap_handle_mlme(struct pgt_softc *, uint32_t,
186: struct pgt_obj_mlme *);
187: void pgt_update_sw_from_hw(struct pgt_softc *,
188: struct pgt_async_trap *, struct mbuf *);
189: int pgt_newstate(struct ieee80211com *, enum ieee80211_state, int);
190: int pgt_drain_tx_queue(struct pgt_softc *, enum pgt_queue);
191: int pgt_dma_alloc(struct pgt_softc *);
192: int pgt_dma_alloc_queue(struct pgt_softc *sc, enum pgt_queue pq);
193: void pgt_dma_free(struct pgt_softc *);
194: void pgt_dma_free_queue(struct pgt_softc *sc, enum pgt_queue pq);
195: void pgt_shutdown(void *);
196: void pgt_power(int, void *);
197:
198: void
199: pgt_write_memory_barrier(struct pgt_softc *sc)
200: {
201: bus_space_barrier(sc->sc_iotag, sc->sc_iohandle, 0, 0,
202: BUS_SPACE_BARRIER_WRITE);
203: }
204:
205: u_int32_t
206: pgt_read_4(struct pgt_softc *sc, uint16_t offset)
207: {
208: return (bus_space_read_4(sc->sc_iotag, sc->sc_iohandle, offset));
209: }
210:
211: void
212: pgt_write_4(struct pgt_softc *sc, uint16_t offset, uint32_t value)
213: {
214: bus_space_write_4(sc->sc_iotag, sc->sc_iohandle, offset, value);
215: }
216:
217: /*
218: * Write out 4 bytes and cause a PCI flush by reading back in on a
219: * harmless register.
220: */
221: void
222: pgt_write_4_flush(struct pgt_softc *sc, uint16_t offset, uint32_t value)
223: {
224: bus_space_write_4(sc->sc_iotag, sc->sc_iohandle, offset, value);
225: (void)bus_space_read_4(sc->sc_iotag, sc->sc_iohandle, PGT_REG_INT_EN);
226: }
227:
228: /*
229: * Print the state of events in the queues from an interrupt or a trigger.
230: */
231: void
232: pgt_debug_events(struct pgt_softc *sc, const char *when)
233: {
234: #define COUNT(i) \
235: letoh32(sc->sc_cb->pcb_driver_curfrag[i]) - \
236: letoh32(sc->sc_cb->pcb_device_curfrag[i])
237: if (sc->sc_debug & SC_DEBUG_EVENTS)
238: DPRINTF(("%s: ev%s: %u %u %u %u %u %u\n",
239: sc->sc_dev.dv_xname, when, COUNT(0), COUNT(1), COUNT(2),
240: COUNT(3), COUNT(4), COUNT(5)));
241: #undef COUNT
242: }
243:
244: uint32_t
245: pgt_queue_frags_pending(struct pgt_softc *sc, enum pgt_queue pq)
246: {
247: return (letoh32(sc->sc_cb->pcb_driver_curfrag[pq]) -
248: letoh32(sc->sc_cb->pcb_device_curfrag[pq]));
249: }
250:
251: void
252: pgt_reinit_rx_desc_frag(struct pgt_softc *sc, struct pgt_desc *pd)
253: {
254: pd->pd_fragp->pf_addr = htole32((uint32_t)pd->pd_dmaaddr);
255: pd->pd_fragp->pf_size = htole16(PGT_FRAG_SIZE);
256: pd->pd_fragp->pf_flags = 0;
257:
258: bus_dmamap_sync(sc->sc_dmat, pd->pd_dmam, 0, pd->pd_dmam->dm_mapsize,
259: BUS_DMASYNC_POSTWRITE);
260: }
261:
262: int
263: pgt_load_tx_desc_frag(struct pgt_softc *sc, enum pgt_queue pq,
264: struct pgt_desc *pd)
265: {
266: int error;
267:
268: error = bus_dmamap_load(sc->sc_dmat, pd->pd_dmam, pd->pd_mem,
269: PGT_FRAG_SIZE, NULL, BUS_DMA_NOWAIT);
270: if (error) {
271: DPRINTF(("%s: unable to load %s tx DMA: %d\n",
272: sc->sc_dev.dv_xname,
273: pgt_queue_is_data(pq) ? "data" : "mgmt", error));
274: return (error);
275: }
276: pd->pd_dmaaddr = pd->pd_dmam->dm_segs[0].ds_addr;
277: pd->pd_fragp->pf_addr = htole32((uint32_t)pd->pd_dmaaddr);
278: pd->pd_fragp->pf_size = htole16(PGT_FRAG_SIZE);
279: pd->pd_fragp->pf_flags = htole16(0);
280:
281: bus_dmamap_sync(sc->sc_dmat, pd->pd_dmam, 0, pd->pd_dmam->dm_mapsize,
282: BUS_DMASYNC_POSTWRITE);
283:
284: return (0);
285: }
286:
287: void
288: pgt_unload_tx_desc_frag(struct pgt_softc *sc, struct pgt_desc *pd)
289: {
290: bus_dmamap_unload(sc->sc_dmat, pd->pd_dmam);
291: pd->pd_dmaaddr = 0;
292: }
293:
294: int
295: pgt_load_firmware(struct pgt_softc *sc)
296: {
297: int error, reg, dirreg, fwoff, ucodeoff, fwlen;
298: uint8_t *ucode;
299: uint32_t *uc;
300: size_t size;
301: char *name;
302:
303: if (sc->sc_flags & SC_ISL3877)
304: name = "pgt-isl3877";
305: else
306: name = "pgt-isl3890"; /* includes isl3880 */
307:
308: error = loadfirmware(name, &ucode, &size);
309:
310: if (error != 0) {
311: DPRINTF(("%s: error %d, could not read microcode %s!\n",
312: sc->sc_dev.dv_xname, error, name));
313: return (EIO);
314: }
315:
316: if (size & 3) {
317: DPRINTF(("%s: bad firmware size %u\n",
318: sc->sc_dev.dv_xname, size));
319: free(ucode, M_DEVBUF);
320: return (EINVAL);
321: }
322:
323: pgt_reboot(sc);
324:
325: fwoff = 0;
326: ucodeoff = 0;
327: uc = (uint32_t *)ucode;
328: reg = PGT_FIRMWARE_INTERNAL_OFFSET;
329: while (fwoff < size) {
330: pgt_write_4_flush(sc, PGT_REG_DIR_MEM_BASE, reg);
331:
332: if ((size - fwoff) >= PGT_DIRECT_MEMORY_SIZE)
333: fwlen = PGT_DIRECT_MEMORY_SIZE;
334: else
335: fwlen = size - fwoff;
336:
337: dirreg = PGT_DIRECT_MEMORY_OFFSET;
338: while (fwlen > 4) {
339: pgt_write_4(sc, dirreg, uc[ucodeoff]);
340: fwoff += 4;
341: dirreg += 4;
342: reg += 4;
343: fwlen -= 4;
344: ucodeoff++;
345: }
346: pgt_write_4_flush(sc, dirreg, uc[ucodeoff]);
347: fwoff += 4;
348: dirreg += 4;
349: reg += 4;
350: fwlen -= 4;
351: ucodeoff++;
352: }
353: DPRINTF(("%s: %d bytes microcode loaded from %s\n",
354: sc->sc_dev.dv_xname, fwoff, name));
355:
356: reg = pgt_read_4(sc, PGT_REG_CTRL_STAT);
357: reg &= ~(PGT_CTRL_STAT_RESET | PGT_CTRL_STAT_CLOCKRUN);
358: reg |= PGT_CTRL_STAT_RAMBOOT;
359: pgt_write_4_flush(sc, PGT_REG_CTRL_STAT, reg);
360: pgt_write_memory_barrier(sc);
361: DELAY(PGT_WRITEIO_DELAY);
362:
363: reg |= PGT_CTRL_STAT_RESET;
364: pgt_write_4(sc, PGT_REG_CTRL_STAT, reg);
365: pgt_write_memory_barrier(sc);
366: DELAY(PGT_WRITEIO_DELAY);
367:
368: reg &= ~PGT_CTRL_STAT_RESET;
369: pgt_write_4(sc, PGT_REG_CTRL_STAT, reg);
370: pgt_write_memory_barrier(sc);
371: DELAY(PGT_WRITEIO_DELAY);
372:
373: free(ucode, M_DEVBUF);
374:
375: return (0);
376: }
377:
378: void
379: pgt_cleanup_queue(struct pgt_softc *sc, enum pgt_queue pq,
380: struct pgt_frag pqfrags[])
381: {
382: struct pgt_desc *pd;
383: unsigned int i;
384:
385: sc->sc_cb->pcb_device_curfrag[pq] = 0;
386: i = 0;
387: /* XXX why only freeq ??? */
388: TAILQ_FOREACH(pd, &sc->sc_freeq[pq], pd_link) {
389: pd->pd_fragnum = i;
390: pd->pd_fragp = &pqfrags[i];
391: if (pgt_queue_is_rx(pq))
392: pgt_reinit_rx_desc_frag(sc, pd);
393: i++;
394: }
395: sc->sc_freeq_count[pq] = i;
396: /*
397: * The ring buffer describes how many free buffers are available from
398: * the host (for receive queues) or how many are pending (for
399: * transmit queues).
400: */
401: if (pgt_queue_is_rx(pq))
402: sc->sc_cb->pcb_driver_curfrag[pq] = htole32(i);
403: else
404: sc->sc_cb->pcb_driver_curfrag[pq] = 0;
405: }
406:
407: /*
408: * Turn off interrupts, reset the device (possibly loading firmware),
409: * and put everything in a known state.
410: */
411: int
412: pgt_reset(struct pgt_softc *sc)
413: {
414: int error;
415:
416: /* disable all interrupts */
417: pgt_write_4_flush(sc, PGT_REG_INT_EN, 0);
418: DELAY(PGT_WRITEIO_DELAY);
419:
420: /*
421: * Set up the management receive queue, assuming there are no
422: * requests in progress.
423: */
424: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
425: sc->sc_cbdmam->dm_mapsize,
426: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE);
427: pgt_cleanup_queue(sc, PGT_QUEUE_DATA_LOW_RX,
428: &sc->sc_cb->pcb_data_low_rx[0]);
429: pgt_cleanup_queue(sc, PGT_QUEUE_DATA_LOW_TX,
430: &sc->sc_cb->pcb_data_low_tx[0]);
431: pgt_cleanup_queue(sc, PGT_QUEUE_DATA_HIGH_RX,
432: &sc->sc_cb->pcb_data_high_rx[0]);
433: pgt_cleanup_queue(sc, PGT_QUEUE_DATA_HIGH_TX,
434: &sc->sc_cb->pcb_data_high_tx[0]);
435: pgt_cleanup_queue(sc, PGT_QUEUE_MGMT_RX,
436: &sc->sc_cb->pcb_mgmt_rx[0]);
437: pgt_cleanup_queue(sc, PGT_QUEUE_MGMT_TX,
438: &sc->sc_cb->pcb_mgmt_tx[0]);
439: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
440: sc->sc_cbdmam->dm_mapsize,
441: BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_PREREAD);
442:
443: /* load firmware */
444: if (sc->sc_flags & SC_NEEDS_FIRMWARE) {
445: error = pgt_load_firmware(sc);
446: if (error) {
447: printf("%s: firmware load failed\n",
448: sc->sc_dev.dv_xname);
449: return (error);
450: }
451: sc->sc_flags &= ~SC_NEEDS_FIRMWARE;
452: DPRINTF(("%s: firmware loaded\n", sc->sc_dev.dv_xname));
453: }
454:
455: /* upload the control block's DMA address */
456: pgt_write_4_flush(sc, PGT_REG_CTRL_BLK_BASE,
457: htole32((uint32_t)sc->sc_cbdmam->dm_segs[0].ds_addr));
458: DELAY(PGT_WRITEIO_DELAY);
459:
460: /* send a reset event */
461: pgt_write_4_flush(sc, PGT_REG_DEV_INT, PGT_DEV_INT_RESET);
462: DELAY(PGT_WRITEIO_DELAY);
463:
464: /* await only the initialization interrupt */
465: pgt_write_4_flush(sc, PGT_REG_INT_EN, PGT_INT_STAT_INIT);
466: DELAY(PGT_WRITEIO_DELAY);
467:
468: return (0);
469: }
470:
471: /*
472: * If we're trying to reset and the device has seemingly not been detached,
473: * we'll spend a minute seeing if we can't do the reset.
474: */
475: void
476: pgt_stop(struct pgt_softc *sc, unsigned int flag)
477: {
478: struct ieee80211com *ic;
479: unsigned int wokeup;
480: int tryagain = 0;
481:
482: ic = &sc->sc_ic;
483:
484: ic->ic_if.if_flags &= ~IFF_RUNNING;
485: sc->sc_flags |= SC_UNINITIALIZED;
486: sc->sc_flags |= flag;
487:
488: pgt_drain_tx_queue(sc, PGT_QUEUE_DATA_LOW_TX);
489: pgt_drain_tx_queue(sc, PGT_QUEUE_DATA_HIGH_TX);
490: pgt_drain_tx_queue(sc, PGT_QUEUE_MGMT_TX);
491:
492: trying_again:
493: /* disable all interrupts */
494: pgt_write_4_flush(sc, PGT_REG_INT_EN, 0);
495: DELAY(PGT_WRITEIO_DELAY);
496:
497: /* reboot card */
498: pgt_reboot(sc);
499:
500: do {
501: wokeup = 0;
502: /*
503: * We don't expect to be woken up, just to drop the lock
504: * and time out. Only tx queues can have anything valid
505: * on them outside of an interrupt.
506: */
507: while (!TAILQ_EMPTY(&sc->sc_mgmtinprog)) {
508: struct pgt_mgmt_desc *pmd;
509:
510: pmd = TAILQ_FIRST(&sc->sc_mgmtinprog);
511: TAILQ_REMOVE(&sc->sc_mgmtinprog, pmd, pmd_link);
512: pmd->pmd_error = ENETRESET;
513: wakeup_one(pmd);
514: if (sc->sc_debug & SC_DEBUG_MGMT)
515: DPRINTF(("%s: queue: mgmt %p <- %#x "
516: "(drained)\n", sc->sc_dev.dv_xname,
517: pmd, pmd->pmd_oid));
518: wokeup++;
519: }
520: if (wokeup > 0) {
521: if (flag == SC_NEEDS_RESET && sc->sc_flags & SC_DYING) {
522: sc->sc_flags &= ~flag;
523: return;
524: }
525: }
526: } while (wokeup > 0);
527:
528: if (flag == SC_NEEDS_RESET) {
529: int error;
530:
531: DPRINTF(("%s: resetting\n", sc->sc_dev.dv_xname));
532: sc->sc_flags &= ~SC_POWERSAVE;
533: sc->sc_flags |= SC_NEEDS_FIRMWARE;
534: error = pgt_reset(sc);
535: if (error == 0) {
536: tsleep(&sc->sc_flags, 0, "pgtres", hz);
537: if (sc->sc_flags & SC_UNINITIALIZED) {
538: printf("%s: not responding\n",
539: sc->sc_dev.dv_xname);
540: /* Thud. It was probably removed. */
541: if (tryagain)
542: panic("pgt went for lunch"); /* XXX */
543: tryagain = 1;
544: } else {
545: /* await all interrupts */
546: pgt_write_4_flush(sc, PGT_REG_INT_EN,
547: PGT_INT_STAT_SOURCES);
548: DELAY(PGT_WRITEIO_DELAY);
549: ic->ic_if.if_flags |= IFF_RUNNING;
550: }
551: }
552:
553: if (tryagain)
554: goto trying_again;
555:
556: sc->sc_flags &= ~flag;
557: if (ic->ic_if.if_flags & IFF_RUNNING)
558: pgt_update_hw_from_sw(sc,
559: ic->ic_state != IEEE80211_S_INIT,
560: ic->ic_opmode != IEEE80211_M_MONITOR);
561: }
562:
563: ic->ic_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
564: ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
565: }
566:
567: void
568: pgt_attach(void *xsc)
569: {
570: struct pgt_softc *sc = xsc;
571: int error;
572:
573: /* debug flags */
574: //sc->sc_debug |= SC_DEBUG_QUEUES; /* super verbose */
575: //sc->sc_debug |= SC_DEBUG_MGMT;
576: sc->sc_debug |= SC_DEBUG_UNEXPECTED;
577: //sc->sc_debug |= SC_DEBUG_TRIGGER; /* verbose */
578: //sc->sc_debug |= SC_DEBUG_EVENTS; /* super verbose */
579: //sc->sc_debug |= SC_DEBUG_POWER;
580: sc->sc_debug |= SC_DEBUG_TRAP;
581: sc->sc_debug |= SC_DEBUG_LINK;
582: //sc->sc_debug |= SC_DEBUG_RXANNEX;
583: //sc->sc_debug |= SC_DEBUG_RXFRAG;
584: //sc->sc_debug |= SC_DEBUG_RXETHER;
585:
586: /* enable card if possible */
587: if (sc->sc_enable != NULL)
588: (*sc->sc_enable)(sc);
589:
590: error = pgt_dma_alloc(sc);
591: if (error)
592: return;
593:
594: sc->sc_ic.ic_if.if_softc = sc;
595: TAILQ_INIT(&sc->sc_mgmtinprog);
596: TAILQ_INIT(&sc->sc_kthread.sck_traps);
597: sc->sc_flags |= SC_NEEDS_FIRMWARE | SC_UNINITIALIZED;
598: sc->sc_80211_ioc_auth = IEEE80211_AUTH_OPEN;
599:
600: error = pgt_reset(sc);
601: if (error)
602: return;
603:
604: tsleep(&sc->sc_flags, 0, "pgtres", hz);
605: if (sc->sc_flags & SC_UNINITIALIZED) {
606: printf("%s: not responding\n", sc->sc_dev.dv_xname);
607: return;
608: } else {
609: /* await all interrupts */
610: pgt_write_4_flush(sc, PGT_REG_INT_EN, PGT_INT_STAT_SOURCES);
611: DELAY(PGT_WRITEIO_DELAY);
612: }
613:
614: error = pgt_net_attach(sc);
615: if (error)
616: return;
617:
618: if (kthread_create(pgt_per_device_kthread, sc, NULL,
619: sc->sc_dev.dv_xname) != 0)
620: return;
621:
622: ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
623: }
624:
625: int
626: pgt_detach(struct pgt_softc *sc)
627: {
628: if (sc->sc_flags & SC_NEEDS_FIRMWARE || sc->sc_flags & SC_UNINITIALIZED)
629: /* device was not initialized correctly, so leave early */
630: goto out;
631:
632: /* stop card */
633: pgt_stop(sc, SC_DYING);
634: pgt_reboot(sc);
635:
636: /*
637: * Disable shutdown and power hooks
638: */
639: if (sc->sc_shutdown_hook != NULL)
640: shutdownhook_disestablish(sc->sc_shutdown_hook);
641: if (sc->sc_power_hook != NULL)
642: powerhook_disestablish(sc->sc_power_hook);
643:
644: ieee80211_ifdetach(&sc->sc_ic.ic_if);
645: if_detach(&sc->sc_ic.ic_if);
646:
647: out:
648: /* disable card if possible */
649: if (sc->sc_disable != NULL)
650: (*sc->sc_disable)(sc);
651:
652: pgt_dma_free(sc);
653:
654: return (0);
655: }
656:
657: void
658: pgt_reboot(struct pgt_softc *sc)
659: {
660: uint32_t reg;
661:
662: reg = pgt_read_4(sc, PGT_REG_CTRL_STAT);
663: reg &= ~(PGT_CTRL_STAT_RESET | PGT_CTRL_STAT_RAMBOOT);
664: pgt_write_4(sc, PGT_REG_CTRL_STAT, reg);
665: pgt_write_memory_barrier(sc);
666: DELAY(PGT_WRITEIO_DELAY);
667:
668: reg |= PGT_CTRL_STAT_RESET;
669: pgt_write_4(sc, PGT_REG_CTRL_STAT, reg);
670: pgt_write_memory_barrier(sc);
671: DELAY(PGT_WRITEIO_DELAY);
672:
673: reg &= ~PGT_CTRL_STAT_RESET;
674: pgt_write_4(sc, PGT_REG_CTRL_STAT, reg);
675: pgt_write_memory_barrier(sc);
676: DELAY(PGT_RESET_DELAY);
677: }
678:
679: void
680: pgt_init_intr(struct pgt_softc *sc)
681: {
682: if ((sc->sc_flags & SC_UNINITIALIZED) == 0) {
683: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
684: DPRINTF(("%s: spurious initialization\n",
685: sc->sc_dev.dv_xname));
686: } else {
687: sc->sc_flags &= ~SC_UNINITIALIZED;
688: wakeup(&sc->sc_flags);
689: }
690: }
691:
692: /*
693: * If called with a NULL last_nextpkt, only the mgmt queue will be checked
694: * for new packets.
695: */
696: void
697: pgt_update_intr(struct pgt_softc *sc, int hack)
698: {
699: /* priority order */
700: enum pgt_queue pqs[PGT_QUEUE_COUNT] = {
701: PGT_QUEUE_MGMT_TX, PGT_QUEUE_MGMT_RX,
702: PGT_QUEUE_DATA_HIGH_TX, PGT_QUEUE_DATA_HIGH_RX,
703: PGT_QUEUE_DATA_LOW_TX, PGT_QUEUE_DATA_LOW_RX
704: };
705: struct mbuf *m;
706: uint32_t npend;
707: unsigned int dirtycount;
708: int i;
709:
710: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
711: sc->sc_cbdmam->dm_mapsize,
712: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE);
713: pgt_debug_events(sc, "intr");
714: /*
715: * Check for completion of tx in their dirty queues.
716: * Check completion of rx into their dirty queues.
717: */
718: for (i = 0; i < PGT_QUEUE_COUNT; i++) {
719: size_t qdirty, qfree, qtotal;
720:
721: qdirty = sc->sc_dirtyq_count[pqs[i]];
722: qfree = sc->sc_freeq_count[pqs[i]];
723: qtotal = qdirty + qfree;
724: /*
725: * We want the wrap-around here.
726: */
727: if (pgt_queue_is_rx(pqs[i])) {
728: int data;
729:
730: data = pgt_queue_is_data(pqs[i]);
731: #ifdef PGT_BUGGY_INTERRUPT_RECOVERY
732: if (hack && data)
733: continue;
734: #endif
735: npend = pgt_queue_frags_pending(sc, pqs[i]);
736: /*
737: * Receive queues clean up below, so qfree must
738: * always be qtotal (qdirty is 0).
739: */
740: if (npend > qfree) {
741: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
742: DPRINTF(("%s: rx queue [%u] "
743: "overflowed by %u\n",
744: sc->sc_dev.dv_xname, pqs[i],
745: npend - qfree));
746: sc->sc_flags |= SC_INTR_RESET;
747: break;
748: }
749: while (qfree-- > npend)
750: pgt_rxdone(sc, pqs[i]);
751: } else {
752: npend = pgt_queue_frags_pending(sc, pqs[i]);
753: if (npend > qdirty) {
754: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
755: DPRINTF(("%s: tx queue [%u] "
756: "underflowed by %u\n",
757: sc->sc_dev.dv_xname, pqs[i],
758: npend - qdirty));
759: sc->sc_flags |= SC_INTR_RESET;
760: break;
761: }
762: /*
763: * If the free queue was empty, or the data transmit
764: * queue just became empty, wake up any waiters.
765: */
766: if (qdirty > npend) {
767: if (pgt_queue_is_data(pqs[i])) {
768: sc->sc_ic.ic_if.if_timer = 0;
769: sc->sc_ic.ic_if.if_flags &=
770: ~IFF_OACTIVE;
771: }
772: while (qdirty-- > npend)
773: pgt_txdone(sc, pqs[i]);
774: }
775: }
776: }
777:
778: /*
779: * This is the deferred completion for received management frames
780: * and where we queue network frames for stack input.
781: */
782: dirtycount = sc->sc_dirtyq_count[PGT_QUEUE_MGMT_RX];
783: while (!TAILQ_EMPTY(&sc->sc_dirtyq[PGT_QUEUE_MGMT_RX])) {
784: struct pgt_mgmt_desc *pmd;
785:
786: pmd = TAILQ_FIRST(&sc->sc_mgmtinprog);
787: /*
788: * If there is no mgmt request in progress or the operation
789: * returned is explicitly a trap, this pmd will essentially
790: * be ignored.
791: */
792: pgt_mgmtrx_completion(sc, pmd);
793: }
794: sc->sc_cb->pcb_driver_curfrag[PGT_QUEUE_MGMT_RX] =
795: htole32(dirtycount +
796: letoh32(sc->sc_cb->pcb_driver_curfrag[PGT_QUEUE_MGMT_RX]));
797:
798: dirtycount = sc->sc_dirtyq_count[PGT_QUEUE_DATA_HIGH_RX];
799: while (!TAILQ_EMPTY(&sc->sc_dirtyq[PGT_QUEUE_DATA_HIGH_RX])) {
800: if ((m = pgt_datarx_completion(sc, PGT_QUEUE_DATA_HIGH_RX)))
801: pgt_input_frames(sc, m);
802: }
803: sc->sc_cb->pcb_driver_curfrag[PGT_QUEUE_DATA_HIGH_RX] =
804: htole32(dirtycount +
805: letoh32(sc->sc_cb->pcb_driver_curfrag[PGT_QUEUE_DATA_HIGH_RX]));
806:
807: dirtycount = sc->sc_dirtyq_count[PGT_QUEUE_DATA_LOW_RX];
808: while (!TAILQ_EMPTY(&sc->sc_dirtyq[PGT_QUEUE_DATA_LOW_RX])) {
809: if ((m = pgt_datarx_completion(sc, PGT_QUEUE_DATA_LOW_RX)))
810: pgt_input_frames(sc, m);
811: }
812: sc->sc_cb->pcb_driver_curfrag[PGT_QUEUE_DATA_LOW_RX] =
813: htole32(dirtycount +
814: letoh32(sc->sc_cb->pcb_driver_curfrag[PGT_QUEUE_DATA_LOW_RX]));
815:
816: /*
817: * Write out what we've finished with.
818: */
819: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
820: sc->sc_cbdmam->dm_mapsize,
821: BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_PREREAD);
822: }
823:
824: struct mbuf *
825: pgt_ieee80211_encap(struct pgt_softc *sc, struct ether_header *eh,
826: struct mbuf *m, struct ieee80211_node **ni)
827: {
828: struct ieee80211com *ic;
829: struct ieee80211_frame *frame;
830: struct llc *snap;
831:
832: ic = &sc->sc_ic;
833: if (ni != NULL && ic->ic_opmode == IEEE80211_M_MONITOR) {
834: *ni = ieee80211_ref_node(ic->ic_bss);
835: (*ni)->ni_inact = 0;
836: return (m);
837: }
838:
839: M_PREPEND(m, sizeof(*frame) + sizeof(*snap), M_DONTWAIT);
840: if (m != NULL)
841: m = m_pullup(m, sizeof(*frame) + sizeof(*snap));
842: if (m == NULL)
843: return (m);
844: frame = mtod(m, struct ieee80211_frame *);
845: snap = (struct llc *)&frame[1];
846: if (ni != NULL) {
847: if (ic->ic_opmode == IEEE80211_M_STA) {
848: *ni = ieee80211_ref_node(ic->ic_bss);
849: } else {
850: *ni = ieee80211_find_node(ic, eh->ether_shost);
851: /*
852: * Make up associations for ad-hoc mode. To support
853: * ad-hoc WPA, we'll need to maintain a bounded
854: * pool of ad-hoc stations.
855: */
856: if (*ni == NULL &&
857: ic->ic_opmode != IEEE80211_M_HOSTAP) {
858: *ni = ieee80211_dup_bss(ic, eh->ether_shost);
859: if (*ni != NULL) {
860: (*ni)->ni_associd = 1;
861: ic->ic_newassoc(ic, *ni, 1);
862: }
863: }
864: if (*ni == NULL) {
865: m_freem(m);
866: return (NULL);
867: }
868: }
869: (*ni)->ni_inact = 0;
870: }
871: snap->llc_dsap = snap->llc_ssap = LLC_SNAP_LSAP;
872: snap->llc_control = LLC_UI;
873: snap->llc_snap.org_code[0] = 0;
874: snap->llc_snap.org_code[1] = 0;
875: snap->llc_snap.org_code[2] = 0;
876: snap->llc_snap.ether_type = eh->ether_type;
877: frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
878: /* Doesn't look like much of the 802.11 header is available. */
879: *(uint16_t *)frame->i_dur = *(uint16_t *)frame->i_seq = 0;
880: /*
881: * Translate the addresses; WDS is not handled.
882: */
883: switch (ic->ic_opmode) {
884: case IEEE80211_M_STA:
885: frame->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
886: IEEE80211_ADDR_COPY(frame->i_addr1, eh->ether_dhost);
887: IEEE80211_ADDR_COPY(frame->i_addr2, ic->ic_bss->ni_bssid);
888: IEEE80211_ADDR_COPY(frame->i_addr3, eh->ether_shost);
889: break;
890: case IEEE80211_M_IBSS:
891: case IEEE80211_M_AHDEMO:
892: frame->i_fc[1] = IEEE80211_FC1_DIR_NODS;
893: IEEE80211_ADDR_COPY(frame->i_addr1, eh->ether_dhost);
894: IEEE80211_ADDR_COPY(frame->i_addr2, eh->ether_shost);
895: IEEE80211_ADDR_COPY(frame->i_addr3, ic->ic_bss->ni_bssid);
896: break;
897: case IEEE80211_M_HOSTAP:
898: /* HostAP forwarding defaults to being done on firmware. */
899: frame->i_fc[1] = IEEE80211_FC1_DIR_TODS;
900: IEEE80211_ADDR_COPY(frame->i_addr1, ic->ic_bss->ni_bssid);
901: IEEE80211_ADDR_COPY(frame->i_addr2, eh->ether_shost);
902: IEEE80211_ADDR_COPY(frame->i_addr3, eh->ether_dhost);
903: break;
904: default:
905: break;
906: }
907: return (m);
908: }
909:
910: void
911: pgt_input_frames(struct pgt_softc *sc, struct mbuf *m)
912: {
913: struct ether_header eh;
914: struct ifnet *ifp;
915: struct ieee80211_channel *chan;
916: struct ieee80211_node *ni;
917: struct ieee80211com *ic;
918: struct pgt_rx_annex *pra;
919: struct pgt_rx_header *pha;
920: struct mbuf *next;
921: unsigned int n;
922: uint32_t rstamp;
923: uint8_t rate, rssi;
924:
925: ic = &sc->sc_ic;
926: ifp = &ic->ic_if;
927: for (next = m; m != NULL; m = next) {
928: next = m->m_nextpkt;
929: m->m_nextpkt = NULL;
930:
931: if (ic->ic_opmode == IEEE80211_M_MONITOR) {
932: if (m->m_len < sizeof(*pha)) {
933: m = m_pullup(m, sizeof(*pha));
934: if (m == NULL) {
935: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
936: DPRINTF(("%s: m_pullup "
937: "failure\n",
938: sc->sc_dev.dv_xname));
939: ifp->if_ierrors++;
940: continue;
941: }
942: }
943: pha = mtod(m, struct pgt_rx_header *);
944: pra = NULL;
945: goto input;
946: }
947:
948: if (m->m_len < sizeof(*pra)) {
949: m = m_pullup(m, sizeof(*pra));
950: if (m == NULL) {
951: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
952: DPRINTF(("%s: m_pullup failure\n",
953: sc->sc_dev.dv_xname));
954: ifp->if_ierrors++;
955: continue;
956: }
957: }
958: pra = mtod(m, struct pgt_rx_annex *);
959: pha = &pra->pra_header;
960: if (sc->sc_debug & SC_DEBUG_RXANNEX)
961: DPRINTF(("%s: rx annex: ? %04x "
962: "len %u clock %u flags %02x ? %02x rate %u ? %02x "
963: "freq %u ? %04x rssi %u pad %02x%02x%02x\n",
964: sc->sc_dev.dv_xname,
965: letoh16(pha->pra_unknown0),
966: letoh16(pha->pra_length),
967: letoh32(pha->pra_clock), pha->pra_flags,
968: pha->pra_unknown1, pha->pra_rate,
969: pha->pra_unknown2, letoh32(pha->pra_frequency),
970: pha->pra_unknown3, pha->pra_rssi,
971: pha->pra_pad[0], pha->pra_pad[1], pha->pra_pad[2]));
972: if (sc->sc_debug & SC_DEBUG_RXETHER)
973: DPRINTF(("%s: rx ether: %s < %s 0x%04x\n",
974: sc->sc_dev.dv_xname,
975: ether_sprintf(pra->pra_ether_dhost),
976: ether_sprintf(pra->pra_ether_shost),
977: ntohs(pra->pra_ether_type)));
978:
979: memcpy(eh.ether_dhost, pra->pra_ether_dhost, ETHER_ADDR_LEN);
980: memcpy(eh.ether_shost, pra->pra_ether_shost, ETHER_ADDR_LEN);
981: eh.ether_type = pra->pra_ether_type;
982:
983: input:
984: /*
985: * This flag is set if e.g. packet could not be decrypted.
986: */
987: if (pha->pra_flags & PRA_FLAG_BAD) {
988: ifp->if_ierrors++;
989: m_freem(m);
990: continue;
991: }
992:
993: /*
994: * After getting what we want, chop off the annex, then
995: * turn into something that looks like it really was
996: * 802.11.
997: */
998: rssi = pha->pra_rssi;
999: rstamp = letoh32(pha->pra_clock);
1000: rate = pha->pra_rate;
1001: n = ieee80211_mhz2ieee(letoh32(pha->pra_frequency), 0);
1002: if (n <= IEEE80211_CHAN_MAX)
1003: chan = &ic->ic_channels[n];
1004: else
1005: chan = ic->ic_bss->ni_chan;
1006: /* Send to 802.3 listeners. */
1007: if (pra) {
1008: m_adj(m, sizeof(*pra));
1009: } else
1010: m_adj(m, sizeof(*pha));
1011:
1012: m = pgt_ieee80211_encap(sc, &eh, m, &ni);
1013: if (m != NULL) {
1014: #if NBPFILTER > 0
1015: if (sc->sc_drvbpf != NULL) {
1016: struct mbuf mb;
1017: struct pgt_rx_radiotap_hdr *tap = &sc->sc_rxtap;
1018:
1019: tap->wr_flags = 0;
1020: tap->wr_chan_freq = htole16(chan->ic_freq);
1021: tap->wr_chan_flags = htole16(chan->ic_flags);
1022: tap->wr_rssi = rssi;
1023: tap->wr_max_rssi = ic->ic_max_rssi;
1024:
1025: mb.m_data = (caddr_t)tap;
1026: mb.m_len = sc->sc_rxtap_len;
1027: mb.m_next = m;
1028: mb.m_nextpkt = NULL;
1029: mb.m_type = 0;
1030: mb.m_flags = 0;
1031: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
1032: }
1033: #endif
1034: ni->ni_rssi = rssi;
1035: ni->ni_rstamp = rstamp;
1036: ieee80211_input(ifp, m, ni, rssi, rstamp);
1037: /*
1038: * The frame may have caused the node to be marked for
1039: * reclamation (e.g. in response to a DEAUTH message)
1040: * so use free_node here instead of unref_node.
1041: */
1042: if (ni == ic->ic_bss)
1043: ieee80211_unref_node(&ni);
1044: else
1045: ieee80211_release_node(&sc->sc_ic, ni);
1046: } else {
1047: ifp->if_ierrors++;
1048: }
1049: }
1050: }
1051:
1052: void
1053: pgt_wakeup_intr(struct pgt_softc *sc)
1054: {
1055: int shouldupdate;
1056: int i;
1057:
1058: shouldupdate = 0;
1059: /* Check for any queues being empty before updating. */
1060: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
1061: sc->sc_cbdmam->dm_mapsize,
1062: BUS_DMASYNC_POSTREAD);
1063: for (i = 0; !shouldupdate && i < PGT_QUEUE_COUNT; i++) {
1064: if (pgt_queue_is_tx(i))
1065: shouldupdate = pgt_queue_frags_pending(sc, i);
1066: else
1067: shouldupdate = pgt_queue_frags_pending(sc, i) <
1068: sc->sc_freeq_count[i];
1069: }
1070: if (!TAILQ_EMPTY(&sc->sc_mgmtinprog))
1071: shouldupdate = 1;
1072: if (sc->sc_debug & SC_DEBUG_POWER)
1073: DPRINTF(("%s: wakeup interrupt (update = %d)\n",
1074: sc->sc_dev.dv_xname, shouldupdate));
1075: sc->sc_flags &= ~SC_POWERSAVE;
1076: if (shouldupdate) {
1077: pgt_write_4_flush(sc, PGT_REG_DEV_INT, PGT_DEV_INT_UPDATE);
1078: DELAY(PGT_WRITEIO_DELAY);
1079: }
1080: }
1081:
1082: void
1083: pgt_sleep_intr(struct pgt_softc *sc)
1084: {
1085: int allowed;
1086: int i;
1087:
1088: allowed = 1;
1089: /* Check for any queues not being empty before allowing. */
1090: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
1091: sc->sc_cbdmam->dm_mapsize,
1092: BUS_DMASYNC_POSTREAD);
1093: for (i = 0; allowed && i < PGT_QUEUE_COUNT; i++) {
1094: if (pgt_queue_is_tx(i))
1095: allowed = pgt_queue_frags_pending(sc, i) == 0;
1096: else
1097: allowed = pgt_queue_frags_pending(sc, i) >=
1098: sc->sc_freeq_count[i];
1099: }
1100: if (!TAILQ_EMPTY(&sc->sc_mgmtinprog))
1101: allowed = 0;
1102: if (sc->sc_debug & SC_DEBUG_POWER)
1103: DPRINTF(("%s: sleep interrupt (allowed = %d)\n",
1104: sc->sc_dev.dv_xname, allowed));
1105: if (allowed && sc->sc_ic.ic_flags & IEEE80211_F_PMGTON) {
1106: sc->sc_flags |= SC_POWERSAVE;
1107: pgt_write_4_flush(sc, PGT_REG_DEV_INT, PGT_DEV_INT_SLEEP);
1108: DELAY(PGT_WRITEIO_DELAY);
1109: }
1110: }
1111:
1112: void
1113: pgt_empty_traps(struct pgt_softc_kthread *sck)
1114: {
1115: struct pgt_async_trap *pa;
1116: struct mbuf *m;
1117:
1118: while (!TAILQ_EMPTY(&sck->sck_traps)) {
1119: pa = TAILQ_FIRST(&sck->sck_traps);
1120: TAILQ_REMOVE(&sck->sck_traps, pa, pa_link);
1121: m = pa->pa_mbuf;
1122: m_freem(m);
1123: }
1124: }
1125:
1126: void
1127: pgt_per_device_kthread(void *argp)
1128: {
1129: struct pgt_softc *sc;
1130: struct pgt_softc_kthread *sck;
1131: struct pgt_async_trap *pa;
1132: struct mbuf *m;
1133: int s;
1134:
1135: sc = argp;
1136: sck = &sc->sc_kthread;
1137: while (!sck->sck_exit) {
1138: if (!sck->sck_update && !sck->sck_reset &&
1139: TAILQ_EMPTY(&sck->sck_traps))
1140: tsleep(&sc->sc_kthread, 0, "pgtkth", 0);
1141: if (sck->sck_reset) {
1142: DPRINTF(("%s: [thread] async reset\n",
1143: sc->sc_dev.dv_xname));
1144: sck->sck_reset = 0;
1145: sck->sck_update = 0;
1146: pgt_empty_traps(sck);
1147: s = splnet();
1148: pgt_stop(sc, SC_NEEDS_RESET);
1149: splx(s);
1150: } else if (!TAILQ_EMPTY(&sck->sck_traps)) {
1151: DPRINTF(("%s: [thread] got a trap\n",
1152: sc->sc_dev.dv_xname));
1153: pa = TAILQ_FIRST(&sck->sck_traps);
1154: TAILQ_REMOVE(&sck->sck_traps, pa, pa_link);
1155: m = pa->pa_mbuf;
1156: m_adj(m, sizeof(*pa));
1157: pgt_update_sw_from_hw(sc, pa, m);
1158: m_freem(m);
1159: } else if (sck->sck_update) {
1160: sck->sck_update = 0;
1161: pgt_update_sw_from_hw(sc, NULL, NULL);
1162: }
1163: }
1164: pgt_empty_traps(sck);
1165: kthread_exit(0);
1166: }
1167:
1168: void
1169: pgt_async_reset(struct pgt_softc *sc)
1170: {
1171: if (sc->sc_flags & (SC_DYING | SC_NEEDS_RESET))
1172: return;
1173: sc->sc_kthread.sck_reset = 1;
1174: wakeup(&sc->sc_kthread);
1175: }
1176:
1177: void
1178: pgt_async_update(struct pgt_softc *sc)
1179: {
1180: if (sc->sc_flags & SC_DYING)
1181: return;
1182: sc->sc_kthread.sck_update = 1;
1183: wakeup(&sc->sc_kthread);
1184: }
1185:
1186: int
1187: pgt_intr(void *arg)
1188: {
1189: struct pgt_softc *sc;
1190: struct ifnet *ifp;
1191: u_int32_t reg;
1192:
1193: sc = arg;
1194: ifp = &sc->sc_ic.ic_if;
1195:
1196: /*
1197: * Here the Linux driver ands in the value of the INT_EN register,
1198: * and masks off everything but the documented interrupt bits. Why?
1199: *
1200: * Unknown bit 0x4000 is set upon initialization, 0x8000000 some
1201: * other times.
1202: */
1203: if (sc->sc_ic.ic_flags & IEEE80211_F_PMGTON &&
1204: sc->sc_flags & SC_POWERSAVE) {
1205: /*
1206: * Don't try handling the interrupt in sleep mode.
1207: */
1208: reg = pgt_read_4(sc, PGT_REG_CTRL_STAT);
1209: if (reg & PGT_CTRL_STAT_SLEEPMODE)
1210: return (0);
1211: }
1212: reg = pgt_read_4(sc, PGT_REG_INT_STAT);
1213: if (reg == 0)
1214: return (0); /* This interrupt is not from us */
1215:
1216: pgt_write_4_flush(sc, PGT_REG_INT_ACK, reg);
1217: if (reg & PGT_INT_STAT_INIT)
1218: pgt_init_intr(sc);
1219: if (reg & PGT_INT_STAT_UPDATE) {
1220: pgt_update_intr(sc, 0);
1221: /*
1222: * If we got an update, it's not really asleep.
1223: */
1224: sc->sc_flags &= ~SC_POWERSAVE;
1225: /*
1226: * Pretend I have any idea what the documentation
1227: * would say, and just give it a shot sending an
1228: * "update" after acknowledging the interrupt
1229: * bits and writing out the new control block.
1230: */
1231: pgt_write_4_flush(sc, PGT_REG_DEV_INT, PGT_DEV_INT_UPDATE);
1232: DELAY(PGT_WRITEIO_DELAY);
1233: }
1234: if (reg & PGT_INT_STAT_SLEEP && !(reg & PGT_INT_STAT_WAKEUP))
1235: pgt_sleep_intr(sc);
1236: if (reg & PGT_INT_STAT_WAKEUP)
1237: pgt_wakeup_intr(sc);
1238:
1239: if (sc->sc_flags & SC_INTR_RESET) {
1240: sc->sc_flags &= ~SC_INTR_RESET;
1241: pgt_async_reset(sc);
1242: }
1243:
1244: if (reg & ~PGT_INT_STAT_SOURCES && sc->sc_debug & SC_DEBUG_UNEXPECTED) {
1245: DPRINTF(("%s: unknown interrupt bits %#x (stat %#x)\n",
1246: sc->sc_dev.dv_xname,
1247: reg & ~PGT_INT_STAT_SOURCES,
1248: pgt_read_4(sc, PGT_REG_CTRL_STAT)));
1249: }
1250:
1251: if (!IFQ_IS_EMPTY(&ifp->if_snd))
1252: pgt_start(ifp);
1253:
1254: return (1);
1255: }
1256:
1257: void
1258: pgt_txdone(struct pgt_softc *sc, enum pgt_queue pq)
1259: {
1260: struct pgt_desc *pd;
1261:
1262: pd = TAILQ_FIRST(&sc->sc_dirtyq[pq]);
1263: TAILQ_REMOVE(&sc->sc_dirtyq[pq], pd, pd_link);
1264: sc->sc_dirtyq_count[pq]--;
1265: TAILQ_INSERT_TAIL(&sc->sc_freeq[pq], pd, pd_link);
1266: sc->sc_freeq_count[pq]++;
1267: bus_dmamap_sync(sc->sc_dmat, pd->pd_dmam, 0,
1268: pd->pd_dmam->dm_mapsize,
1269: BUS_DMASYNC_POSTREAD);
1270: /* Management frames want completion information. */
1271: if (sc->sc_debug & SC_DEBUG_QUEUES) {
1272: DPRINTF(("%s: queue: tx %u <- [%u]\n",
1273: sc->sc_dev.dv_xname, pd->pd_fragnum, pq));
1274: if (sc->sc_debug & SC_DEBUG_MGMT && pgt_queue_is_mgmt(pq)) {
1275: struct pgt_mgmt_frame *pmf;
1276:
1277: pmf = (struct pgt_mgmt_frame *)pd->pd_mem;
1278: DPRINTF(("%s: queue: txmgmt %p <- "
1279: "(ver %u, op %u, flags %#x)\n",
1280: sc->sc_dev.dv_xname,
1281: pd, pmf->pmf_version, pmf->pmf_operation,
1282: pmf->pmf_flags));
1283: }
1284: }
1285: pgt_unload_tx_desc_frag(sc, pd);
1286: }
1287:
1288: void
1289: pgt_rxdone(struct pgt_softc *sc, enum pgt_queue pq)
1290: {
1291: struct pgt_desc *pd;
1292:
1293: pd = TAILQ_FIRST(&sc->sc_freeq[pq]);
1294: TAILQ_REMOVE(&sc->sc_freeq[pq], pd, pd_link);
1295: sc->sc_freeq_count[pq]--;
1296: TAILQ_INSERT_TAIL(&sc->sc_dirtyq[pq], pd, pd_link);
1297: sc->sc_dirtyq_count[pq]++;
1298: bus_dmamap_sync(sc->sc_dmat, pd->pd_dmam, 0,
1299: pd->pd_dmam->dm_mapsize,
1300: BUS_DMASYNC_POSTREAD);
1301: if (sc->sc_debug & SC_DEBUG_QUEUES)
1302: DPRINTF(("%s: queue: rx %u <- [%u]\n",
1303: sc->sc_dev.dv_xname, pd->pd_fragnum, pq));
1304: if (sc->sc_debug & SC_DEBUG_UNEXPECTED &&
1305: pd->pd_fragp->pf_flags & ~htole16(PF_FLAG_MF))
1306: DPRINTF(("%s: unknown flags on rx [%u]: %#x\n",
1307: sc->sc_dev.dv_xname, pq, letoh16(pd->pd_fragp->pf_flags)));
1308: }
1309:
1310: /*
1311: * Traps are generally used for the firmware to report changes in state
1312: * back to the host. Mostly this processes changes in link state, but
1313: * it needs to also be used to initiate WPA and other authentication
1314: * schemes in terms of client (station) or server (access point).
1315: */
1316: void
1317: pgt_trap_received(struct pgt_softc *sc, uint32_t oid, void *trapdata,
1318: size_t size)
1319: {
1320: struct pgt_async_trap *pa;
1321: struct mbuf *m;
1322: char *p;
1323: size_t total;
1324:
1325: if (sc->sc_flags & SC_DYING)
1326: return;
1327:
1328: total = sizeof(oid) + size + sizeof(struct pgt_async_trap);
1329: if (total >= MINCLSIZE) {
1330: MGETHDR(m, M_DONTWAIT, MT_DATA);
1331: if (m == NULL)
1332: return;
1333: MCLGET(m, M_DONTWAIT);
1334: if (!(m->m_flags & M_EXT)) {
1335: m_freem(m);
1336: m = NULL;
1337: }
1338: } else
1339: m = m_get(M_DONTWAIT, MT_DATA);
1340:
1341: if (m == NULL)
1342: return;
1343: else
1344: m->m_len = total;
1345:
1346: pa = mtod(m, struct pgt_async_trap *);
1347: p = mtod(m, char *) + sizeof(*pa);
1348: *(uint32_t *)p = oid;
1349: p += sizeof(uint32_t);
1350: memcpy(p, trapdata, size);
1351: pa->pa_mbuf = m;
1352:
1353: TAILQ_INSERT_TAIL(&sc->sc_kthread.sck_traps, pa, pa_link);
1354: wakeup(&sc->sc_kthread);
1355: }
1356:
1357: /*
1358: * Process a completed management response (all requests should be
1359: * responded to, quickly) or an event (trap).
1360: */
1361: void
1362: pgt_mgmtrx_completion(struct pgt_softc *sc, struct pgt_mgmt_desc *pmd)
1363: {
1364: struct pgt_desc *pd;
1365: struct pgt_mgmt_frame *pmf;
1366: uint32_t oid, size;
1367:
1368: pd = TAILQ_FIRST(&sc->sc_dirtyq[PGT_QUEUE_MGMT_RX]);
1369: TAILQ_REMOVE(&sc->sc_dirtyq[PGT_QUEUE_MGMT_RX], pd, pd_link);
1370: sc->sc_dirtyq_count[PGT_QUEUE_MGMT_RX]--;
1371: TAILQ_INSERT_TAIL(&sc->sc_freeq[PGT_QUEUE_MGMT_RX],
1372: pd, pd_link);
1373: sc->sc_freeq_count[PGT_QUEUE_MGMT_RX]++;
1374: if (letoh16(pd->pd_fragp->pf_size) < sizeof(*pmf)) {
1375: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1376: DPRINTF(("%s: mgmt desc too small: %u\n",
1377: sc->sc_dev.dv_xname,
1378: letoh16(pd->pd_fragp->pf_size)));
1379: goto out_nopmd;
1380: }
1381: pmf = (struct pgt_mgmt_frame *)pd->pd_mem;
1382: if (pmf->pmf_version != PMF_VER) {
1383: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1384: DPRINTF(("%s: unknown mgmt version %u\n",
1385: sc->sc_dev.dv_xname, pmf->pmf_version));
1386: goto out_nopmd;
1387: }
1388: if (pmf->pmf_device != PMF_DEV) {
1389: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1390: DPRINTF(("%s: unknown mgmt dev %u\n",
1391: sc->sc_dev.dv_xname, pmf->pmf_device));
1392: goto out;
1393: }
1394: if (pmf->pmf_flags & ~PMF_FLAG_VALID) {
1395: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1396: DPRINTF(("%s: unknown mgmt flags %x\n",
1397: sc->sc_dev.dv_xname,
1398: pmf->pmf_flags & ~PMF_FLAG_VALID));
1399: goto out;
1400: }
1401: if (pmf->pmf_flags & PMF_FLAG_LE) {
1402: oid = letoh32(pmf->pmf_oid);
1403: size = letoh32(pmf->pmf_size);
1404: } else {
1405: oid = betoh32(pmf->pmf_oid);
1406: size = betoh32(pmf->pmf_size);
1407: }
1408: if (pmf->pmf_operation == PMF_OP_TRAP) {
1409: pmd = NULL; /* ignored */
1410: DPRINTF(("%s: mgmt trap received (op %u, oid %#x, len %u)\n",
1411: sc->sc_dev.dv_xname,
1412: pmf->pmf_operation, oid, size));
1413: pgt_trap_received(sc, oid, (char *)pmf + sizeof(*pmf),
1414: min(size, PGT_FRAG_SIZE - sizeof(*pmf)));
1415: goto out_nopmd;
1416: }
1417: if (pmd == NULL) {
1418: if (sc->sc_debug & (SC_DEBUG_UNEXPECTED | SC_DEBUG_MGMT))
1419: DPRINTF(("%s: spurious mgmt received "
1420: "(op %u, oid %#x, len %u)\n", sc->sc_dev.dv_xname,
1421: pmf->pmf_operation, oid, size));
1422: goto out_nopmd;
1423: }
1424: switch (pmf->pmf_operation) {
1425: case PMF_OP_RESPONSE:
1426: pmd->pmd_error = 0;
1427: break;
1428: case PMF_OP_ERROR:
1429: pmd->pmd_error = EPERM;
1430: goto out;
1431: default:
1432: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1433: DPRINTF(("%s: unknown mgmt op %u\n",
1434: sc->sc_dev.dv_xname, pmf->pmf_operation));
1435: pmd->pmd_error = EIO;
1436: goto out;
1437: }
1438: if (oid != pmd->pmd_oid) {
1439: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1440: DPRINTF(("%s: mgmt oid changed from %#x -> %#x\n",
1441: sc->sc_dev.dv_xname, pmd->pmd_oid, oid));
1442: pmd->pmd_oid = oid;
1443: }
1444: if (pmd->pmd_recvbuf != NULL) {
1445: if (size > PGT_FRAG_SIZE) {
1446: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1447: DPRINTF(("%s: mgmt oid %#x has bad size %u\n",
1448: sc->sc_dev.dv_xname, oid, size));
1449: pmd->pmd_error = EIO;
1450: goto out;
1451: }
1452: if (size > pmd->pmd_len)
1453: pmd->pmd_error = ENOMEM;
1454: else
1455: memcpy(pmd->pmd_recvbuf, (char *)pmf + sizeof(*pmf),
1456: size);
1457: pmd->pmd_len = size;
1458: }
1459:
1460: out:
1461: TAILQ_REMOVE(&sc->sc_mgmtinprog, pmd, pmd_link);
1462: wakeup_one(pmd);
1463: if (sc->sc_debug & SC_DEBUG_MGMT)
1464: DPRINTF(("%s: queue: mgmt %p <- (op %u, oid %#x, len %u)\n",
1465: sc->sc_dev.dv_xname, pmd, pmf->pmf_operation,
1466: pmd->pmd_oid, pmd->pmd_len));
1467: out_nopmd:
1468: pgt_reinit_rx_desc_frag(sc, pd);
1469: }
1470:
1471: /*
1472: * Queue packets for reception and defragmentation. I don't know now
1473: * whether the rx queue being full enough to start, but not finish,
1474: * queueing a fragmented packet, can happen.
1475: */
1476: struct mbuf *
1477: pgt_datarx_completion(struct pgt_softc *sc, enum pgt_queue pq)
1478: {
1479: struct ifnet *ifp;
1480: struct pgt_desc *pd;
1481: struct mbuf *top, **mp, *m;
1482: size_t datalen;
1483: uint16_t morefrags, dataoff;
1484: int tlen = 0;
1485:
1486: ifp = &sc->sc_ic.ic_if;
1487: m = NULL;
1488: top = NULL;
1489: mp = ⊤
1490:
1491: while ((pd = TAILQ_FIRST(&sc->sc_dirtyq[pq])) != NULL) {
1492: TAILQ_REMOVE(&sc->sc_dirtyq[pq], pd, pd_link);
1493: sc->sc_dirtyq_count[pq]--;
1494: datalen = letoh16(pd->pd_fragp->pf_size);
1495: dataoff = letoh32(pd->pd_fragp->pf_addr) - pd->pd_dmaaddr;
1496: morefrags = pd->pd_fragp->pf_flags & htole16(PF_FLAG_MF);
1497:
1498: if (sc->sc_debug & SC_DEBUG_RXFRAG)
1499: DPRINTF(("%s: rx frag: len %u memoff %u flags %x\n",
1500: sc->sc_dev.dv_xname, datalen, dataoff,
1501: pd->pd_fragp->pf_flags));
1502:
1503: /* Add the (two+?) bytes for the header. */
1504: if (datalen + dataoff > PGT_FRAG_SIZE) {
1505: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1506: DPRINTF(("%s data rx too big: %u\n",
1507: sc->sc_dev.dv_xname, datalen));
1508: goto fail;
1509: }
1510:
1511: if (m == NULL)
1512: MGETHDR(m, M_DONTWAIT, MT_DATA);
1513: else
1514: m = m_get(M_DONTWAIT, MT_DATA);
1515:
1516: if (m == NULL)
1517: goto fail;
1518: if (datalen >= MINCLSIZE) {
1519: MCLGET(m, M_DONTWAIT);
1520: if (!(m->m_flags & M_EXT)) {
1521: m_free(m);
1522: goto fail;
1523: }
1524: }
1525: bcopy(pd->pd_mem + dataoff, mtod(m, char *), datalen);
1526: m->m_len = datalen;
1527: tlen += datalen;
1528:
1529: *mp = m;
1530: mp = &m->m_next;
1531:
1532: TAILQ_INSERT_TAIL(&sc->sc_freeq[pq], pd, pd_link);
1533: sc->sc_freeq_count[pq]++;
1534: pgt_reinit_rx_desc_frag(sc, pd);
1535:
1536: if (!morefrags)
1537: break;
1538: }
1539:
1540: if (top) {
1541: ifp->if_ipackets++;
1542: top->m_pkthdr.len = tlen;
1543: top->m_pkthdr.rcvif = ifp;
1544: }
1545: return (top);
1546:
1547: fail:
1548: TAILQ_INSERT_TAIL(&sc->sc_freeq[pq], pd, pd_link);
1549: sc->sc_freeq_count[pq]++;
1550: pgt_reinit_rx_desc_frag(sc, pd);
1551:
1552: ifp->if_ierrors++;
1553: if (top)
1554: m_freem(top);
1555: return (NULL);
1556: }
1557:
1558: int
1559: pgt_oid_get(struct pgt_softc *sc, enum pgt_oid oid,
1560: void *arg, size_t arglen)
1561: {
1562: struct pgt_mgmt_desc pmd;
1563: int error;
1564:
1565: bzero(&pmd, sizeof(pmd));
1566: pmd.pmd_recvbuf = arg;
1567: pmd.pmd_len = arglen;
1568: pmd.pmd_oid = oid;
1569:
1570: error = pgt_mgmt_request(sc, &pmd);
1571: if (error == 0)
1572: error = pmd.pmd_error;
1573: if (error != 0 && error != EPERM && sc->sc_debug & SC_DEBUG_UNEXPECTED)
1574: DPRINTF(("%s: failure getting oid %#x: %d\n",
1575: sc->sc_dev.dv_xname, oid, error));
1576:
1577: return (error);
1578: }
1579:
1580: int
1581: pgt_oid_retrieve(struct pgt_softc *sc, enum pgt_oid oid,
1582: void *arg, size_t arglen)
1583: {
1584: struct pgt_mgmt_desc pmd;
1585: int error;
1586:
1587: bzero(&pmd, sizeof(pmd));
1588: pmd.pmd_sendbuf = arg;
1589: pmd.pmd_recvbuf = arg;
1590: pmd.pmd_len = arglen;
1591: pmd.pmd_oid = oid;
1592:
1593: error = pgt_mgmt_request(sc, &pmd);
1594: if (error == 0)
1595: error = pmd.pmd_error;
1596: if (error != 0 && error != EPERM && sc->sc_debug & SC_DEBUG_UNEXPECTED)
1597: DPRINTF(("%s: failure retrieving oid %#x: %d\n",
1598: sc->sc_dev.dv_xname, oid, error));
1599:
1600: return (error);
1601: }
1602:
1603: int
1604: pgt_oid_set(struct pgt_softc *sc, enum pgt_oid oid,
1605: const void *arg, size_t arglen)
1606: {
1607: struct pgt_mgmt_desc pmd;
1608: int error;
1609:
1610: bzero(&pmd, sizeof(pmd));
1611: pmd.pmd_sendbuf = arg;
1612: pmd.pmd_len = arglen;
1613: pmd.pmd_oid = oid;
1614:
1615: error = pgt_mgmt_request(sc, &pmd);
1616: if (error == 0)
1617: error = pmd.pmd_error;
1618: if (error != 0 && error != EPERM && sc->sc_debug & SC_DEBUG_UNEXPECTED)
1619: DPRINTF(("%s: failure setting oid %#x: %d\n",
1620: sc->sc_dev.dv_xname, oid, error));
1621:
1622: return (error);
1623: }
1624:
1625: void
1626: pgt_state_dump(struct pgt_softc *sc)
1627: {
1628: printf("%s: state dump: control 0x%08x interrupt 0x%08x\n",
1629: sc->sc_dev.dv_xname,
1630: pgt_read_4(sc, PGT_REG_CTRL_STAT),
1631: pgt_read_4(sc, PGT_REG_INT_STAT));
1632:
1633: printf("%s: state dump: driver curfrag[]\n",
1634: sc->sc_dev.dv_xname);
1635:
1636: printf("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
1637: sc->sc_dev.dv_xname,
1638: letoh32(sc->sc_cb->pcb_driver_curfrag[0]),
1639: letoh32(sc->sc_cb->pcb_driver_curfrag[1]),
1640: letoh32(sc->sc_cb->pcb_driver_curfrag[2]),
1641: letoh32(sc->sc_cb->pcb_driver_curfrag[3]),
1642: letoh32(sc->sc_cb->pcb_driver_curfrag[4]),
1643: letoh32(sc->sc_cb->pcb_driver_curfrag[5]));
1644:
1645: printf("%s: state dump: device curfrag[]\n",
1646: sc->sc_dev.dv_xname);
1647:
1648: printf("%s: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
1649: sc->sc_dev.dv_xname,
1650: letoh32(sc->sc_cb->pcb_device_curfrag[0]),
1651: letoh32(sc->sc_cb->pcb_device_curfrag[1]),
1652: letoh32(sc->sc_cb->pcb_device_curfrag[2]),
1653: letoh32(sc->sc_cb->pcb_device_curfrag[3]),
1654: letoh32(sc->sc_cb->pcb_device_curfrag[4]),
1655: letoh32(sc->sc_cb->pcb_device_curfrag[5]));
1656: }
1657:
1658: int
1659: pgt_mgmt_request(struct pgt_softc *sc, struct pgt_mgmt_desc *pmd)
1660: {
1661: struct pgt_desc *pd;
1662: struct pgt_mgmt_frame *pmf;
1663: int error, i;
1664:
1665: if (sc->sc_flags & (SC_DYING | SC_NEEDS_RESET))
1666: return (EIO);
1667: if (pmd->pmd_len > PGT_FRAG_SIZE - sizeof(*pmf))
1668: return (ENOMEM);
1669: pd = TAILQ_FIRST(&sc->sc_freeq[PGT_QUEUE_MGMT_TX]);
1670: if (pd == NULL)
1671: return (ENOMEM);
1672: error = pgt_load_tx_desc_frag(sc, PGT_QUEUE_MGMT_TX, pd);
1673: if (error)
1674: return (error);
1675: pmf = (struct pgt_mgmt_frame *)pd->pd_mem;
1676: pmf->pmf_version = PMF_VER;
1677: /* "get" and "retrieve" operations look the same */
1678: if (pmd->pmd_recvbuf != NULL)
1679: pmf->pmf_operation = PMF_OP_GET;
1680: else
1681: pmf->pmf_operation = PMF_OP_SET;
1682: pmf->pmf_oid = htobe32(pmd->pmd_oid);
1683: pmf->pmf_device = PMF_DEV;
1684: pmf->pmf_flags = 0;
1685: pmf->pmf_size = htobe32(pmd->pmd_len);
1686: /* "set" and "retrieve" operations both send data */
1687: if (pmd->pmd_sendbuf != NULL)
1688: memcpy((char *)pmf + sizeof(*pmf), pmd->pmd_sendbuf,
1689: pmd->pmd_len);
1690: else
1691: bzero((char *)pmf + sizeof(*pmf), pmd->pmd_len);
1692: pmd->pmd_error = EINPROGRESS;
1693: TAILQ_INSERT_TAIL(&sc->sc_mgmtinprog, pmd, pmd_link);
1694: if (sc->sc_debug & SC_DEBUG_MGMT)
1695: DPRINTF(("%s: queue: mgmt %p -> (op %u, oid %#x, len %u)\n",
1696: sc->sc_dev.dv_xname,
1697: pmd, pmf->pmf_operation,
1698: pmd->pmd_oid, pmd->pmd_len));
1699: pgt_desc_transmit(sc, PGT_QUEUE_MGMT_TX, pd,
1700: sizeof(*pmf) + pmd->pmd_len, 0);
1701: /*
1702: * Try for one second, triggering 10 times.
1703: *
1704: * Do our best to work around seemingly buggy CardBus controllers
1705: * on Soekris 4521 that fail to get interrupts with alarming
1706: * regularity: run as if an interrupt occurred and service every
1707: * queue except for mbuf reception.
1708: */
1709: i = 0;
1710: do {
1711: if (tsleep(pmd, 0, "pgtmgm", hz / 10) != EWOULDBLOCK)
1712: break;
1713: if (pmd->pmd_error != EINPROGRESS)
1714: break;
1715: if (sc->sc_flags & (SC_DYING | SC_NEEDS_RESET)) {
1716: pmd->pmd_error = EIO;
1717: TAILQ_REMOVE(&sc->sc_mgmtinprog, pmd, pmd_link);
1718: break;
1719: }
1720: if (i != 9)
1721: pgt_maybe_trigger(sc, PGT_QUEUE_MGMT_RX);
1722: #ifdef PGT_BUGGY_INTERRUPT_RECOVERY
1723: pgt_update_intr(sc, 0);
1724: #endif
1725: } while (i++ < 10);
1726:
1727: if (pmd->pmd_error == EINPROGRESS) {
1728: printf("%s: timeout waiting for management "
1729: "packet response to %#x\n",
1730: sc->sc_dev.dv_xname, pmd->pmd_oid);
1731: TAILQ_REMOVE(&sc->sc_mgmtinprog, pmd, pmd_link);
1732: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1733: pgt_state_dump(sc);
1734: pgt_async_reset(sc);
1735: error = ETIMEDOUT;
1736: } else
1737: error = 0;
1738:
1739: return (error);
1740: }
1741:
1742: void
1743: pgt_desc_transmit(struct pgt_softc *sc, enum pgt_queue pq, struct pgt_desc *pd,
1744: uint16_t len, int morecoming)
1745: {
1746: TAILQ_REMOVE(&sc->sc_freeq[pq], pd, pd_link);
1747: sc->sc_freeq_count[pq]--;
1748: TAILQ_INSERT_TAIL(&sc->sc_dirtyq[pq], pd, pd_link);
1749: sc->sc_dirtyq_count[pq]++;
1750: if (sc->sc_debug & SC_DEBUG_QUEUES)
1751: DPRINTF(("%s: queue: tx %u -> [%u]\n", sc->sc_dev.dv_xname,
1752: pd->pd_fragnum, pq));
1753: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
1754: sc->sc_cbdmam->dm_mapsize,
1755: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE);
1756: if (morecoming)
1757: pd->pd_fragp->pf_flags |= htole16(PF_FLAG_MF);
1758: pd->pd_fragp->pf_size = htole16(len);
1759: bus_dmamap_sync(sc->sc_dmat, pd->pd_dmam, 0,
1760: pd->pd_dmam->dm_mapsize,
1761: BUS_DMASYNC_POSTWRITE);
1762: sc->sc_cb->pcb_driver_curfrag[pq] =
1763: htole32(letoh32(sc->sc_cb->pcb_driver_curfrag[pq]) + 1);
1764: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
1765: sc->sc_cbdmam->dm_mapsize,
1766: BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_PREREAD);
1767: if (!morecoming)
1768: pgt_maybe_trigger(sc, pq);
1769: }
1770:
1771: void
1772: pgt_maybe_trigger(struct pgt_softc *sc, enum pgt_queue pq)
1773: {
1774: unsigned int tries = 1000000 / PGT_WRITEIO_DELAY; /* one second */
1775: uint32_t reg;
1776:
1777: if (sc->sc_debug & SC_DEBUG_TRIGGER)
1778: DPRINTF(("%s: triggered by queue [%u]\n",
1779: sc->sc_dev.dv_xname, pq));
1780: pgt_debug_events(sc, "trig");
1781: if (sc->sc_flags & SC_POWERSAVE) {
1782: /* Magic values ahoy? */
1783: if (pgt_read_4(sc, PGT_REG_INT_STAT) == 0xabadface) {
1784: do {
1785: reg = pgt_read_4(sc, PGT_REG_CTRL_STAT);
1786: if (!(reg & PGT_CTRL_STAT_SLEEPMODE))
1787: DELAY(PGT_WRITEIO_DELAY);
1788: } while (tries-- != 0);
1789: if (!(reg & PGT_CTRL_STAT_SLEEPMODE)) {
1790: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
1791: DPRINTF(("%s: timeout triggering from "
1792: "sleep mode\n",
1793: sc->sc_dev.dv_xname));
1794: pgt_async_reset(sc);
1795: return;
1796: }
1797: }
1798: pgt_write_4_flush(sc, PGT_REG_DEV_INT,
1799: PGT_DEV_INT_WAKEUP);
1800: DELAY(PGT_WRITEIO_DELAY);
1801: /* read the status back in */
1802: (void)pgt_read_4(sc, PGT_REG_CTRL_STAT);
1803: DELAY(PGT_WRITEIO_DELAY);
1804: } else {
1805: pgt_write_4_flush(sc, PGT_REG_DEV_INT, PGT_DEV_INT_UPDATE);
1806: DELAY(PGT_WRITEIO_DELAY);
1807: }
1808: }
1809:
1810: struct ieee80211_node *
1811: pgt_ieee80211_node_alloc(struct ieee80211com *ic)
1812: {
1813: struct pgt_ieee80211_node *pin;
1814:
1815: pin = malloc(sizeof(*pin), M_DEVBUF, M_NOWAIT);
1816: if (pin != NULL) {
1817: bzero(pin, sizeof *pin);
1818: pin->pin_dot1x_auth = PIN_DOT1X_UNAUTHORIZED;
1819: }
1820: return (struct ieee80211_node *)pin;
1821: }
1822:
1823: void
1824: pgt_ieee80211_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni,
1825: int reallynew)
1826: {
1827: ieee80211_ref_node(ni);
1828: }
1829:
1830: void
1831: pgt_ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
1832: {
1833: struct pgt_ieee80211_node *pin;
1834:
1835: pin = (struct pgt_ieee80211_node *)ni;
1836: free(pin, M_DEVBUF);
1837: }
1838:
1839: void
1840: pgt_ieee80211_node_copy(struct ieee80211com *ic, struct ieee80211_node *dst,
1841: const struct ieee80211_node *src)
1842: {
1843: const struct pgt_ieee80211_node *psrc;
1844: struct pgt_ieee80211_node *pdst;
1845:
1846: psrc = (const struct pgt_ieee80211_node *)src;
1847: pdst = (struct pgt_ieee80211_node *)dst;
1848: bcopy(psrc, pdst, sizeof(*psrc));
1849: }
1850:
1851: int
1852: pgt_ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
1853: int type, int arg)
1854: {
1855: return (EOPNOTSUPP);
1856: }
1857:
1858: int
1859: pgt_net_attach(struct pgt_softc *sc)
1860: {
1861: struct ieee80211com *ic = &sc->sc_ic;
1862: struct ifnet *ifp = &ic->ic_if;
1863: struct ieee80211_rateset *rs;
1864: uint8_t rates[IEEE80211_RATE_MAXSIZE];
1865: struct pgt_obj_buffer psbuffer;
1866: struct pgt_obj_frequencies *freqs;
1867: uint32_t phymode, country;
1868: unsigned int chan, i, j, firstchan = -1;
1869: int error;
1870:
1871: psbuffer.pob_size = htole32(PGT_FRAG_SIZE * PGT_PSM_BUFFER_FRAME_COUNT);
1872: psbuffer.pob_addr = htole32(sc->sc_psmdmam->dm_segs[0].ds_addr);
1873: error = pgt_oid_set(sc, PGT_OID_PSM_BUFFER, &psbuffer, sizeof(country));
1874: if (error)
1875: return (error);
1876: error = pgt_oid_get(sc, PGT_OID_PHY, &phymode, sizeof(phymode));
1877: if (error)
1878: return (error);
1879: error = pgt_oid_get(sc, PGT_OID_MAC_ADDRESS, ic->ic_myaddr,
1880: sizeof(ic->ic_myaddr));
1881: if (error)
1882: return (error);
1883: error = pgt_oid_get(sc, PGT_OID_COUNTRY, &country, sizeof(country));
1884: if (error)
1885: return (error);
1886:
1887: ifp->if_softc = sc;
1888: ifp->if_init = pgt_init;
1889: ifp->if_ioctl = pgt_ioctl;
1890: ifp->if_start = pgt_start;
1891: ifp->if_watchdog = pgt_watchdog;
1892: ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
1893: strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
1894:
1895: IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
1896: IFQ_SET_READY(&ifp->if_snd);
1897:
1898: /*
1899: * Set channels
1900: *
1901: * Prism hardware likes to report supported frequencies that are
1902: * not actually available for the country of origin.
1903: */
1904: j = sizeof(*freqs) + (IEEE80211_CHAN_MAX + 1) * sizeof(uint16_t);
1905: freqs = malloc(j, M_DEVBUF, M_WAITOK);
1906: error = pgt_oid_get(sc, PGT_OID_SUPPORTED_FREQUENCIES, freqs, j);
1907: if (error) {
1908: free(freqs, M_DEVBUF);
1909: return (error);
1910: }
1911:
1912: for (i = 0, j = letoh16(freqs->pof_count); i < j; i++) {
1913: chan = ieee80211_mhz2ieee(letoh16(freqs->pof_freqlist_mhz[i]),
1914: 0);
1915:
1916: if (chan > IEEE80211_CHAN_MAX) {
1917: printf("%s: reported bogus channel (%uMHz)\n",
1918: sc->sc_dev.dv_xname, chan);
1919: free(freqs, M_DEVBUF);
1920: return (EIO);
1921: }
1922:
1923: if (letoh16(freqs->pof_freqlist_mhz[i]) < 5000) {
1924: if (!(phymode & htole32(PGT_OID_PHY_2400MHZ)))
1925: continue;
1926: if (country == letoh32(PGT_COUNTRY_USA)) {
1927: if (chan >= 12 && chan <= 14)
1928: continue;
1929: }
1930: if (chan <= 14)
1931: ic->ic_channels[chan].ic_flags |=
1932: IEEE80211_CHAN_B;
1933: ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_PUREG;
1934: } else {
1935: if (!(phymode & htole32(PGT_OID_PHY_5000MHZ)))
1936: continue;
1937: ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_A;
1938: }
1939:
1940: ic->ic_channels[chan].ic_freq =
1941: letoh16(freqs->pof_freqlist_mhz[i]);
1942:
1943: if (firstchan == -1)
1944: firstchan = chan;
1945:
1946: DPRINTF(("%s: set channel %d to freq %uMHz\n",
1947: sc->sc_dev.dv_xname, chan,
1948: letoh16(freqs->pof_freqlist_mhz[i])));
1949: }
1950: free(freqs, M_DEVBUF);
1951: if (firstchan == -1) {
1952: printf("%s: no channels found\n", sc->sc_dev.dv_xname);
1953: return (EIO);
1954: }
1955:
1956: /*
1957: * Set rates
1958: */
1959: bzero(rates, sizeof(rates));
1960: error = pgt_oid_get(sc, PGT_OID_SUPPORTED_RATES, rates, sizeof(rates));
1961: if (error)
1962: return (error);
1963: for (i = 0; i < sizeof(rates) && rates[i] != 0; i++) {
1964: switch (rates[i]) {
1965: case 2:
1966: case 4:
1967: case 11:
1968: case 22:
1969: case 44: /* maybe */
1970: if (phymode & htole32(PGT_OID_PHY_2400MHZ)) {
1971: rs = &ic->ic_sup_rates[IEEE80211_MODE_11B];
1972: rs->rs_rates[rs->rs_nrates++] = rates[i];
1973: }
1974: default:
1975: if (phymode & htole32(PGT_OID_PHY_2400MHZ)) {
1976: rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
1977: rs->rs_rates[rs->rs_nrates++] = rates[i];
1978: }
1979: if (phymode & htole32(PGT_OID_PHY_5000MHZ)) {
1980: rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
1981: rs->rs_rates[rs->rs_nrates++] = rates[i];
1982: }
1983: rs = &ic->ic_sup_rates[IEEE80211_MODE_AUTO];
1984: rs->rs_rates[rs->rs_nrates++] = rates[i];
1985: }
1986: }
1987:
1988: ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_IBSS | IEEE80211_C_PMGT |
1989: IEEE80211_C_HOSTAP | IEEE80211_C_TXPMGT | IEEE80211_C_SHSLOT |
1990: IEEE80211_C_SHPREAMBLE | IEEE80211_C_MONITOR;
1991:
1992: ic->ic_opmode = IEEE80211_M_STA;
1993: ic->ic_state = IEEE80211_S_INIT;
1994:
1995: if_attach(ifp);
1996: ieee80211_ifattach(ifp);
1997:
1998: /* setup post-attach/pre-lateattach vector functions */
1999: sc->sc_newstate = ic->ic_newstate;
2000: ic->ic_newstate = pgt_newstate;
2001: ic->ic_node_alloc = pgt_ieee80211_node_alloc;
2002: ic->ic_newassoc = pgt_ieee80211_newassoc;
2003: ic->ic_node_free = pgt_ieee80211_node_free;
2004: ic->ic_node_copy = pgt_ieee80211_node_copy;
2005: ic->ic_send_mgmt = pgt_ieee80211_send_mgmt;
2006: ic->ic_max_rssi = 255; /* rssi is a u_int8_t */
2007:
2008: /* let net80211 handle switching around the media + resetting */
2009: ieee80211_media_init(ifp, pgt_media_change, pgt_media_status);
2010:
2011: #if NBPFILTER > 0
2012: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
2013: sizeof(struct ieee80211_frame) + 64);
2014:
2015: sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
2016: sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
2017: sc->sc_rxtap.wr_ihdr.it_present = htole32(PGT_RX_RADIOTAP_PRESENT);
2018:
2019: sc->sc_txtap_len = sizeof(sc->sc_txtapu);
2020: sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
2021: sc->sc_txtap.wt_ihdr.it_present = htole32(PGT_TX_RADIOTAP_PRESENT);
2022: #endif
2023:
2024: /*
2025: * Enable shutdown and power hooks
2026: */
2027: sc->sc_shutdown_hook = shutdownhook_establish(pgt_shutdown, sc);
2028: if (sc->sc_shutdown_hook == NULL)
2029: printf("%s: WARNING: unable to establish shutdown hook\n",
2030: sc->sc_dev.dv_xname);
2031: sc->sc_power_hook = powerhook_establish(pgt_power, sc);
2032: if (sc->sc_power_hook == NULL)
2033: printf("%s: WARNING: unable to establish power hook\n",
2034: sc->sc_dev.dv_xname);
2035:
2036: return (0);
2037: }
2038:
2039: int
2040: pgt_media_change(struct ifnet *ifp)
2041: {
2042: struct pgt_softc *sc = ifp->if_softc;
2043: int error;
2044:
2045: error = ieee80211_media_change(ifp);
2046: if (error == ENETRESET) {
2047: pgt_update_hw_from_sw(sc, 0, 0);
2048: error = 0;
2049: }
2050:
2051: return (error);
2052: }
2053:
2054: void
2055: pgt_media_status(struct ifnet *ifp, struct ifmediareq *imr)
2056: {
2057: struct pgt_softc *sc = ifp->if_softc;
2058: struct ieee80211com *ic = &sc->sc_ic;
2059: uint32_t rate;
2060: int s;
2061:
2062: imr->ifm_status = 0;
2063: imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
2064:
2065: if (!(ifp->if_flags & IFF_UP))
2066: return;
2067:
2068: s = splnet();
2069:
2070: if (ic->ic_fixed_rate != -1) {
2071: rate = ic->ic_sup_rates[ic->ic_curmode].
2072: rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
2073: } else {
2074: if (pgt_oid_get(sc, PGT_OID_LINK_STATE, &rate, sizeof(rate)))
2075: return;
2076: rate = letoh32(rate);
2077: if (sc->sc_debug & SC_DEBUG_LINK) {
2078: DPRINTF(("%s: %s: link rate %u\n",
2079: sc->sc_dev.dv_xname, __func__, rate));
2080: }
2081: if (rate == 0)
2082: return;
2083: }
2084:
2085: imr->ifm_status = IFM_AVALID;
2086: imr->ifm_active = IFM_IEEE80211;
2087: if (ic->ic_state == IEEE80211_S_RUN)
2088: imr->ifm_status |= IFM_ACTIVE;
2089:
2090: imr->ifm_active |= ieee80211_rate2media(ic, rate, ic->ic_curmode);
2091:
2092: switch (ic->ic_opmode) {
2093: case IEEE80211_M_STA:
2094: break;
2095: case IEEE80211_M_IBSS:
2096: imr->ifm_active |= IFM_IEEE80211_ADHOC;
2097: break;
2098: case IEEE80211_M_AHDEMO:
2099: imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
2100: break;
2101: case IEEE80211_M_HOSTAP:
2102: imr->ifm_active |= IFM_IEEE80211_HOSTAP;
2103: break;
2104: case IEEE80211_M_MONITOR:
2105: imr->ifm_active |= IFM_IEEE80211_MONITOR;
2106: break;
2107: default:
2108: break;
2109: }
2110:
2111: splx(s);
2112: }
2113:
2114: /*
2115: * Start data frames. Critical sections surround the boundary of
2116: * management frame transmission / transmission acknowledgement / response
2117: * and data frame transmission / transmission acknowledgement.
2118: */
2119: void
2120: pgt_start(struct ifnet *ifp)
2121: {
2122: struct pgt_softc *sc;
2123: struct ieee80211com *ic;
2124: struct pgt_desc *pd;
2125: struct mbuf *m;
2126: int error;
2127:
2128: sc = ifp->if_softc;
2129: ic = &sc->sc_ic;
2130:
2131: if (sc->sc_flags & (SC_DYING | SC_NEEDS_RESET) ||
2132: !(ifp->if_flags & IFF_RUNNING) ||
2133: ic->ic_state != IEEE80211_S_RUN) {
2134: return;
2135: }
2136:
2137: /*
2138: * Management packets should probably be MLME frames
2139: * (i.e. hostap "managed" mode); we don't touch the
2140: * net80211 management queue.
2141: */
2142: for (; sc->sc_dirtyq_count[PGT_QUEUE_DATA_LOW_TX] <
2143: PGT_QUEUE_FULL_THRESHOLD && !IFQ_IS_EMPTY(&ifp->if_snd);) {
2144: pd = TAILQ_FIRST(&sc->sc_freeq[PGT_QUEUE_DATA_LOW_TX]);
2145: IFQ_POLL(&ifp->if_snd, m);
2146: if (m == NULL)
2147: break;
2148: if (m->m_pkthdr.len <= PGT_FRAG_SIZE) {
2149: error = pgt_load_tx_desc_frag(sc,
2150: PGT_QUEUE_DATA_LOW_TX, pd);
2151: if (error)
2152: break;
2153: IFQ_DEQUEUE(&ifp->if_snd, m);
2154: m_copydata(m, 0, m->m_pkthdr.len, pd->pd_mem);
2155: pgt_desc_transmit(sc, PGT_QUEUE_DATA_LOW_TX,
2156: pd, m->m_pkthdr.len, 0);
2157: } else if (m->m_pkthdr.len <= PGT_FRAG_SIZE * 2) {
2158: struct pgt_desc *pd2;
2159:
2160: /*
2161: * Transmit a fragmented frame if there is
2162: * not enough room in one fragment; limit
2163: * to two fragments (802.11 itself couldn't
2164: * even support a full two.)
2165: */
2166: if (sc->sc_dirtyq_count[PGT_QUEUE_DATA_LOW_TX] + 2 >
2167: PGT_QUEUE_FULL_THRESHOLD)
2168: break;
2169: pd2 = TAILQ_NEXT(pd, pd_link);
2170: error = pgt_load_tx_desc_frag(sc,
2171: PGT_QUEUE_DATA_LOW_TX, pd);
2172: if (error == 0) {
2173: error = pgt_load_tx_desc_frag(sc,
2174: PGT_QUEUE_DATA_LOW_TX, pd2);
2175: if (error) {
2176: pgt_unload_tx_desc_frag(sc, pd);
2177: TAILQ_INSERT_HEAD(&sc->sc_freeq[
2178: PGT_QUEUE_DATA_LOW_TX], pd,
2179: pd_link);
2180: }
2181: }
2182: if (error)
2183: break;
2184: IFQ_DEQUEUE(&ifp->if_snd, m);
2185: m_copydata(m, 0, PGT_FRAG_SIZE, pd->pd_mem);
2186: pgt_desc_transmit(sc, PGT_QUEUE_DATA_LOW_TX,
2187: pd, PGT_FRAG_SIZE, 1);
2188: m_copydata(m, PGT_FRAG_SIZE,
2189: m->m_pkthdr.len - PGT_FRAG_SIZE, pd2->pd_mem);
2190: pgt_desc_transmit(sc, PGT_QUEUE_DATA_LOW_TX,
2191: pd2, m->m_pkthdr.len - PGT_FRAG_SIZE, 0);
2192: } else {
2193: IFQ_DEQUEUE(&ifp->if_snd, m);
2194: ifp->if_oerrors++;
2195: m_freem(m);
2196: m = NULL;
2197: }
2198: if (m != NULL) {
2199: struct ieee80211_node *ni;
2200: #if NBPFILTER > 0
2201: if (ifp->if_bpf != NULL)
2202: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
2203: #endif
2204: ifp->if_opackets++;
2205: ifp->if_timer = 1;
2206: sc->sc_txtimer = 5;
2207: ni = ieee80211_find_txnode(&sc->sc_ic,
2208: mtod(m, struct ether_header *)->ether_dhost);
2209: if (ni != NULL) {
2210: ni->ni_inact = 0;
2211: if (ni != ic->ic_bss)
2212: ieee80211_release_node(&sc->sc_ic, ni);
2213: }
2214: #if NBPFILTER > 0
2215: if (sc->sc_drvbpf != NULL) {
2216: struct mbuf mb;
2217: struct ether_header eh;
2218: struct pgt_tx_radiotap_hdr *tap = &sc->sc_txtap;
2219:
2220: bcopy(mtod(m, struct ether_header *), &eh,
2221: sizeof(eh));
2222: m_adj(m, sizeof(eh));
2223: m = pgt_ieee80211_encap(sc, &eh, m, NULL);
2224:
2225: tap->wt_flags = 0;
2226: //tap->wt_rate = rate;
2227: tap->wt_rate = 0;
2228: tap->wt_chan_freq =
2229: htole16(ic->ic_bss->ni_chan->ic_freq);
2230: tap->wt_chan_flags =
2231: htole16(ic->ic_bss->ni_chan->ic_flags);
2232:
2233: if (m != NULL) {
2234: mb.m_data = (caddr_t)tap;
2235: mb.m_len = sc->sc_txtap_len;
2236: mb.m_next = m;
2237: mb.m_nextpkt = NULL;
2238: mb.m_type = 0;
2239: mb.m_flags = 0;
2240:
2241: bpf_mtap(sc->sc_drvbpf, &mb,
2242: BPF_DIRECTION_OUT);
2243: }
2244: }
2245: #endif
2246: if (m != NULL)
2247: m_freem(m);
2248: }
2249: }
2250: }
2251:
2252: int
2253: pgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t req)
2254: {
2255: struct pgt_softc *sc = ifp->if_softc;
2256: struct ifaddr *ifa;
2257: struct ifreq *ifr;
2258: struct wi_req *wreq;
2259: struct ieee80211_nodereq_all *na;
2260: struct ieee80211com *ic;
2261: struct pgt_obj_bsslist *pob;
2262: struct wi_scan_p2_hdr *p2hdr;
2263: struct wi_scan_res *res;
2264: uint32_t noise;
2265: int maxscan, i, j, s, error = 0;
2266:
2267: ic = &sc->sc_ic;
2268: ifr = (struct ifreq *)req;
2269:
2270: s = splnet();
2271: switch (cmd) {
2272: case SIOCS80211SCAN:
2273: /*
2274: * This chip scans always as soon as it gets initialized.
2275: */
2276:
2277: /*
2278: * Give us a bit time to scan in case we were not
2279: * initialized before and let the userland process wait.
2280: */
2281: tsleep(&sc->sc_flags, 0, "pgtsca", hz * SCAN_TIMEOUT);
2282:
2283: break;
2284: case SIOCG80211ALLNODES: {
2285: struct ieee80211_nodereq *nr = NULL;
2286: na = (struct ieee80211_nodereq_all *)req;
2287: wreq = malloc(sizeof(*wreq), M_DEVBUF, M_WAITOK);
2288: bzero(wreq, sizeof(*wreq));
2289:
2290: maxscan = PGT_OBJ_BSSLIST_NBSS;
2291: pob = malloc(sizeof(*pob) +
2292: sizeof(struct pgt_obj_bss) * maxscan, M_DEVBUF, M_WAITOK);
2293: error = pgt_oid_get(sc, PGT_OID_NOISE_FLOOR, &noise,
2294: sizeof(noise));
2295:
2296: if (error == 0) {
2297: noise = letoh32(noise);
2298: error = pgt_oid_get(sc, PGT_OID_BSS_LIST, pob,
2299: sizeof(*pob) +
2300: sizeof(struct pgt_obj_bss) * maxscan);
2301: }
2302:
2303: if (error == 0) {
2304: maxscan = min(PGT_OBJ_BSSLIST_NBSS,
2305: letoh32(pob->pob_count));
2306: maxscan = min(maxscan,
2307: (sizeof(wreq->wi_val) - sizeof(*p2hdr)) /
2308: WI_PRISM2_RES_SIZE);
2309: p2hdr = (struct wi_scan_p2_hdr *)&wreq->wi_val;
2310: p2hdr->wi_rsvd = 0;
2311: p2hdr->wi_reason = 1;
2312: wreq->wi_len = (maxscan * WI_PRISM2_RES_SIZE) / 2 +
2313: sizeof(*p2hdr) / 2;
2314: wreq->wi_type = WI_RID_SCAN_RES;
2315: }
2316:
2317: for (na->na_nodes = j = i = 0; i < maxscan &&
2318: (na->na_size >= j + sizeof(struct ieee80211_nodereq));
2319: i++) {
2320: /* allocate node space */
2321: if (nr == NULL)
2322: nr = malloc(sizeof(*nr), M_DEVBUF, M_WAITOK);
2323:
2324: /* get next BSS scan result */
2325: res = (struct wi_scan_res *)
2326: ((char *)&wreq->wi_val + sizeof(*p2hdr) +
2327: i * WI_PRISM2_RES_SIZE);
2328: pgt_obj_bss2scanres(sc, &pob->pob_bsslist[i],
2329: res, noise);
2330:
2331: /* copy it to node structure for ifconfig to read */
2332: bzero(nr, sizeof(*nr));
2333: IEEE80211_ADDR_COPY(nr->nr_macaddr, res->wi_bssid);
2334: IEEE80211_ADDR_COPY(nr->nr_bssid, res->wi_bssid);
2335: nr->nr_channel = letoh16(res->wi_chan);
2336: nr->nr_chan_flags = IEEE80211_CHAN_B;
2337: nr->nr_rssi = letoh16(res->wi_signal);
2338: nr->nr_max_rssi = 0; /* XXX */
2339: nr->nr_nwid_len = letoh16(res->wi_ssid_len);
2340: bcopy(res->wi_ssid, nr->nr_nwid, nr->nr_nwid_len);
2341: nr->nr_intval = letoh16(res->wi_interval);
2342: nr->nr_capinfo = letoh16(res->wi_capinfo);
2343: nr->nr_txrate = res->wi_rate == WI_WAVELAN_RES_1M ? 2 :
2344: (res->wi_rate == WI_WAVELAN_RES_2M ? 4 :
2345: (res->wi_rate == WI_WAVELAN_RES_5M ? 11 :
2346: (res->wi_rate == WI_WAVELAN_RES_11M ? 22 : 0)));
2347: nr->nr_nrates = 0;
2348: while (res->wi_srates[nr->nr_nrates] != 0) {
2349: nr->nr_rates[nr->nr_nrates] =
2350: res->wi_srates[nr->nr_nrates] &
2351: WI_VAR_SRATES_MASK;
2352: nr->nr_nrates++;
2353: }
2354: nr->nr_flags = 0;
2355: if (bcmp(nr->nr_macaddr, nr->nr_bssid,
2356: IEEE80211_ADDR_LEN) == 0)
2357: nr->nr_flags |= IEEE80211_NODEREQ_AP;
2358: error = copyout(nr, (caddr_t)na->na_node + j,
2359: sizeof(struct ieee80211_nodereq));
2360: if (error)
2361: break;
2362:
2363: /* point to next node entry */
2364: j += sizeof(struct ieee80211_nodereq);
2365: na->na_nodes++;
2366: }
2367: if (nr)
2368: free(nr, M_DEVBUF);
2369: free(pob, M_DEVBUF);
2370: break;
2371: }
2372: case SIOCSIFADDR:
2373: ifa = (struct ifaddr *)req;
2374: ifp->if_flags |= IFF_UP;
2375: #ifdef INET
2376: if (ifa->ifa_addr->sa_family == AF_INET)
2377: arp_ifinit(&sc->sc_ic.ic_ac, ifa);
2378: #endif
2379: /* FALLTHROUGH */
2380: case SIOCSIFFLAGS:
2381: if (ifp->if_flags & IFF_UP) {
2382: if ((ifp->if_flags & IFF_RUNNING) == 0) {
2383: pgt_init(ifp);
2384: error = ENETRESET;
2385: }
2386: } else {
2387: if (ifp->if_flags & IFF_RUNNING) {
2388: pgt_stop(sc, SC_NEEDS_RESET);
2389: error = ENETRESET;
2390: }
2391: }
2392: break;
2393: case SIOCADDMULTI:
2394: case SIOCDELMULTI:
2395: error = (cmd == SIOCADDMULTI) ?
2396: ether_addmulti(ifr, &ic->ic_ac) :
2397: ether_delmulti(ifr, &ic->ic_ac);
2398:
2399: if (error == ENETRESET)
2400: error = 0;
2401: break;
2402: case SIOCSIFMTU:
2403: if (ifr->ifr_mtu > PGT_FRAG_SIZE) {
2404: error = EINVAL;
2405: break;
2406: }
2407: /* FALLTHROUGH */
2408: default:
2409: error = ieee80211_ioctl(ifp, cmd, req);
2410: break;
2411: }
2412:
2413: if (error == ENETRESET) {
2414: pgt_update_hw_from_sw(sc, 0, 0);
2415: error = 0;
2416: }
2417: splx(s);
2418:
2419: return (error);
2420: }
2421:
2422: void
2423: pgt_obj_bss2scanres(struct pgt_softc *sc, struct pgt_obj_bss *pob,
2424: struct wi_scan_res *scanres, uint32_t noise)
2425: {
2426: struct ieee80211_rateset *rs;
2427: struct wi_scan_res ap;
2428: unsigned int i, n;
2429:
2430: rs = &sc->sc_ic.ic_sup_rates[IEEE80211_MODE_AUTO];
2431: bzero(&ap, sizeof(ap));
2432: ap.wi_chan = ieee80211_mhz2ieee(letoh16(pob->pob_channel), 0);
2433: ap.wi_noise = noise;
2434: ap.wi_signal = letoh16(pob->pob_rssi);
2435: IEEE80211_ADDR_COPY(ap.wi_bssid, pob->pob_address);
2436: ap.wi_interval = letoh16(pob->pob_beacon_period);
2437: ap.wi_capinfo = letoh16(pob->pob_capinfo);
2438: ap.wi_ssid_len = min(sizeof(ap.wi_ssid), pob->pob_ssid.pos_length);
2439: memcpy(ap.wi_ssid, pob->pob_ssid.pos_ssid, ap.wi_ssid_len);
2440: n = 0;
2441: for (i = 0; i < 16; i++) {
2442: if (letoh16(pob->pob_rates) & (1 << i)) {
2443: if (i > rs->rs_nrates)
2444: break;
2445: ap.wi_srates[n++] = ap.wi_rate = rs->rs_rates[i];
2446: if (n >= sizeof(ap.wi_srates) / sizeof(ap.wi_srates[0]))
2447: break;
2448: }
2449: }
2450: memcpy(scanres, &ap, WI_PRISM2_RES_SIZE);
2451: }
2452:
2453: void
2454: node_mark_active_ap(void *arg, struct ieee80211_node *ni)
2455: {
2456: /*
2457: * HostAP mode lets all nodes stick around unless
2458: * the firmware AP kicks them off.
2459: */
2460: ni->ni_inact = 0;
2461: }
2462:
2463: void
2464: node_mark_active_adhoc(void *arg, struct ieee80211_node *ni)
2465: {
2466: struct pgt_ieee80211_node *pin;
2467:
2468: /*
2469: * As there is no association in ad-hoc, we let links just
2470: * time out naturally as long they are not holding any private
2471: * configuration, such as 802.1x authorization.
2472: */
2473: pin = (struct pgt_ieee80211_node *)ni;
2474: if (pin->pin_dot1x_auth == PIN_DOT1X_AUTHORIZED)
2475: pin->pin_node.ni_inact = 0;
2476: }
2477:
2478: void
2479: pgt_watchdog(struct ifnet *ifp)
2480: {
2481: struct pgt_softc *sc;
2482:
2483: sc = ifp->if_softc;
2484: /*
2485: * Check for timed out transmissions (and make sure to set
2486: * this watchdog to fire again if there is still data in the
2487: * output device queue).
2488: */
2489: if (sc->sc_dirtyq_count[PGT_QUEUE_DATA_LOW_TX] != 0) {
2490: int count;
2491:
2492: ifp->if_timer = 1;
2493: if (sc->sc_txtimer && --sc->sc_txtimer == 0) {
2494: count = pgt_drain_tx_queue(sc, PGT_QUEUE_DATA_LOW_TX);
2495: if (sc->sc_debug & SC_DEBUG_UNEXPECTED)
2496: DPRINTF(("%s: timeout %d data transmissions\n",
2497: sc->sc_dev.dv_xname, count));
2498: }
2499: }
2500: if (sc->sc_flags & (SC_DYING | SC_NEEDS_RESET))
2501: return;
2502: /*
2503: * If we're goign to kick the device out of power-save mode
2504: * just to update the BSSID and such, we should not do it
2505: * very often; need to determine in what way to do that.
2506: */
2507: if (ifp->if_flags & IFF_RUNNING &&
2508: sc->sc_ic.ic_state != IEEE80211_S_INIT &&
2509: sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR)
2510: pgt_async_update(sc);
2511:
2512: /*
2513: * As a firmware-based HostAP, we should not time out
2514: * nodes inside the driver additionally to the timeout
2515: * that exists in the firmware. The only things we
2516: * should have to deal with timing out when doing HostAP
2517: * are the privacy-related.
2518: */
2519: switch (sc->sc_ic.ic_opmode) {
2520: case IEEE80211_M_HOSTAP:
2521: ieee80211_iterate_nodes(&sc->sc_ic,
2522: node_mark_active_ap, NULL);
2523: break;
2524: case IEEE80211_M_IBSS:
2525: ieee80211_iterate_nodes(&sc->sc_ic,
2526: node_mark_active_adhoc, NULL);
2527: break;
2528: default:
2529: break;
2530: }
2531: ieee80211_watchdog(ifp);
2532: ifp->if_timer = 1;
2533: }
2534:
2535: int
2536: pgt_init(struct ifnet *ifp)
2537: {
2538: struct pgt_softc *sc = ifp->if_softc;
2539: struct ieee80211com *ic = &sc->sc_ic;
2540:
2541: /* set default channel */
2542: ic->ic_bss->ni_chan = ic->ic_ibss_chan;
2543:
2544: if (!(sc->sc_flags & (SC_DYING | SC_UNINITIALIZED)))
2545: pgt_update_hw_from_sw(sc,
2546: ic->ic_state != IEEE80211_S_INIT,
2547: ic->ic_opmode != IEEE80211_M_MONITOR);
2548:
2549: ifp->if_flags |= IFF_RUNNING;
2550: ifp->if_flags &= ~IFF_OACTIVE;
2551:
2552: /* Begin background scanning */
2553: ieee80211_new_state(&sc->sc_ic, IEEE80211_S_SCAN, -1);
2554:
2555: return (0);
2556: }
2557:
2558: /*
2559: * After most every configuration change, everything needs to be fully
2560: * reinitialized. For some operations (currently, WEP settings
2561: * in ad-hoc+802.1x mode), the change is "soft" and doesn't remove
2562: * "associations," and allows EAP authorization to occur again.
2563: * If keepassoc is specified, the reset operation should try to go
2564: * back to the BSS had before.
2565: */
2566: void
2567: pgt_update_hw_from_sw(struct pgt_softc *sc, int keepassoc, int keepnodes)
2568: {
2569: struct ieee80211com *ic = &sc->sc_ic;
2570: struct arpcom *ac = &ic->ic_ac;
2571: struct ifnet *ifp = &ac->ac_if;
2572: struct pgt_obj_key keyobj;
2573: struct pgt_obj_ssid essid;
2574: uint8_t availrates[IEEE80211_RATE_MAXSIZE + 1];
2575: uint32_t mode, bsstype, config, profile, channel, slot, preamble;
2576: uint32_t wep, exunencrypted, wepkey, dot1x, auth, mlme;
2577: unsigned int i;
2578: int success, shouldbeup, s;
2579:
2580: config = PGT_CONFIG_MANUAL_RUN | PGT_CONFIG_RX_ANNEX;
2581:
2582: /*
2583: * Promiscuous mode is currently a no-op since packets transmitted,
2584: * while in promiscuous mode, don't ever seem to go anywhere.
2585: */
2586: shouldbeup = ifp->if_flags & IFF_RUNNING && ifp->if_flags & IFF_UP;
2587:
2588: if (shouldbeup) {
2589: switch (ic->ic_opmode) {
2590: case IEEE80211_M_STA:
2591: if (ifp->if_flags & IFF_PROMISC)
2592: mode = PGT_MODE_CLIENT; /* what to do? */
2593: else
2594: mode = PGT_MODE_CLIENT;
2595: bsstype = PGT_BSS_TYPE_STA;
2596: dot1x = PGT_DOT1X_AUTH_ENABLED;
2597: break;
2598: case IEEE80211_M_IBSS:
2599: if (ifp->if_flags & IFF_PROMISC)
2600: mode = PGT_MODE_CLIENT; /* what to do? */
2601: else
2602: mode = PGT_MODE_CLIENT;
2603: bsstype = PGT_BSS_TYPE_IBSS;
2604: dot1x = PGT_DOT1X_AUTH_ENABLED;
2605: break;
2606: case IEEE80211_M_HOSTAP:
2607: mode = PGT_MODE_AP;
2608: bsstype = PGT_BSS_TYPE_STA;
2609: /*
2610: * For IEEE 802.1x, we need to authenticate and
2611: * authorize hosts from here on or they remain
2612: * associated but without the ability to send or
2613: * receive normal traffic to us (courtesy the
2614: * firmware AP implementation).
2615: */
2616: dot1x = PGT_DOT1X_AUTH_ENABLED;
2617: /*
2618: * WDS mode needs several things to work:
2619: * discovery of exactly how creating the WDS
2620: * links is meant to function, an interface
2621: * for this, and ability to encode or decode
2622: * the WDS frames.
2623: */
2624: if (sc->sc_wds)
2625: config |= PGT_CONFIG_WDS;
2626: break;
2627: case IEEE80211_M_MONITOR:
2628: mode = PGT_MODE_PROMISCUOUS;
2629: bsstype = PGT_BSS_TYPE_ANY;
2630: dot1x = PGT_DOT1X_AUTH_NONE;
2631: break;
2632: default:
2633: goto badopmode;
2634: }
2635: } else {
2636: badopmode:
2637: mode = PGT_MODE_CLIENT;
2638: bsstype = PGT_BSS_TYPE_NONE;
2639: }
2640:
2641: DPRINTF(("%s: current mode is ", sc->sc_dev.dv_xname));
2642: switch (ic->ic_curmode) {
2643: case IEEE80211_MODE_11A:
2644: profile = PGT_PROFILE_A_ONLY;
2645: preamble = PGT_OID_PREAMBLE_MODE_DYNAMIC;
2646: DPRINTF(("IEEE80211_MODE_11A\n"));
2647: break;
2648: case IEEE80211_MODE_11B:
2649: profile = PGT_PROFILE_B_ONLY;
2650: preamble = PGT_OID_PREAMBLE_MODE_LONG;
2651: DPRINTF(("IEEE80211_MODE_11B\n"));
2652: break;
2653: case IEEE80211_MODE_11G:
2654: profile = PGT_PROFILE_G_ONLY;
2655: preamble = PGT_OID_PREAMBLE_MODE_SHORT;
2656: DPRINTF(("IEEE80211_MODE_11G\n"));
2657: break;
2658: case IEEE80211_MODE_FH:
2659: /* FALLTHROUGH */
2660: case IEEE80211_MODE_TURBO: /* not handled */
2661: /* FALLTHROUGH */
2662: case IEEE80211_MODE_AUTO:
2663: profile = PGT_PROFILE_MIXED_G_WIFI;
2664: preamble = PGT_OID_PREAMBLE_MODE_DYNAMIC;
2665: DPRINTF(("IEEE80211_MODE_AUTO\n"));
2666: break;
2667: default:
2668: panic("unknown mode %d\n", ic->ic_curmode);
2669: }
2670:
2671: switch (sc->sc_80211_ioc_auth) {
2672: case IEEE80211_AUTH_NONE:
2673: auth = PGT_AUTH_MODE_NONE;
2674: break;
2675: case IEEE80211_AUTH_OPEN:
2676: auth = PGT_AUTH_MODE_OPEN;
2677: break;
2678: default:
2679: auth = PGT_AUTH_MODE_SHARED;
2680: break;
2681: }
2682:
2683: if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
2684: wep = 1;
2685: exunencrypted = 1;
2686: } else {
2687: wep = 0;
2688: exunencrypted = 0;
2689: }
2690:
2691: mlme = htole32(PGT_MLME_AUTO_LEVEL_AUTO);
2692: wep = htole32(wep);
2693: exunencrypted = htole32(exunencrypted);
2694: profile = htole32(profile);
2695: preamble = htole32(preamble);
2696: bsstype = htole32(bsstype);
2697: config = htole32(config);
2698: mode = htole32(mode);
2699:
2700: if (!wep || !sc->sc_dot1x)
2701: dot1x = PGT_DOT1X_AUTH_NONE;
2702: dot1x = htole32(dot1x);
2703: auth = htole32(auth);
2704:
2705: if (ic->ic_flags & IEEE80211_F_SHSLOT)
2706: slot = htole32(PGT_OID_SLOT_MODE_SHORT);
2707: else
2708: slot = htole32(PGT_OID_SLOT_MODE_DYNAMIC);
2709:
2710: if (ic->ic_des_chan == IEEE80211_CHAN_ANYC) {
2711: if (keepassoc)
2712: channel = 0;
2713: else
2714: channel = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
2715: } else
2716: channel = ieee80211_chan2ieee(ic, ic->ic_des_chan);
2717:
2718: DPRINTF(("%s: set rates", sc->sc_dev.dv_xname));
2719: for (i = 0; i < ic->ic_sup_rates[ic->ic_curmode].rs_nrates; i++) {
2720: availrates[i] = ic->ic_sup_rates[ic->ic_curmode].rs_rates[i];
2721: DPRINTF((" %d", availrates[i]));
2722: }
2723: DPRINTF(("\n"));
2724: availrates[i++] = 0;
2725:
2726: essid.pos_length = min(ic->ic_des_esslen, sizeof(essid.pos_ssid));
2727: memcpy(&essid.pos_ssid, ic->ic_des_essid, essid.pos_length);
2728:
2729: s = splnet();
2730: for (success = 0; success == 0; success = 1) {
2731: SETOID(PGT_OID_PROFILE, &profile, sizeof(profile));
2732: SETOID(PGT_OID_CONFIG, &config, sizeof(config));
2733: SETOID(PGT_OID_MLME_AUTO_LEVEL, &mlme, sizeof(mlme));
2734:
2735: if (!IEEE80211_ADDR_EQ(ic->ic_myaddr, ac->ac_enaddr)) {
2736: SETOID(PGT_OID_MAC_ADDRESS, ac->ac_enaddr,
2737: sizeof(ac->ac_enaddr));
2738: IEEE80211_ADDR_COPY(ic->ic_myaddr, ac->ac_enaddr);
2739: }
2740:
2741: SETOID(PGT_OID_MODE, &mode, sizeof(mode));
2742: SETOID(PGT_OID_BSS_TYPE, &bsstype, sizeof(bsstype));
2743:
2744: if (channel != 0 && channel != IEEE80211_CHAN_ANY)
2745: SETOID(PGT_OID_CHANNEL, &channel, sizeof(channel));
2746:
2747: if (ic->ic_flags & IEEE80211_F_DESBSSID) {
2748: SETOID(PGT_OID_BSSID, ic->ic_des_bssid,
2749: sizeof(ic->ic_des_bssid));
2750: } else if (keepassoc) {
2751: SETOID(PGT_OID_BSSID, ic->ic_bss->ni_bssid,
2752: sizeof(ic->ic_bss->ni_bssid));
2753: }
2754:
2755: SETOID(PGT_OID_SSID, &essid, sizeof(essid));
2756:
2757: if (ic->ic_des_esslen > 0)
2758: SETOID(PGT_OID_SSID_OVERRIDE, &essid, sizeof(essid));
2759:
2760: SETOID(PGT_OID_RATES, &availrates, i);
2761: SETOID(PGT_OID_EXTENDED_RATES, &availrates, i);
2762: SETOID(PGT_OID_PREAMBLE_MODE, &preamble, sizeof(preamble));
2763: SETOID(PGT_OID_SLOT_MODE, &slot, sizeof(slot));
2764: SETOID(PGT_OID_AUTH_MODE, &auth, sizeof(auth));
2765: SETOID(PGT_OID_EXCLUDE_UNENCRYPTED, &exunencrypted,
2766: sizeof(exunencrypted));
2767: SETOID(PGT_OID_DOT1X, &dot1x, sizeof(dot1x));
2768: SETOID(PGT_OID_PRIVACY_INVOKED, &wep, sizeof(wep));
2769: /*
2770: * Setting WEP key(s)
2771: */
2772: if (letoh32(wep) != 0) {
2773: keyobj.pok_type = PGT_OBJ_KEY_TYPE_WEP;
2774: /* key 1 */
2775: keyobj.pok_length = min(sizeof(keyobj.pok_key),
2776: IEEE80211_KEYBUF_SIZE);
2777: keyobj.pok_length = min(keyobj.pok_length,
2778: ic->ic_nw_keys[0].k_len);
2779: bcopy(ic->ic_nw_keys[0].k_key, keyobj.pok_key,
2780: keyobj.pok_length);
2781: SETOID(PGT_OID_DEFAULT_KEY0, &keyobj, sizeof(keyobj));
2782: /* key 2 */
2783: keyobj.pok_length = min(sizeof(keyobj.pok_key),
2784: IEEE80211_KEYBUF_SIZE);
2785: keyobj.pok_length = min(keyobj.pok_length,
2786: ic->ic_nw_keys[1].k_len);
2787: bcopy(ic->ic_nw_keys[1].k_key, keyobj.pok_key,
2788: keyobj.pok_length);
2789: SETOID(PGT_OID_DEFAULT_KEY1, &keyobj, sizeof(keyobj));
2790: /* key 3 */
2791: keyobj.pok_length = min(sizeof(keyobj.pok_key),
2792: IEEE80211_KEYBUF_SIZE);
2793: keyobj.pok_length = min(keyobj.pok_length,
2794: ic->ic_nw_keys[2].k_len);
2795: bcopy(ic->ic_nw_keys[2].k_key, keyobj.pok_key,
2796: keyobj.pok_length);
2797: SETOID(PGT_OID_DEFAULT_KEY2, &keyobj, sizeof(keyobj));
2798: /* key 4 */
2799: keyobj.pok_length = min(sizeof(keyobj.pok_key),
2800: IEEE80211_KEYBUF_SIZE);
2801: keyobj.pok_length = min(keyobj.pok_length,
2802: ic->ic_nw_keys[3].k_len);
2803: bcopy(ic->ic_nw_keys[3].k_key, keyobj.pok_key,
2804: keyobj.pok_length);
2805: SETOID(PGT_OID_DEFAULT_KEY3, &keyobj, sizeof(keyobj));
2806:
2807: wepkey = htole32(ic->ic_wep_txkey);
2808: SETOID(PGT_OID_DEFAULT_KEYNUM, &wepkey, sizeof(wepkey));
2809: }
2810: /* set mode again to commit */
2811: SETOID(PGT_OID_MODE, &mode, sizeof(mode));
2812: }
2813: splx(s);
2814:
2815: if (success) {
2816: if (shouldbeup && keepnodes)
2817: sc->sc_flags |= SC_NOFREE_ALLNODES;
2818: if (shouldbeup)
2819: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2820: else
2821: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2822: } else {
2823: printf("%s: problem setting modes\n", sc->sc_dev.dv_xname);
2824: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2825: }
2826: }
2827:
2828: void
2829: pgt_hostap_handle_mlme(struct pgt_softc *sc, uint32_t oid,
2830: struct pgt_obj_mlme *mlme)
2831: {
2832: struct ieee80211com *ic = &sc->sc_ic;
2833: struct pgt_ieee80211_node *pin;
2834: struct ieee80211_node *ni;
2835:
2836: ni = ieee80211_find_node(ic, mlme->pom_address);
2837: pin = (struct pgt_ieee80211_node *)ni;
2838: switch (oid) {
2839: case PGT_OID_DISASSOCIATE:
2840: if (ni != NULL)
2841: ieee80211_release_node(&sc->sc_ic, ni);
2842: break;
2843: case PGT_OID_ASSOCIATE:
2844: if (ni == NULL) {
2845: ni = ieee80211_dup_bss(ic, mlme->pom_address);
2846: if (ni == NULL)
2847: break;
2848: ic->ic_newassoc(ic, ni, 1);
2849: pin = (struct pgt_ieee80211_node *)ni;
2850: }
2851: ni->ni_associd = letoh16(mlme->pom_id);
2852: pin->pin_mlme_state = letoh16(mlme->pom_state);
2853: break;
2854: default:
2855: if (pin != NULL)
2856: pin->pin_mlme_state = letoh16(mlme->pom_state);
2857: break;
2858: }
2859: }
2860:
2861: /*
2862: * Either in response to an event or after a certain amount of time,
2863: * synchronize our idea of the network we're part of from the hardware.
2864: */
2865: void
2866: pgt_update_sw_from_hw(struct pgt_softc *sc, struct pgt_async_trap *pa,
2867: struct mbuf *args)
2868: {
2869: struct ieee80211com *ic = &sc->sc_ic;
2870: struct pgt_obj_ssid ssid;
2871: struct pgt_obj_bss bss;
2872: uint32_t channel, noise, ls;
2873: int error, s;
2874:
2875: if (pa != NULL) {
2876: struct pgt_obj_mlme *mlme;
2877: uint32_t oid;
2878:
2879: oid = *mtod(args, uint32_t *);
2880: m_adj(args, sizeof(uint32_t));
2881: if (sc->sc_debug & SC_DEBUG_TRAP)
2882: DPRINTF(("%s: trap: oid %#x len %u\n",
2883: sc->sc_dev.dv_xname, oid, args->m_len));
2884: switch (oid) {
2885: case PGT_OID_LINK_STATE:
2886: if (args->m_len < sizeof(uint32_t))
2887: break;
2888: ls = letoh32(*mtod(args, uint32_t *));
2889: if (sc->sc_debug & (SC_DEBUG_TRAP | SC_DEBUG_LINK))
2890: DPRINTF(("%s: %s: link rate %u\n",
2891: sc->sc_dev.dv_xname, __func__, ls));
2892: if (ls)
2893: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2894: else
2895: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2896: goto gotlinkstate;
2897: case PGT_OID_DEAUTHENTICATE:
2898: case PGT_OID_AUTHENTICATE:
2899: case PGT_OID_DISASSOCIATE:
2900: case PGT_OID_ASSOCIATE:
2901: if (args->m_len < sizeof(struct pgt_obj_mlme))
2902: break;
2903: mlme = mtod(args, struct pgt_obj_mlme *);
2904: if (sc->sc_debug & SC_DEBUG_TRAP)
2905: DPRINTF(("%s: mlme: address "
2906: "%s id 0x%02x state 0x%02x code 0x%02x\n",
2907: sc->sc_dev.dv_xname,
2908: ether_sprintf(mlme->pom_address),
2909: letoh16(mlme->pom_id),
2910: letoh16(mlme->pom_state),
2911: letoh16(mlme->pom_code)));
2912: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2913: pgt_hostap_handle_mlme(sc, oid, mlme);
2914: break;
2915: }
2916: return;
2917: }
2918: if (ic->ic_state == IEEE80211_S_SCAN) {
2919: s = splnet();
2920: error = pgt_oid_get(sc, PGT_OID_LINK_STATE, &ls, sizeof(ls));
2921: splx(s);
2922: if (error)
2923: return;
2924: DPRINTF(("%s: up_sw_from_hw: link %u\n", sc->sc_dev.dv_xname,
2925: htole32(ls)));
2926: if (ls != 0)
2927: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2928: }
2929:
2930: gotlinkstate:
2931: s = splnet();
2932: if (pgt_oid_get(sc, PGT_OID_NOISE_FLOOR, &noise, sizeof(noise)) != 0)
2933: goto out;
2934: sc->sc_noise = letoh32(noise);
2935: if (ic->ic_state == IEEE80211_S_RUN) {
2936: if (pgt_oid_get(sc, PGT_OID_CHANNEL, &channel,
2937: sizeof(channel)) != 0)
2938: goto out;
2939: channel = min(letoh32(channel), IEEE80211_CHAN_MAX);
2940: ic->ic_bss->ni_chan = &ic->ic_channels[channel];
2941: if (pgt_oid_get(sc, PGT_OID_BSSID, ic->ic_bss->ni_bssid,
2942: sizeof(ic->ic_bss->ni_bssid)) != 0)
2943: goto out;
2944: IEEE80211_ADDR_COPY(&bss.pob_address, ic->ic_bss->ni_bssid);
2945: error = pgt_oid_retrieve(sc, PGT_OID_BSS_FIND, &bss,
2946: sizeof(bss));
2947: if (error == 0)
2948: ic->ic_bss->ni_rssi = bss.pob_rssi;
2949: else if (error != EPERM)
2950: goto out;
2951: error = pgt_oid_get(sc, PGT_OID_SSID, &ssid, sizeof(ssid));
2952: if (error)
2953: goto out;
2954: ic->ic_bss->ni_esslen = min(ssid.pos_length,
2955: sizeof(ic->ic_bss->ni_essid));
2956: memcpy(ic->ic_bss->ni_essid, ssid.pos_ssid,
2957: ssid.pos_length);
2958: }
2959:
2960: out:
2961: splx(s);
2962: }
2963:
2964: int
2965: pgt_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2966: {
2967: struct pgt_softc *sc = ic->ic_if.if_softc;
2968: enum ieee80211_state ostate;
2969:
2970: ostate = ic->ic_state;
2971:
2972: DPRINTF(("%s: newstate %s -> %s\n", sc->sc_dev.dv_xname,
2973: ieee80211_state_name[ostate], ieee80211_state_name[nstate]));
2974:
2975: switch (nstate) {
2976: case IEEE80211_S_INIT:
2977: if (sc->sc_dirtyq_count[PGT_QUEUE_DATA_LOW_TX] == 0)
2978: ic->ic_if.if_timer = 0;
2979: ic->ic_mgt_timer = 0;
2980: ic->ic_flags &= ~IEEE80211_F_SIBSS;
2981: if (ic->ic_wep_ctx != NULL) {
2982: free(ic->ic_wep_ctx, M_DEVBUF);
2983: ic->ic_wep_ctx = NULL;
2984: }
2985: ieee80211_free_allnodes(ic);
2986: break;
2987: case IEEE80211_S_SCAN:
2988: ic->ic_if.if_timer = 1;
2989: ic->ic_mgt_timer = 0;
2990: if (sc->sc_flags & SC_NOFREE_ALLNODES)
2991: sc->sc_flags &= ~SC_NOFREE_ALLNODES;
2992: else
2993: ieee80211_free_allnodes(ic);
2994:
2995: /* Just use any old channel; we override it anyway. */
2996: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2997: ieee80211_create_ibss(ic, ic->ic_ibss_chan);
2998: break;
2999: case IEEE80211_S_RUN:
3000: ic->ic_if.if_timer = 1;
3001: break;
3002: default:
3003: break;
3004: }
3005:
3006: return (sc->sc_newstate(ic, nstate, arg));
3007: }
3008:
3009: int
3010: pgt_drain_tx_queue(struct pgt_softc *sc, enum pgt_queue pq)
3011: {
3012: int wokeup = 0;
3013:
3014: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
3015: sc->sc_cbdmam->dm_mapsize,
3016: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE);
3017: sc->sc_cb->pcb_device_curfrag[pq] =
3018: sc->sc_cb->pcb_driver_curfrag[pq];
3019: bus_dmamap_sync(sc->sc_dmat, sc->sc_cbdmam, 0,
3020: sc->sc_cbdmam->dm_mapsize,
3021: BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_PREREAD);
3022: while (!TAILQ_EMPTY(&sc->sc_dirtyq[pq])) {
3023: struct pgt_desc *pd;
3024:
3025: pd = TAILQ_FIRST(&sc->sc_dirtyq[pq]);
3026: TAILQ_REMOVE(&sc->sc_dirtyq[pq], pd, pd_link);
3027: sc->sc_dirtyq_count[pq]--;
3028: TAILQ_INSERT_TAIL(&sc->sc_freeq[pq], pd, pd_link);
3029: sc->sc_freeq_count[pq]++;
3030: pgt_unload_tx_desc_frag(sc, pd);
3031: if (sc->sc_debug & SC_DEBUG_QUEUES)
3032: DPRINTF(("%s: queue: tx %u <- [%u] (drained)\n",
3033: sc->sc_dev.dv_xname, pd->pd_fragnum, pq));
3034: wokeup++;
3035: if (pgt_queue_is_data(pq))
3036: sc->sc_ic.ic_if.if_oerrors++;
3037: }
3038:
3039: return (wokeup);
3040: }
3041:
3042: int
3043: pgt_dma_alloc(struct pgt_softc *sc)
3044: {
3045: size_t size;
3046: int i, error, nsegs;
3047:
3048: for (i = 0; i < PGT_QUEUE_COUNT; i++) {
3049: TAILQ_INIT(&sc->sc_freeq[i]);
3050: TAILQ_INIT(&sc->sc_dirtyq[i]);
3051: }
3052:
3053: /*
3054: * control block
3055: */
3056: size = sizeof(struct pgt_control_block);
3057:
3058: error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
3059: BUS_DMA_NOWAIT, &sc->sc_cbdmam);
3060: if (error != 0) {
3061: printf("%s: can not create DMA tag for control block\n",
3062: sc->sc_dev.dv_xname);
3063: goto out;
3064: }
3065:
3066: error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE,
3067: 0, &sc->sc_cbdmas, 1, &nsegs, BUS_DMA_NOWAIT);
3068: if (error != 0) {
3069: printf("%s: can not allocate DMA memory for control block\n",
3070: sc->sc_dev.dv_xname);
3071: goto out;
3072: }
3073:
3074: error = bus_dmamem_map(sc->sc_dmat, &sc->sc_cbdmas, nsegs,
3075: size, (caddr_t *)&sc->sc_cb, BUS_DMA_NOWAIT);
3076: if (error != 0) {
3077: printf("%s: can not map DMA memory for control block\n",
3078: sc->sc_dev.dv_xname);
3079: goto out;
3080: }
3081: bzero(sc->sc_cb, size);
3082:
3083: error = bus_dmamap_load(sc->sc_dmat, sc->sc_cbdmam,
3084: sc->sc_cb, size, NULL, BUS_DMA_NOWAIT);
3085: if (error != 0) {
3086: printf("%s: can not load DMA map for control block\n",
3087: sc->sc_dev.dv_xname);
3088: goto out;
3089: }
3090:
3091: /*
3092: * powersave
3093: */
3094: size = PGT_FRAG_SIZE * PGT_PSM_BUFFER_FRAME_COUNT;
3095:
3096: error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
3097: BUS_DMA_ALLOCNOW, &sc->sc_psmdmam);
3098: if (error != 0) {
3099: printf("%s: can not create DMA tag for powersave\n",
3100: sc->sc_dev.dv_xname);
3101: goto out;
3102: }
3103:
3104: error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE,
3105: 0, &sc->sc_psmdmas, 1, &nsegs, BUS_DMA_NOWAIT);
3106: if (error != 0) {
3107: printf("%s: can not allocate DMA memory for powersave\n",
3108: sc->sc_dev.dv_xname);
3109: goto out;
3110: }
3111:
3112: error = bus_dmamem_map(sc->sc_dmat, &sc->sc_psmdmas, nsegs,
3113: size, (caddr_t *)&sc->sc_psmbuf, BUS_DMA_NOWAIT);
3114: if (error != 0) {
3115: printf("%s: can not map DMA memory for powersave\n",
3116: sc->sc_dev.dv_xname);
3117: goto out;
3118: }
3119: bzero(sc->sc_psmbuf, size);
3120:
3121: error = bus_dmamap_load(sc->sc_dmat, sc->sc_psmdmam,
3122: sc->sc_psmbuf, size, NULL, BUS_DMA_WAITOK);
3123: if (error != 0) {
3124: printf("%s: can not load DMA map for powersave\n",
3125: sc->sc_dev.dv_xname);
3126: goto out;
3127: }
3128:
3129: /*
3130: * fragments
3131: */
3132: error = pgt_dma_alloc_queue(sc, PGT_QUEUE_DATA_LOW_RX);
3133: if (error != 0)
3134: goto out;
3135:
3136: error = pgt_dma_alloc_queue(sc, PGT_QUEUE_DATA_LOW_TX);
3137: if (error != 0)
3138: goto out;
3139:
3140: error = pgt_dma_alloc_queue(sc, PGT_QUEUE_DATA_HIGH_RX);
3141: if (error != 0)
3142: goto out;
3143:
3144: error = pgt_dma_alloc_queue(sc, PGT_QUEUE_DATA_HIGH_TX);
3145: if (error != 0)
3146: goto out;
3147:
3148: error = pgt_dma_alloc_queue(sc, PGT_QUEUE_MGMT_RX);
3149: if (error != 0)
3150: goto out;
3151:
3152: error = pgt_dma_alloc_queue(sc, PGT_QUEUE_MGMT_TX);
3153: if (error != 0)
3154: goto out;
3155:
3156: out:
3157: if (error) {
3158: printf("%s: error in DMA allocation\n", sc->sc_dev.dv_xname);
3159: pgt_dma_free(sc);
3160: }
3161:
3162: return (error);
3163: }
3164:
3165: int
3166: pgt_dma_alloc_queue(struct pgt_softc *sc, enum pgt_queue pq)
3167: {
3168: struct pgt_desc *pd;
3169: struct pgt_frag *pcbqueue;
3170: size_t i, qsize;
3171: int error, nsegs;
3172:
3173: switch (pq) {
3174: case PGT_QUEUE_DATA_LOW_RX:
3175: pcbqueue = sc->sc_cb->pcb_data_low_rx;
3176: qsize = PGT_QUEUE_DATA_RX_SIZE;
3177: break;
3178: case PGT_QUEUE_DATA_LOW_TX:
3179: pcbqueue = sc->sc_cb->pcb_data_low_tx;
3180: qsize = PGT_QUEUE_DATA_TX_SIZE;
3181: break;
3182: case PGT_QUEUE_DATA_HIGH_RX:
3183: pcbqueue = sc->sc_cb->pcb_data_high_rx;
3184: qsize = PGT_QUEUE_DATA_RX_SIZE;
3185: break;
3186: case PGT_QUEUE_DATA_HIGH_TX:
3187: pcbqueue = sc->sc_cb->pcb_data_high_tx;
3188: qsize = PGT_QUEUE_DATA_TX_SIZE;
3189: break;
3190: case PGT_QUEUE_MGMT_RX:
3191: pcbqueue = sc->sc_cb->pcb_mgmt_rx;
3192: qsize = PGT_QUEUE_MGMT_SIZE;
3193: break;
3194: case PGT_QUEUE_MGMT_TX:
3195: pcbqueue = sc->sc_cb->pcb_mgmt_tx;
3196: qsize = PGT_QUEUE_MGMT_SIZE;
3197: break;
3198: }
3199:
3200: for (i = 0; i < qsize; i++) {
3201: pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
3202:
3203: error = bus_dmamap_create(sc->sc_dmat, PGT_FRAG_SIZE, 1,
3204: PGT_FRAG_SIZE, 0, BUS_DMA_ALLOCNOW, &pd->pd_dmam);
3205: if (error != 0) {
3206: printf("%s: can not create DMA tag for fragment\n",
3207: sc->sc_dev.dv_xname);
3208: free(pd, M_DEVBUF);
3209: break;
3210: }
3211:
3212: error = bus_dmamem_alloc(sc->sc_dmat, PGT_FRAG_SIZE, PAGE_SIZE,
3213: 0, &pd->pd_dmas, 1, &nsegs, BUS_DMA_WAITOK);
3214: if (error != 0) {
3215: printf("%s: error alloc frag %u on queue %u\n",
3216: sc->sc_dev.dv_xname, i, pq);
3217: free(pd, M_DEVBUF);
3218: break;
3219: }
3220:
3221: error = bus_dmamem_map(sc->sc_dmat, &pd->pd_dmas, nsegs,
3222: PGT_FRAG_SIZE, (caddr_t *)&pd->pd_mem, BUS_DMA_WAITOK);
3223: if (error != 0) {
3224: printf("%s: error map frag %u on queue %u\n",
3225: sc->sc_dev.dv_xname, i, pq);
3226: free(pd, M_DEVBUF);
3227: break;
3228: }
3229:
3230: if (pgt_queue_is_rx(pq)) {
3231: error = bus_dmamap_load(sc->sc_dmat, pd->pd_dmam,
3232: pd->pd_mem, PGT_FRAG_SIZE, NULL, BUS_DMA_NOWAIT);
3233: if (error != 0) {
3234: printf("%s: error load frag %u on queue %u\n",
3235: sc->sc_dev.dv_xname, i, pq);
3236: bus_dmamem_free(sc->sc_dmat, &pd->pd_dmas,
3237: nsegs);
3238: free(pd, M_DEVBUF);
3239: break;
3240: }
CVSweb