diff --git a/data/system/data/firmware/iprowifi4965/iwlwifi-6000g2b-ucode-18.168.6.1.tgz b/data/system/data/firmware/iprowifi4965/iwlwifi-6000g2b-ucode-18.168.6.1.tgz new file mode 100644 index 0000000000..3d1dc4414a Binary files /dev/null and b/data/system/data/firmware/iprowifi4965/iwlwifi-6000g2b-ucode-18.168.6.1.tgz differ diff --git a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an.c b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an.c index 63cface801..0898961e95 100644 --- a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an.c +++ b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an.c @@ -102,7 +102,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include @@ -140,9 +139,11 @@ static void an_reset(struct an_softc *); static int an_init_mpi350_desc(struct an_softc *); static int an_ioctl(struct ifnet *, u_long, caddr_t); static void an_init(void *); +static void an_init_locked(struct an_softc *); static int an_init_tx_ring(struct an_softc *); static void an_start(struct ifnet *); -static void an_watchdog(struct ifnet *); +static void an_start_locked(struct ifnet *); +static void an_watchdog(struct an_softc *); static void an_rxeof(struct an_softc *); static void an_txeof(struct an_softc *, int); @@ -314,7 +315,7 @@ an_pci_probe(device_t dev) struct an_softc *sc = device_get_softc(dev); mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + MTX_DEF); return(0); } @@ -347,10 +348,6 @@ an_probe(device_t dev) * to be able to issue commands and call some of the * other routines. */ - sc->an_bhandle = rman_get_bushandle(sc->port_res); - sc->an_btag = rman_get_bustag(sc->port_res); - sc->an_unit = device_get_unit(dev); - ssid.an_len = sizeof(ssid); ssid.an_type = AN_RID_SSIDLIST; @@ -360,7 +357,7 @@ an_probe(device_t dev) CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF); mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + MTX_DEF); AN_LOCK(sc); an_reset(sc); @@ -600,8 +597,7 @@ an_init_mpi350_desc(struct an_softc *sc) cmd_struct.an_parm1 = AN_RX_DESC_OFFSET; cmd_struct.an_parm2 = AN_MAX_RX_DESC; if (an_cmd_struct(sc, &cmd_struct, &reply)) { - printf("an%d: failed to allocate RX descriptor\n", - sc->an_unit); + if_printf(sc->an_ifp, "failed to allocate RX descriptor\n"); return(EIO); } @@ -629,8 +625,7 @@ an_init_mpi350_desc(struct an_softc *sc) cmd_struct.an_parm1 = AN_TX_DESC_OFFSET; cmd_struct.an_parm2 = AN_MAX_TX_DESC; if (an_cmd_struct(sc, &cmd_struct, &reply)) { - printf("an%d: failed to allocate TX descriptor\n", - sc->an_unit); + if_printf(sc->an_ifp, "failed to allocate TX descriptor\n"); return(EIO); } @@ -659,8 +654,7 @@ an_init_mpi350_desc(struct an_softc *sc) cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET; cmd_struct.an_parm2 = 1; if (an_cmd_struct(sc, &cmd_struct, &reply)) { - printf("an%d: failed to allocate host descriptor\n", - sc->an_unit); + if_printf(sc->an_ifp, "failed to allocate host descriptor\n"); return(EIO); } @@ -678,7 +672,7 @@ an_init_mpi350_desc(struct an_softc *sc) } int -an_attach(struct an_softc *sc, int unit, int flags) +an_attach(struct an_softc *sc, int flags) { struct ifnet *ifp; int error = EIO; @@ -687,7 +681,7 @@ an_attach(struct an_softc *sc, int unit, int flags) ifp = sc->an_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { - printf("an%d: can not if_alloc()\n", sc->an_unit); + device_printf(sc->an_dev, "can not if_alloc()\n"); goto fail; } @@ -708,7 +702,7 @@ an_attach(struct an_softc *sc, int unit, int flags) /* Load factory config */ if (an_cmd(sc, AN_CMD_READCFG, 0)) { - printf("an%d: failed to load config data\n", sc->an_unit); + device_printf(sc->an_dev, "failed to load config data\n"); goto fail; } @@ -716,7 +710,7 @@ an_attach(struct an_softc *sc, int unit, int flags) sc->an_config.an_type = AN_RID_GENCONFIG; sc->an_config.an_len = sizeof(struct an_ltv_genconfig); if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { - printf("an%d: read record failed\n", sc->an_unit); + device_printf(sc->an_dev, "read record failed\n"); goto fail; } @@ -724,7 +718,7 @@ an_attach(struct an_softc *sc, int unit, int flags) sc->an_caps.an_type = AN_RID_CAPABILITIES; sc->an_caps.an_len = sizeof(struct an_ltv_caps); if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { - printf("an%d: read record failed\n", sc->an_unit); + device_printf(sc->an_dev, "read record failed\n"); goto fail; } @@ -732,7 +726,7 @@ an_attach(struct an_softc *sc, int unit, int flags) sc->an_ssidlist.an_type = AN_RID_SSIDLIST; sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { - printf("an%d: read record failed\n", sc->an_unit); + device_printf(sc->an_dev, "read record failed\n"); goto fail; } @@ -740,7 +734,7 @@ an_attach(struct an_softc *sc, int unit, int flags) sc->an_aplist.an_type = AN_RID_APLIST; sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { - printf("an%d: read record failed\n", sc->an_unit); + device_printf(sc->an_dev, "read record failed\n"); goto fail; } @@ -751,26 +745,25 @@ an_attach(struct an_softc *sc, int unit, int flags) sc->an_rssimap.an_type = AN_RID_RSSI_MAP; sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map); if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) { - printf("an%d: unable to get RSSI <-> dBM map\n", sc->an_unit); + device_printf(sc->an_dev, + "unable to get RSSI <-> dBM map\n"); } else { - printf("an%d: got RSSI <-> dBM map\n", sc->an_unit); + device_printf(sc->an_dev, "got RSSI <-> dBM map\n"); sc->an_have_rssimap = 1; } } else { - printf("an%d: no RSSI <-> dBM map\n", sc->an_unit); + device_printf(sc->an_dev, "no RSSI <-> dBM map\n"); } #endif AN_UNLOCK(sc); ifp->if_softc = sc; - sc->an_unit = unit; if_initname(ifp, device_get_name(sc->an_dev), device_get_unit(sc->an_dev)); ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = an_ioctl; ifp->if_start = an_start; - ifp->if_watchdog = an_watchdog; ifp->if_init = an_init; ifp->if_baudrate = 10000000; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); @@ -897,7 +890,7 @@ an_rxeof(struct an_softc *sc) */ if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) && - (rx_frame.an_frame_ctl & + (rx_frame.an_frame_ctl & IEEE80211_FC0_SUBTYPE_BEACON)) { return; } @@ -907,9 +900,9 @@ an_rxeof(struct an_softc *sc) + sizeof(rx_frame); /* Check for insane frame length */ if (len > sizeof(sc->buf_802_11)) { - printf("an%d: oversized packet " + if_printf(ifp, "oversized packet " "received (%d, %d)\n", - sc->an_unit, len, MCLBYTES); + len, MCLBYTES); ifp->if_ierrors++; return; } @@ -933,9 +926,9 @@ an_rxeof(struct an_softc *sc) + ieee80211_header_len; /* Check for insane frame length */ if (len > sizeof(sc->buf_802_11)) { - printf("an%d: oversized packet " + if_printf(ifp, "oversized packet " "received (%d, %d)\n", - sc->an_unit, len, MCLBYTES); + len, MCLBYTES); ifp->if_ierrors++; return; } @@ -993,9 +986,9 @@ an_rxeof(struct an_softc *sc) len = rx_frame_802_3.an_rx_802_3_payload_len; if (len > sizeof(sc->buf_802_11)) { m_freem(m); - printf("an%d: oversized packet " + if_printf(ifp, "oversized packet " "received (%d, %d)\n", - sc->an_unit, len, MCLBYTES); + len, MCLBYTES); ifp->if_ierrors++; return; } @@ -1073,9 +1066,9 @@ an_rxeof(struct an_softc *sc) len = an_rx_desc.an_len + 12; if (len > MCLBYTES) { m_freem(m); - printf("an%d: oversized packet " + if_printf(ifp, "oversized packet " "received (%d, %d)\n", - sc->an_unit, len, MCLBYTES); + len, MCLBYTES); ifp->if_ierrors++; return; } @@ -1116,9 +1109,8 @@ an_rxeof(struct an_softc *sc) ((u_int32_t *)(void *)&an_rx_desc)[i]); } else { - printf("an%d: Didn't get valid RX packet " + if_printf(ifp, "Didn't get valid RX packet " "%x %x %d\n", - sc->an_unit, an_rx_desc.an_done, an_rx_desc.an_valid, an_rx_desc.an_len); } @@ -1135,7 +1127,7 @@ an_txeof(struct an_softc *sc, int status) AN_LOCK_ASSERT(sc); ifp = sc->an_ifp; - ifp->if_timer = 0; + sc->an_timer = 0; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (!sc->mpi350) { @@ -1188,6 +1180,8 @@ an_stats_update(void *xsc) sc = xsc; AN_LOCK_ASSERT(sc); ifp = sc->an_ifp; + if (sc->an_timer > 0 && --sc->an_timer == 0) + an_watchdog(sc); sc->an_status.an_type = AN_RID_STATUS; sc->an_status.an_len = sizeof(struct an_ltv_status); @@ -1233,10 +1227,8 @@ an_intr(void *xsc) ifp = sc->an_ifp; -#if !defined(__HAIKU__) /* Disable interrupts. */ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); -#endif status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)); CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350)); @@ -1281,7 +1273,7 @@ an_intr(void *xsc) CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - an_start(ifp); + an_start_locked(ifp); AN_UNLOCK(sc); @@ -1395,7 +1387,7 @@ an_reset(struct an_softc *sc) an_cmd(sc, AN_CMD_NOOP2, 0); if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) - printf("an%d: reset failed\n", sc->an_unit); + if_printf(sc->an_ifp, "reset failed\n"); an_cmd(sc, AN_CMD_DISABLE, 0); @@ -1412,6 +1404,7 @@ an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) struct an_card_rid_desc an_rid_desc; struct an_command cmd; struct an_reply reply; + struct ifnet *ifp; u_int16_t *ptr; u_int8_t *ptr2; int i, len; @@ -1420,16 +1413,17 @@ an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) if (ltv->an_len < 4 || ltv->an_type == 0) return(EINVAL); + ifp = sc->an_ifp; if (!sc->mpi350){ /* Tell the NIC to enter record read mode. */ if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { - printf("an%d: RID access failed\n", sc->an_unit); + if_printf(ifp, "RID access failed\n"); return(EIO); } /* Seek to the record. */ if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { - printf("an%d: seek to record failed\n", sc->an_unit); + if_printf(ifp, "seek to record failed\n"); return(EIO); } @@ -1441,8 +1435,8 @@ an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) */ len = CSR_READ_2(sc, AN_DATA1); if (len > (ltv->an_len - 2)) { - printf("an%d: record length mismatch -- expected %d, " - "got %d for Rid %x\n", sc->an_unit, + if_printf(ifp, "record length mismatch -- expected %d, " + "got %d for Rid %x\n", ltv->an_len - 2, len, ltv->an_type); len = ltv->an_len - 2; } else { @@ -1478,8 +1472,8 @@ an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) if (an_cmd_struct(sc, &cmd, &reply) || reply.an_status & AN_CMD_QUAL_MASK) { - printf("an%d: failed to read RID %x %x %x %x %x, %d\n", - sc->an_unit, ltv->an_type, + if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n", + ltv->an_type, reply.an_status, reply.an_resp0, reply.an_resp1, @@ -1495,8 +1489,8 @@ an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) len = an_rid_desc.an_len; if (len > (ltv->an_len - 2)) { - printf("an%d: record length mismatch -- expected %d, " - "got %d for Rid %x\n", sc->an_unit, + if_printf(ifp, "record length mismatch -- expected %d, " + "got %d for Rid %x\n", ltv->an_len - 2, len, ltv->an_type); len = ltv->an_len - 2; } else { @@ -1588,8 +1582,9 @@ an_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) DELAY(100000); if ((i = an_cmd_struct(sc, &cmd, &reply))) { - printf("an%d: failed to write RID 1 %x %x %x %x %x, %d\n", - sc->an_unit, ltv->an_type, + if_printf(sc->an_ifp, + "failed to write RID 1 %x %x %x %x %x, %d\n", + ltv->an_type, reply.an_status, reply.an_resp0, reply.an_resp1, @@ -1600,8 +1595,9 @@ an_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) if (reply.an_status & AN_CMD_QUAL_MASK) { - printf("an%d: failed to write RID 2 %x %x %x %x %x, %d\n", - sc->an_unit, ltv->an_type, + if_printf(sc->an_ifp, + "failed to write RID 2 %x %x %x %x %x, %d\n", + ltv->an_type, reply.an_status, reply.an_resp0, reply.an_resp1, @@ -1625,11 +1621,11 @@ an_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string) char buf[17], temp; len = ltv->an_len - 4; - printf("an%d: RID %4x, Length %4d, Mode %s\n", - sc->an_unit, ltv->an_type, ltv->an_len - 4, string); + if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n", + ltv->an_type, ltv->an_len - 4, string); if (an_dump == 1 || (an_dump == ltv->an_type)) { - printf("an%d:\t", sc->an_unit); + if_printf(sc->an_ifp, "\t"); bzero(buf,sizeof(buf)); ptr2 = (u_int8_t *)<v->an_val; @@ -1644,7 +1640,7 @@ an_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string) if (++count == 16) { count = 0; printf("%s\n",buf); - printf("an%d:\t", sc->an_unit); + if_printf(sc->an_ifp, "\t"); bzero(buf,sizeof(buf)); } } @@ -1671,7 +1667,7 @@ an_seek(struct an_softc *sc, int id, int off, int chan) offreg = AN_OFF1; break; default: - printf("an%d: invalid data path: %x\n", sc->an_unit, chan); + if_printf(sc->an_ifp, "invalid data path: %x\n", chan); return(EIO); } @@ -1745,8 +1741,8 @@ an_alloc_nicmem(struct an_softc *sc, int len, int *id) int i; if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { - printf("an%d: failed to allocate %d bytes on NIC\n", - sc->an_unit, len); + if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n", + len); return(ENOMEM); } @@ -1828,9 +1824,7 @@ an_setdef(struct an_softc *sc, struct an_req *areq) case AN_RID_WEP_PERM: case AN_RID_LEAPUSERNAME: case AN_RID_LEAPPASSWORD: - AN_UNLOCK(sc); - an_init(sc); - AN_LOCK(sc); + an_init_locked(sc); /* Disable the MAC. */ an_cmd(sc, AN_CMD_DISABLE, 0); @@ -1865,17 +1859,14 @@ an_setdef(struct an_softc *sc, struct an_req *areq) } break; default: - printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type); + if_printf(ifp, "unknown RID: %x\n", areq->an_type); return; } /* Reinitialize the card. */ - if (ifp->if_flags) { - AN_UNLOCK(sc); - an_init(sc); - AN_LOCK(sc); - } + if (ifp->if_flags) + an_init_locked(sc); return; } @@ -1893,11 +1884,8 @@ an_promisc(struct an_softc *sc, int promisc) if (sc->mpi350) an_init_mpi350_desc(sc); } - if (sc->an_monitor || sc->an_was_monitor) { - AN_UNLOCK(sc); - an_init(sc); - AN_LOCK(sc); - } + if (sc->an_monitor || sc->an_was_monitor) + an_init_locked(sc); sc->an_was_monitor = sc->an_monitor; an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); @@ -1951,20 +1939,14 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) !(ifp->if_flags & IFF_PROMISC) && sc->an_if_flags & IFF_PROMISC) { an_promisc(sc, 0); - } else { - AN_UNLOCK(sc); - an_init(sc); - AN_LOCK(sc); - } + } else + an_init_locked(sc); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - AN_UNLOCK(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) an_stop(sc); - AN_LOCK(sc); - } } - AN_UNLOCK(sc); sc->an_if_flags = ifp->if_flags; + AN_UNLOCK(sc); error = 0; break; case SIOCSIFMEDIA: @@ -2488,7 +2470,6 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) AN_UNLOCK(sc); break; } - AN_UNLOCK(sc); if (ireq->i_val == 4) { config->an_home_product |= AN_HOME_NETWORK; ireq->i_val = 0; @@ -2500,10 +2481,9 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) = config->an_home_product; /* update configuration */ - an_init(sc); + an_init_locked(sc); bzero(&sc->areq, sizeof(struct an_ltv_key)); - AN_LOCK(sc); sc->areq.an_len = sizeof(struct an_ltv_key); sc->areq.an_type = AN_RID_WEP_PERM; key->kindex = 0xffff; @@ -2586,6 +2566,9 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) an_setdef(sc, &sc->areq); AN_UNLOCK(sc); break; + default: + AN_UNLOCK(sc); + break; } /* @@ -2635,14 +2618,21 @@ static void an_init(void *xsc) { struct an_softc *sc = xsc; - struct ifnet *ifp = sc->an_ifp; AN_LOCK(sc); + an_init_locked(sc); + AN_UNLOCK(sc); +} - if (sc->an_gone) { - AN_UNLOCK(sc); +static void +an_init_locked(struct an_softc *sc) +{ + struct ifnet *ifp; + + AN_LOCK_ASSERT(sc); + ifp = sc->an_ifp; + if (sc->an_gone) return; - } if (ifp->if_drv_flags & IFF_DRV_RUNNING) an_stop(sc); @@ -2655,9 +2645,7 @@ an_init(void *xsc) if (sc->mpi350) an_init_mpi350_desc(sc); if (an_init_tx_ring(sc)) { - printf("an%d: tx buffer allocation " - "failed\n", sc->an_unit); - AN_UNLOCK(sc); + if_printf(ifp, "tx buffer allocation failed\n"); return; } } @@ -2697,8 +2685,7 @@ an_init(void *xsc) sc->an_ssidlist.an_type = AN_RID_SSIDLIST; sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { - printf("an%d: failed to set ssid list\n", sc->an_unit); - AN_UNLOCK(sc); + if_printf(ifp, "failed to set ssid list\n"); return; } @@ -2706,8 +2693,7 @@ an_init(void *xsc) sc->an_aplist.an_type = AN_RID_APLIST; sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { - printf("an%d: failed to set AP list\n", sc->an_unit); - AN_UNLOCK(sc); + if_printf(ifp, "failed to set AP list\n"); return; } @@ -2715,15 +2701,13 @@ an_init(void *xsc) sc->an_config.an_len = sizeof(struct an_ltv_genconfig); sc->an_config.an_type = AN_RID_GENCONFIG; if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { - printf("an%d: failed to set configuration\n", sc->an_unit); - AN_UNLOCK(sc); + if_printf(ifp, "failed to set configuration\n"); return; } /* Enable the MAC */ if (an_cmd(sc, AN_CMD_ENABLE, 0)) { - printf("an%d: failed to enable MAC\n", sc->an_unit); - AN_UNLOCK(sc); + if_printf(ifp, "failed to enable MAC\n"); return; } @@ -2737,13 +2721,23 @@ an_init(void *xsc) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); - AN_UNLOCK(sc); return; } static void an_start(struct ifnet *ifp) +{ + struct an_softc *sc; + + sc = ifp->if_softc; + AN_LOCK(sc); + an_start_locked(ifp); + AN_UNLOCK(sc); +} + +static void +an_start_locked(struct ifnet *ifp) { struct an_softc *sc; struct mbuf *m0 = NULL; @@ -2756,6 +2750,7 @@ an_start(struct ifnet *ifp) sc = ifp->if_softc; + AN_LOCK_ASSERT(sc); if (sc->an_gone) return; @@ -2778,7 +2773,6 @@ an_start(struct ifnet *ifp) idx = sc->an_rdata.an_tx_prod; - AN_LOCK(sc); if (!sc->mpi350) { bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); @@ -2805,7 +2799,7 @@ an_start(struct ifnet *ifp) tx_frame_802_3.an_tx_802_3_payload_len, (caddr_t)&sc->an_txbuf); - txcontrol = AN_TXCTL_8023; + txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350); /* write the txcontrol only */ an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, sizeof(txcontrol)); @@ -2829,14 +2823,14 @@ an_start(struct ifnet *ifp) sc->an_rdata.an_tx_ring[idx] = id; if (an_cmd(sc, AN_CMD_TX, id)) - printf("an%d: xmit failed\n", sc->an_unit); + if_printf(ifp, "xmit failed\n"); AN_INC(idx, AN_TX_RING_CNT); /* * Set a timeout in case the chip goes out to lunch. */ - ifp->if_timer = 5; + sc->an_timer = 5; } } else { /* MPI-350 */ /* Disable interrupts. */ @@ -2868,7 +2862,7 @@ an_start(struct ifnet *ifp) tx_frame_802_3.an_tx_802_3_payload_len, (caddr_t)&sc->an_txbuf); - txcontrol = AN_TXCTL_8023; + txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350); /* write the txcontrol only */ bcopy((caddr_t)&txcontrol, &buf[0x08], sizeof(txcontrol)); @@ -2890,7 +2884,7 @@ an_start(struct ifnet *ifp) tx_frame_802_3.an_tx_802_3_payload_len; an_tx_desc.an_phys = sc->an_tx_buffer[idx].an_dma_paddr; - for (i = 0; i < sizeof(an_tx_desc) / 4 ; i++) { + for (i = sizeof(an_tx_desc) / 4 - 1; i >= 0; i--) { CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET /* zero for now */ + (0 * sizeof(an_tx_desc)) @@ -2913,13 +2907,12 @@ an_start(struct ifnet *ifp) /* * Set a timeout in case the chip goes out to lunch. */ - ifp->if_timer = 5; + sc->an_timer = 5; } /* Re-enable interrupts. */ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); } - AN_UNLOCK(sc); if (m0 != NULL) ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -2935,12 +2928,10 @@ an_stop(struct an_softc *sc) struct ifnet *ifp; int i; - AN_LOCK(sc); + AN_LOCK_ASSERT(sc); - if (sc->an_gone) { - AN_UNLOCK(sc); + if (sc->an_gone) return; - } ifp = sc->an_ifp; @@ -2959,36 +2950,27 @@ an_stop(struct an_softc *sc) free(sc->an_flash_buffer, M_DEVBUF); sc->an_flash_buffer = NULL; } - - AN_UNLOCK(sc); - - return; } static void -an_watchdog(struct ifnet *ifp) +an_watchdog(struct an_softc *sc) { - struct an_softc *sc; + struct ifnet *ifp; - sc = ifp->if_softc; - AN_LOCK(sc); + AN_LOCK_ASSERT(sc); - if (sc->an_gone) { - AN_UNLOCK(sc); + if (sc->an_gone) return; - } - printf("an%d: device timeout\n", sc->an_unit); + ifp = sc->an_ifp; + if_printf(ifp, "device timeout\n"); an_reset(sc); if (sc->mpi350) an_init_mpi350_desc(sc); - AN_UNLOCK(sc); - an_init(sc); + an_init_locked(sc); ifp->if_oerrors++; - - return; } int @@ -2997,10 +2979,12 @@ an_shutdown(device_t dev) struct an_softc *sc; sc = device_get_softc(dev); + AN_LOCK(sc); an_stop(sc); sc->an_gone = 1; + AN_UNLOCK(sc); - return 0; + return (0); } void @@ -3018,7 +3002,7 @@ an_resume(device_t dev) an_reset(sc); if (sc->mpi350) an_init_mpi350_desc(sc); - an_init(sc); + an_init_locked(sc); /* Recovery temporary keys */ for (i = 0; i < 4; i++) { @@ -3030,7 +3014,7 @@ an_resume(device_t dev) } if (ifp->if_flags & IFF_UP) - an_start(ifp); + an_start_locked(ifp); AN_UNLOCK(sc); return; @@ -3129,7 +3113,7 @@ an_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m, } #ifdef SIGDEBUG - printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n", + if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n", rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff); #endif @@ -3255,12 +3239,12 @@ an_media_change(struct ifnet *ifp) int otype = sc->an_config.an_opmode; int orate = sc->an_tx_rate; + AN_LOCK(sc); sc->an_tx_rate = ieee80211_media2rate( IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)); if (sc->an_tx_rate < 0) sc->an_tx_rate = 0; - AN_LOCK(sc); if (orate != sc->an_tx_rate) { /* Read the current configuration */ sc->an_config.an_type = AN_RID_GENCONFIG; @@ -3281,11 +3265,11 @@ an_media_change(struct ifnet *ifp) sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION; else sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION; - AN_UNLOCK(sc); if (otype != sc->an_config.an_opmode || orate != sc->an_tx_rate) - an_init(sc); + an_init_locked(sc); + AN_UNLOCK(sc); return(0); } @@ -3306,7 +3290,6 @@ an_media_status(struct ifnet *ifp, struct ifmediareq *imr) imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; imr->ifm_status = IFM_AVALID|IFM_ACTIVE; } - AN_UNLOCK(sc); if (sc->an_tx_rate == 0) { imr->ifm_active = IFM_IEEE80211|IFM_AUTO; @@ -3319,6 +3302,7 @@ an_media_status(struct ifnet *ifp, struct ifmediareq *imr) imr->ifm_status = IFM_AVALID; if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) imr->ifm_status |= IFM_ACTIVE; + AN_UNLOCK(sc); } /********************** Cisco utility support routines *************/ @@ -3563,14 +3547,13 @@ cmdreset(struct ifnet *ifp) int status; struct an_softc *sc = ifp->if_softc; + AN_LOCK(sc); an_stop(sc); - AN_LOCK(sc); an_cmd(sc, AN_CMD_DISABLE, 0); if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { - printf("an%d: Waitbusy hang b4 RESET =%d\n", - sc->an_unit, status); + if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status); AN_UNLOCK(sc); return -EBUSY; } @@ -3580,8 +3563,7 @@ cmdreset(struct ifnet *ifp) if (!(status = WaitBusy(ifp, 100))) { - printf("an%d: Waitbusy hang AFTER RESET =%d\n", - sc->an_unit, status); + if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status); AN_UNLOCK(sc); return -EBUSY; } @@ -3689,8 +3671,7 @@ flashpchar(struct ifnet *ifp, int byte, int dwelltime) /* timeout for busy clear wait */ if (waittime <= 0) { - printf("an%d: flash putchar busywait timeout! \n", - sc->an_unit); + if_printf(ifp, "flash putchar busywait timeout!\n"); return -1; } /* @@ -3756,9 +3737,7 @@ flashrestart(struct ifnet *ifp) FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ - AN_UNLOCK(sc); - an_init(sc); - AN_LOCK(sc); + an_init_locked(sc); FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ return status; @@ -3776,8 +3755,7 @@ flashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) sc = ifp->if_softc; if (sc->mpi350) { - printf("an%d: flashing not supported on MPI 350 yet\n", - sc->an_unit); + if_printf(ifp, "flashing not supported on MPI 350 yet\n"); return(-1); } status = l_ioctl->command; @@ -3822,7 +3800,7 @@ flashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) break; case AIROFLPUTBUF: /* Send 32k to card */ if (l_ioctl->len > FLASH_SIZE) { - printf("an%d: Buffer to big, %x %x\n", sc->an_unit, + if_printf(ifp, "Buffer to big, %x %x\n", l_ioctl->len, FLASH_SIZE); return -EINVAL; } @@ -3839,8 +3817,7 @@ flashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) break; case AIRORESTART: if ((status = flashrestart(ifp)) != 0) { - printf("an%d: FLASHRESTART returned %d\n", - sc->an_unit, status); + if_printf(ifp, "FLASHRESTART returned %d\n", status); return -EIO; } else return 0; diff --git a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_isa.c b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_isa.c index 80933b18ad..19e5cd0755 100644 --- a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_isa.c +++ b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_isa.c @@ -111,11 +111,9 @@ an_attach_isa(device_t dev) an_alloc_port(dev, sc->port_rid, 1); an_alloc_irq(dev, sc->irq_rid, 0); - sc->an_bhandle = rman_get_bushandle(sc->port_res); - sc->an_btag = rman_get_bustag(sc->port_res); sc->an_dev = dev; - error = an_attach(sc, device_get_unit(dev), flags); + error = an_attach(sc, flags); if (error) { an_release_resources(dev); return (error); diff --git a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pccard.c b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pccard.c index b475265d84..bdd40f3dfe 100644 --- a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pccard.c +++ b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pccard.c @@ -141,11 +141,9 @@ an_pccard_attach(device_t dev) an_alloc_irq(dev, sc->irq_rid, 0); - sc->an_bhandle = rman_get_bushandle(sc->port_res); - sc->an_btag = rman_get_bustag(sc->port_res); sc->an_dev = dev; - error = an_attach(sc, device_get_unit(dev), flags); + error = an_attach(sc, flags); if (error) goto fail; diff --git a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pci.c b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pci.c index d13e3ab597..2d0d2b5a66 100644 --- a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pci.c +++ b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_an_pci.c @@ -103,6 +103,7 @@ struct an_type { static struct an_type an_devs[] = { { AIRONET_VENDORID, AIRONET_DEVICEID_35x, "Cisco Aironet 350 Series" }, + { AIRONET_VENDORID, AIRONET_DEVICEID_MPI350, "Cisco Aironet MPI350" }, { AIRONET_VENDORID, AIRONET_DEVICEID_4500, "Aironet PCI4500" }, { AIRONET_VENDORID, AIRONET_DEVICEID_4800, "Aironet PCI4800" }, { AIRONET_VENDORID, AIRONET_DEVICEID_4xxx, "Aironet PCI4500/PCI4800" }, @@ -133,13 +134,6 @@ an_probe_pci(device_t dev) t++; } - if (pci_get_vendor(dev) == AIRONET_VENDORID && - pci_get_device(dev) == AIRONET_DEVICEID_MPI350) { - device_set_desc(dev, "Cisco Aironet MPI350"); - an_pci_probe(dev); - return(BUS_PROBE_DEFAULT); - } - return(ENXIO); } @@ -149,10 +143,9 @@ an_attach_pci(dev) { u_int32_t command; struct an_softc *sc; - int unit, flags, error = 0; + int flags, error = 0; sc = device_get_softc(dev); - unit = device_get_unit(dev); flags = device_get_flags(dev); if (pci_get_vendor(dev) == AIRONET_VENDORID && @@ -169,7 +162,7 @@ an_attach_pci(dev) command = pci_read_config(dev, PCIR_COMMAND, 4); if (!(command & PCIM_CMD_PORTEN)) { - printf("an%d: failed to enable I/O ports!\n", unit); + device_printf(dev, "failed to enable I/O ports!\n"); error = ENXIO; goto fail; } @@ -178,35 +171,28 @@ an_attach_pci(dev) error = an_alloc_port(dev, sc->port_rid, 1); if (error) { - printf("an%d: couldn't map ports\n", unit); + device_printf(dev, "couldn't map ports\n"); goto fail; } - sc->an_btag = rman_get_bustag(sc->port_res); - sc->an_bhandle = rman_get_bushandle(sc->port_res); - /* Allocate memory for MPI350 */ if (sc->mpi350) { /* Allocate memory */ sc->mem_rid = PCIR_BAR(1); error = an_alloc_memory(dev, sc->mem_rid, 1); if (error) { - printf("an%d: couldn't map memory\n", unit); + device_printf(dev, "couldn't map memory\n"); goto fail; } - sc->an_mem_btag = rman_get_bustag(sc->mem_res); - sc->an_mem_bhandle = rman_get_bushandle(sc->mem_res); /* Allocate aux. memory */ sc->mem_aux_rid = PCIR_BAR(2); error = an_alloc_aux_memory(dev, sc->mem_aux_rid, AN_AUX_MEM_SIZE); if (error) { - printf("an%d: couldn't map aux memory\n", unit); + device_printf(dev, "couldn't map aux memory\n"); goto fail; } - sc->an_mem_aux_btag = rman_get_bustag(sc->mem_aux_res); - sc->an_mem_aux_bhandle = rman_get_bushandle(sc->mem_aux_res); /* Allocate DMA region */ error = bus_dma_tag_create(NULL, /* parent */ @@ -222,7 +208,7 @@ an_attach_pci(dev) NULL, /* lockarg */ &sc->an_dtag); if (error) { - printf("an%d: couldn't get DMA region\n", unit); + device_printf(dev, "couldn't get DMA region\n"); goto fail; } } @@ -230,12 +216,14 @@ an_attach_pci(dev) /* Allocate interrupt */ error = an_alloc_irq(dev, 0, RF_SHAREABLE); if (error) { + device_printf(dev, "couldn't get interrupt\n"); goto fail; } sc->an_dev = dev; - error = an_attach(sc, device_get_unit(dev), flags); + error = an_attach(sc, flags); if (error) { + device_printf(dev, "couldn't attach\n"); goto fail; } @@ -244,6 +232,8 @@ an_attach_pci(dev) */ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, NULL, an_intr, sc, &sc->irq_handle); + if (error) + device_printf(dev, "couldn't setup interrupt\n"); fail: if (error) diff --git a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_anreg.h b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_anreg.h index ec0ad2bc4a..279e65b8e1 100644 --- a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_anreg.h +++ b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/dev/an/if_anreg.h @@ -45,47 +45,39 @@ /* * register space access macros */ -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->an_btag, sc->an_bhandle, reg, val) +#define CSR_WRITE_2(sc, reg, val) bus_write_2(sc->port_res, reg, val) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->an_btag, sc->an_bhandle, reg) +#define CSR_READ_2(sc, reg) bus_read_2(sc->port_res, reg) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->an_btag, sc->an_bhandle, reg, val) +#define CSR_WRITE_1(sc, reg, val) bus_write_1(sc->port_res, reg, val) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->an_btag, sc->an_bhandle, reg) +#define CSR_READ_1(sc, reg) bus_read_1(sc->port_res, reg) /* * memory space access macros */ -#define CSR_MEM_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->an_mem_btag, sc->an_mem_bhandle, reg, val) +#define CSR_MEM_WRITE_2(sc, reg, val) bus_write_2(sc->mem_res, reg, val) -#define CSR_MEM_READ_2(sc, reg) \ - bus_space_read_2(sc->an_mem_btag, sc->an_mem_bhandle, reg) +#define CSR_MEM_READ_2(sc, reg) bus_read_2(sc->mem_res, reg) -#define CSR_MEM_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->an_mem_btag, sc->an_mem_bhandle, reg, val) +#define CSR_MEM_WRITE_1(sc, reg, val) bus_write_1(sc->mem_res, reg, val) -#define CSR_MEM_READ_1(sc, reg) \ - bus_space_read_1(sc->an_mem_btag, sc->an_mem_bhandle, reg) +#define CSR_MEM_READ_1(sc, reg) bus_read_1(sc->mem_res, reg) /* * aux. memory space access macros */ #define CSR_MEM_AUX_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg, val) + bus_write_4(sc->mem_aux_res, reg, val) #define CSR_MEM_AUX_READ_4(sc, reg) \ - bus_space_read_4(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg) + bus_read_4(sc->mem_aux_res, reg) #define CSR_MEM_AUX_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg, val) + bus_write_1(sc->mem_aux_res, reg, val) #define CSR_MEM_AUX_READ_1(sc, reg) \ - bus_space_read_1(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg) + bus_read_1(sc->mem_aux_res, reg) /* * Size of Aironet I/O space. @@ -394,13 +386,18 @@ struct an_txframe_802_3 { #define AN_PAYLOADTYPE_ETHER 0x0000 #define AN_PAYLOADTYPE_LLC 0x0010 -#define AN_TXCTL_80211 \ - (AN_TXCTL_TXOK_INTR|AN_TXCTL_TXERR_INTR|AN_HEADERTYPE_80211| \ - AN_PAYLOADTYPE_LLC|AN_TXCTL_NORELEASE) +#define AN_TXCTL_80211 (AN_HEADERTYPE_80211|AN_PAYLOADTYPE_LLC) -#define AN_TXCTL_8023 \ - (AN_TXCTL_TXOK_INTR|AN_TXCTL_TXERR_INTR|AN_HEADERTYPE_8023| \ - AN_PAYLOADTYPE_ETHER|AN_TXCTL_NORELEASE) +#define AN_TXCTL_8023 (AN_HEADERTYPE_8023|AN_PAYLOADTYPE_ETHER) + +/* + * Additions to transmit control bits for MPI350 + */ +#define AN_TXCTL_HW(x) \ + ( x ? (AN_TXCTL_NORELEASE) \ + : \ + (AN_TXCTL_TXOK_INTR|AN_TXCTL_TXERR_INTR|AN_TXCTL_NORELEASE) \ + ) #define AN_TXGAP_80211 0 #define AN_TXGAP_8023 0 @@ -442,8 +439,6 @@ struct an_tx_ring_data { struct an_softc { struct ifnet *an_ifp; - int an_unit; - int port_rid; /* resource id for port range */ struct resource* port_res; /* resource for port range */ int mem_rid; /* resource id for memory range */ @@ -456,11 +451,6 @@ struct an_softc { void* irq_handle; /* handle for irq handler */ struct resource* irq_res; /* resource for irq */ - bus_space_handle_t an_bhandle_p; - bus_space_handle_t an_bhandle; - bus_space_tag_t an_btag; - bus_space_handle_t an_mem_bhandle; - bus_space_tag_t an_mem_btag; bus_space_handle_t an_mem_aux_bhandle; bus_space_tag_t an_mem_aux_btag; bus_dma_tag_t an_dtag; @@ -491,6 +481,7 @@ struct an_softc { struct ifmedia an_ifmedia; int an_monitor; int an_was_monitor; + int an_timer; u_char buf_802_11[MCLBYTES]; struct an_req areq; unsigned short* an_flash_buffer; @@ -513,7 +504,7 @@ int an_pci_probe (device_t); int an_probe (device_t); int an_shutdown (device_t); void an_resume (device_t); -int an_attach (struct an_softc *, int, int); +int an_attach (struct an_softc *, int); int an_detach (device_t); void an_stop (struct an_softc *); diff --git a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/glue.c b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/glue.c index 1b6f594464..9acdafa949 100644 --- a/src/add-ons/kernel/drivers/network/wlan/aironetwifi/glue.c +++ b/src/add-ons/kernel/drivers/network/wlan/aironetwifi/glue.c @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwi.c b/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwi.c index 450605888f..f789ca0ba5 100644 --- a/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwi.c +++ b/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwi.c @@ -106,7 +106,7 @@ static void bwi_start(struct ifnet *); static void bwi_start_locked(struct ifnet *); static int bwi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void bwi_watchdog(struct ifnet *); +static void bwi_watchdog(void *); static void bwi_scan_start(struct ieee80211com *); static void bwi_set_channel(struct ieee80211com *); static void bwi_scan_end(struct ieee80211com *); @@ -461,10 +461,10 @@ bwi_attach(struct bwi_softc *sc) ifp->if_init = bwi_init; ifp->if_ioctl = bwi_ioctl; ifp->if_start = bwi_start; - ifp->if_watchdog = bwi_watchdog; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; IFQ_SET_READY(&ifp->if_snd); + callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); /* * Setup ratesets, phytype, channels and get MAC address @@ -537,11 +537,11 @@ bwi_attach(struct bwi_softc *sc) /* * Add sysctl nodes */ - SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fw_version", CTLFLAG_RD, &sc->sc_fw_version, 0, "Firmware version"); - SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "led_idle", CTLFLAG_RW, &sc->sc_led_idle, 0, "# ticks before LED enters idle state"); @@ -577,6 +577,7 @@ bwi_detach(struct bwi_softc *sc) bwi_stop(sc, 1); callout_drain(&sc->sc_led_blink_ch); callout_drain(&sc->sc_calib_ch); + callout_drain(&sc->sc_watchdog_timer); ieee80211_ifdetach(ic); for (i = 0; i < sc->sc_nmac; ++i) @@ -1288,6 +1289,7 @@ bwi_init_statechg(struct bwi_softc *sc, int statechg) sc->sc_flags &= ~BWI_F_STOP; ifp->if_drv_flags |= IFF_DRV_RUNNING; + callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); /* Enable intrs */ bwi_enable_intrs(sc, BWI_INIT_INTRS); @@ -1426,7 +1428,7 @@ bwi_start_locked(struct ifnet *ifp) tbd->tbd_idx = idx; if (trans) - ifp->if_timer = 5; + sc->sc_tx_timer = 5; } static int @@ -1467,7 +1469,7 @@ bwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if (++tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) ifp->if_drv_flags |= IFF_DRV_OACTIVE; tbd->tbd_idx = (idx + 1) % BWI_TX_NDESC; - ifp->if_timer = 5; + sc->sc_tx_timer = 5; } else { /* NB: m is reclaimed on encap failure */ ieee80211_free_node(ni); @@ -1478,17 +1480,20 @@ bwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, } static void -bwi_watchdog(struct ifnet *ifp) +bwi_watchdog(void *arg) { - struct bwi_softc *sc = ifp->if_softc; + struct bwi_softc *sc; + struct ifnet *ifp; - BWI_LOCK(sc); - if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { + sc = arg; + ifp = sc->sc_ifp; + BWI_ASSERT_LOCKED(sc); + if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) { if_printf(ifp, "watchdog timeout\n"); ifp->if_oerrors++; taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); } - BWI_UNLOCK(sc); + callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); } static void @@ -1544,7 +1549,7 @@ bwi_stop_locked(struct bwi_softc *sc, int statechg) bwi_bbp_power_off(sc); sc->sc_tx_timer = 0; - ifp->if_timer = 0; + callout_stop(&sc->sc_watchdog_timer); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } @@ -3397,7 +3402,7 @@ _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) tb->tb_mbuf = NULL; if (tbd->tbd_used == 0) - ifp->if_timer = 0; + sc->sc_tx_timer = 0; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } @@ -3899,7 +3904,7 @@ bwi_led_attach(struct bwi_softc *sc) "%dth led, act %d, lowact %d\n", i, led->l_act, led->l_flags & BWI_LED_F_ACTLOW); } - callout_init(&sc->sc_led_blink_ch, CALLOUT_MPSAFE); + callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0); } static __inline uint16_t diff --git a/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwivar.h b/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwivar.h index e89ec1a020..bb35623a15 100644 --- a/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwivar.h +++ b/src/add-ons/kernel/drivers/network/wlan/broadcom43xx/dev/bwi/if_bwivar.h @@ -571,6 +571,7 @@ struct bwi_softc { bus_space_handle_t sc_mem_bh; struct callout sc_calib_ch; + struct callout sc_watchdog_timer; struct bwi_regwin *sc_cur_regwin; struct bwi_regwin sc_com_regwin; diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipw.c b/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipw.c index 60b440ace8..0a576ab064 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipw.c +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipw.c @@ -199,6 +199,8 @@ static devclass_t ipw_devclass; DRIVER_MODULE(ipw, pci, ipw_driver, ipw_devclass, 0, 0); +MODULE_VERSION(ipw, 1); + static int ipw_probe(device_t dev) { @@ -289,8 +291,8 @@ ipw_attach(device_t dev) ifp->if_init = ipw_init; ifp->if_ioctl = ipw_ioctl; ifp->if_start = ipw_start; - IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); - ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; IFQ_SET_READY(&ifp->if_snd); ic->ic_ifp = ifp; @@ -888,10 +890,10 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) /* * XXX when joining an ibss network we are called * with a SCAN -> RUN transition on scan complete. - * Use that to call ipw_auth_and_assoc. On completing - * the join we are then called again with an - * AUTH -> RUN transition and we want to do nothing. - * This is all totally bogus and needs to be redone. + * Use that to call ipw_assoc. On completing the + * join we are then called again with an AUTH -> RUN + * transition and we want to do nothing. This is + * all totally bogus and needs to be redone. */ if (ostate == IEEE80211_S_SCAN) ipw_assoc(ic, vap); @@ -904,12 +906,19 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) break; case IEEE80211_S_AUTH: + /* + * Move to ASSOC state after the ipw_assoc() call. Firmware + * takes care of authentication, after the call we'll receive + * only an assoc response which would otherwise be discared + * if we are still in AUTH state. + */ + nstate = IEEE80211_S_ASSOC; ipw_assoc(ic, vap); break; case IEEE80211_S_ASSOC: /* - * If we are not transitioning from AUTH the resend the + * If we are not transitioning from AUTH then resend the * association request. */ if (ostate != IEEE80211_S_AUTH) @@ -1021,7 +1030,6 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) } sc->flags &= ~IPW_FLAG_ASSOCIATING; sc->flags |= IPW_FLAG_ASSOCIATED; - ieee80211_new_state(vap, IEEE80211_S_RUN, -1); break; case IPW_STATE_SCANNING: @@ -1034,8 +1042,10 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) * we checked the 802.11 layer state. */ if (sc->flags & IPW_FLAG_ASSOCIATED) { + IPW_UNLOCK(sc); /* XXX probably need to issue disassoc to fw */ ieee80211_beacon_miss(ic); + IPW_LOCK(sc); } break; @@ -1054,7 +1064,9 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) break; } if (sc->flags & IPW_FLAG_SCANNING) { + IPW_UNLOCK(sc); ieee80211_scan_done(vap); + IPW_LOCK(sc); sc->flags &= ~IPW_FLAG_SCANNING; sc->sc_scan_timer = 0; } @@ -1064,8 +1076,11 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) DPRINTFN(2, ("Association lost (%s flags 0x%x)\n", IEEESTATE(vap), sc->flags)); sc->flags &= ~(IPW_FLAG_ASSOCIATING | IPW_FLAG_ASSOCIATED); - if (vap->iv_state == IEEE80211_S_RUN) + if (vap->iv_state == IEEE80211_S_RUN) { + IPW_UNLOCK(sc); ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); + IPW_LOCK(sc); + } break; case IPW_STATE_DISABLED: @@ -1164,7 +1179,6 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, bus_addr_t physaddr; int error; int8_t rssi, nf; - IPW_LOCK_DECL; DPRINTFN(5, ("received frame len=%u, rssi=%u\n", le32toh(status->len), status->rssi)); @@ -1234,10 +1248,10 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status, IPW_UNLOCK(sc); ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { - (void) ieee80211_input(ni, m, rssi, nf); + (void) ieee80211_input(ni, m, rssi - nf, nf); ieee80211_free_node(ni); } else - (void) ieee80211_input_all(ic, m, rssi, nf); + (void) ieee80211_input_all(ic, m, rssi - nf, nf); IPW_LOCK(sc); bus_dmamap_sync(sc->rbd_dmat, sc->rbd_map, BUS_DMASYNC_PREWRITE); @@ -1378,8 +1392,11 @@ ipw_fatal_error_intr(struct ipw_softc *sc) struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); device_printf(sc->sc_dev, "firmware error\n"); - if (vap != NULL) + if (vap != NULL) { + IPW_UNLOCK(sc); ieee80211_cancel_scan(vap); + IPW_LOCK(sc); + } ieee80211_runtask(ic, &sc->sc_init_task); } @@ -1388,7 +1405,6 @@ ipw_intr(void *arg) { struct ipw_softc *sc = arg; uint32_t r; - IPW_LOCK_DECL; IPW_LOCK(sc); @@ -1728,7 +1744,6 @@ static void ipw_start(struct ifnet *ifp) { struct ipw_softc *sc = ifp->if_softc; - IPW_LOCK_DECL; IPW_LOCK(sc); ipw_start_locked(ifp); @@ -1785,7 +1800,9 @@ ipw_watchdog(void *arg) DPRINTFN(3, ("Scan timeout\n")); /* End the scan */ if (sc->flags & IPW_FLAG_SCANNING) { + IPW_UNLOCK(sc); ieee80211_scan_done(TAILQ_FIRST(&ic->ic_vaps)); + IPW_LOCK(sc); sc->flags &= ~IPW_FLAG_SCANNING; } } @@ -1801,7 +1818,6 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ieee80211com *ic = ifp->if_l2com; struct ifreq *ifr = (struct ifreq *) data; int error = 0, startall = 0; - IPW_LOCK_DECL; switch (cmd) { case SIOCSIFFLAGS: @@ -2211,7 +2227,6 @@ ipw_assoc(struct ieee80211com *ic, struct ieee80211vap *vap) struct ipw_security security; uint32_t data; int error; - IPW_LOCK_DECL; IPW_LOCK(sc); error = ipw_disable(sc); @@ -2270,8 +2285,8 @@ ipw_assoc(struct ieee80211com *ic, struct ieee80211vap *vap) if (error != 0) goto done; - if (vap->iv_appie_assocreq != NULL) { - struct ieee80211_appie *ie = vap->iv_appie_assocreq; + if (vap->iv_appie_wpa != NULL) { + struct ieee80211_appie *ie = vap->iv_appie_wpa; error = ipw_setwpaie(sc, ie->ie_data, ie->ie_len); if (error != 0) goto done; @@ -2301,7 +2316,6 @@ ipw_disassoc(struct ieee80211com *ic, struct ieee80211vap *vap) struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ieee80211_node *ni = vap->iv_bss; struct ipw_softc *sc = ifp->if_softc; - IPW_LOCK_DECL; IPW_LOCK(sc); DPRINTF(("Disassociate from %6D\n", ni->ni_bssid, ":")); @@ -2337,7 +2351,6 @@ ipw_init(void *priv) struct ipw_softc *sc = priv; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - IPW_LOCK_DECL; IPW_LOCK(sc); ipw_init_locked(sc); @@ -2504,19 +2517,19 @@ ipw_config(struct ipw_softc *sc) if (error != 0) return error; - data = htole32(0x3); /* 1, 2 */ + data = htole32(0xf); /* 1, 2, 5.5, 11 */ DPRINTF(("Setting basic tx rates to 0x%x\n", le32toh(data))); error = ipw_cmd(sc, IPW_CMD_SET_BASIC_TX_RATES, &data, sizeof data); if (error != 0) return error; - /* NB: use the same rate set */ + /* Use the same rate set */ DPRINTF(("Setting msdu tx rates to 0x%x\n", le32toh(data))); error = ipw_cmd(sc, IPW_CMD_SET_MSDU_TX_RATES, &data, sizeof data); if (error != 0) return error; - data = htole32(0xf); /* 1, 2, 5.5, 11 */ + /* Use the same rate set */ DPRINTF(("Setting tx rates to 0x%x\n", le32toh(data))); error = ipw_cmd(sc, IPW_CMD_SET_TX_RATES, &data, sizeof data); if (error != 0) @@ -2544,7 +2557,6 @@ static void ipw_stop(void *priv) { struct ipw_softc *sc = priv; - IPW_LOCK_DECL; IPW_LOCK(sc); ipw_stop_locked(sc); @@ -2671,7 +2683,6 @@ ipw_scan_start(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ipw_softc *sc = ifp->if_softc; - IPW_LOCK_DECL; IPW_LOCK(sc); ipw_scan(sc); @@ -2683,7 +2694,6 @@ ipw_set_channel(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ipw_softc *sc = ifp->if_softc; - IPW_LOCK_DECL; IPW_LOCK(sc); if (ic->ic_opmode == IEEE80211_M_MONITOR) { @@ -2711,7 +2721,6 @@ ipw_scan_end(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ipw_softc *sc = ifp->if_softc; - IPW_LOCK_DECL; IPW_LOCK(sc); sc->flags &= ~IPW_FLAG_SCANNING; diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipwvar.h b/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipwvar.h index 69c8de9346..6be3cbc1be 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipwvar.h +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi2100/dev/ipw/if_ipwvar.h @@ -168,13 +168,6 @@ struct ipw_softc { * NB.: This models the only instance of async locking in ipw_init_locked * and must be kept in sync. */ -#define IPW_LOCK_DECL int __waslocked = 0 -#define IPW_LOCK(sc) do { \ - if (!(__waslocked = mtx_owned(&(sc)->sc_mtx))) \ - mtx_lock(&sc->sc_mtx); \ -} while (0) -#define IPW_UNLOCK(sc) do { \ - if (!__waslocked) \ - mtx_unlock(&sc->sc_mtx); \ -} while (0) +#define IPW_LOCK(sc) mtx_lock(&sc->sc_mtx); +#define IPW_UNLOCK(sc) mtx_unlock(&sc->sc_mtx); #define IPW_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi2200/dev/iwi/if_iwi.c b/src/add-ons/kernel/drivers/network/wlan/iprowifi2200/dev/iwi/if_iwi.c index f9ed03b481..a826750c2d 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi2200/dev/iwi/if_iwi.c +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi2200/dev/iwi/if_iwi.c @@ -232,6 +232,8 @@ static devclass_t iwi_devclass; DRIVER_MODULE(iwi, pci, iwi_driver, iwi_devclass, 0, 0); +MODULE_VERSION(iwi, 1); + static __inline uint8_t MEM_READ_1(struct iwi_softc *sc, uint32_t addr) { @@ -397,11 +399,11 @@ iwi_attach(device_t dev) val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2); macaddr[4] = val & 0xff; macaddr[5] = val >> 8; - + bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); - if (pci_get_device(dev) >= 0x4223) + if (pci_get_device(dev) >= 0x4223) setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); @@ -570,7 +572,7 @@ iwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring, int count) error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - count * IWI_CMD_DESC_SIZE, 1, count * IWI_CMD_DESC_SIZE, 0, + count * IWI_CMD_DESC_SIZE, 1, count * IWI_CMD_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create desc DMA tag\n"); @@ -615,7 +617,7 @@ iwi_free_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) } if (ring->desc_dmat != NULL) - bus_dma_tag_destroy(ring->desc_dmat); + bus_dma_tag_destroy(ring->desc_dmat); } static int @@ -632,7 +634,7 @@ iwi_alloc_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring, int count, error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - count * IWI_TX_DESC_SIZE, 1, count * IWI_TX_DESC_SIZE, 0, NULL, + count * IWI_TX_DESC_SIZE, 1, count * IWI_TX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create desc DMA tag\n"); @@ -911,7 +913,7 @@ iwi_node_free(struct ieee80211_node *ni) sc->sc_node_free(ni); } -/* +/* * Convert h/w rate code to IEEE rate code. */ static int @@ -2937,7 +2939,7 @@ iwi_auth_and_assoc(struct iwi_softc *sc, struct ieee80211vap *vap) * key setup. This typically is due to a user app bug * but if we blindly grab the key the firmware will * barf so avoid it for now. - */ + */ if (vap->iv_def_txkey != IEEE80211_KEYIX_NONE) assoc->auth |= vap->iv_def_txkey << 4; @@ -3519,14 +3521,14 @@ iwi_ledattach(struct iwi_softc *sc) SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "softled", CTLTYPE_INT | CTLFLAG_RW, sc, 0, iwi_sysctl_softled, "I", "enable/disable software LED support"); - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "ledpin", CTLFLAG_RW, &sc->sc_ledpin, 0, "pin setting to turn activity LED on"); - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0, "idle time for inactivity LED (ticks)"); /* XXX for debugging */ - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "nictype", CTLFLAG_RD, &sc->sc_nictype, 0, "NIC type from EEPROM"); diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi3945/dev/wpi/if_wpi.c b/src/add-ons/kernel/drivers/network/wlan/iprowifi3945/dev/wpi/if_wpi.c index 7d8721a92f..62f44d1362 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi3945/dev/wpi/if_wpi.c +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi3945/dev/wpi/if_wpi.c @@ -29,7 +29,7 @@ __FBSDID("$FreeBSD$"); * state and told to load boot firmware. The boot firmware loads an init and a * main binary firmware image into SRAM on the card via DMA. * Once the firmware is loaded, the driver/hw then - * communicate by way of circular dma rings via the the SRAM to the firmware. + * communicate by way of circular dma rings via the SRAM to the firmware. * * There is 6 memory rings. 1 command ring, 1 rx data ring & 4 tx data rings. * The 4 tx data rings allow for prioritization QoS. @@ -181,7 +181,7 @@ static uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); static void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); static void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, const uint32_t *, int); -static int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); +static uint16_t wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); static int wpi_alloc_fwmem(struct wpi_softc *); static void wpi_free_fwmem(struct wpi_softc *); static int wpi_load_firmware(struct wpi_softc *); @@ -273,6 +273,8 @@ static devclass_t wpi_devclass; DRIVER_MODULE(wpi, pci, wpi_driver, wpi_devclass, 0, 0); +MODULE_VERSION(wpi, 1); + static const uint8_t wpi_ridx_to_plcp[] = { /* OFDM: IEEE Std 802.11a-1999, pp. 14 Table 80 */ /* R1-R4 (ral/ural is R4-R1) */ @@ -488,7 +490,7 @@ wpi_attach(device_t dev) struct wpi_softc *sc = device_get_softc(dev); struct ifnet *ifp; struct ieee80211com *ic; - int ac, error, result, supportsa = 1; + int ac, error, supportsa = 1; uint32_t tmp; const struct wpi_ident *ident; uint8_t macaddr[IEEE80211_ADDR_LEN]; @@ -545,9 +547,6 @@ wpi_attach(device_t dev) sc->sc_sh = rman_get_bushandle(sc->mem); sc->irq_rid = 0; - if ((result = pci_msi_count(dev)) == 1 && - pci_alloc_msi(dev, &result) == 0) - sc->irq_rid = 1; sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq == NULL) { @@ -747,8 +746,6 @@ wpi_detach(device_t dev) if (sc->irq != NULL) { bus_teardown_intr(dev, sc->irq, sc->sc_ih); bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); - if (sc->irq_rid == 1) - pci_release_msi(dev); } if (sc->mem != NULL) @@ -964,7 +961,7 @@ wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) goto fail; } - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MJUMPAGESIZE, 1, MJUMPAGESIZE, BUS_DMA_NOWAIT, NULL, NULL, &ring->data_dmat); @@ -1009,7 +1006,7 @@ wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) error = ENOMEM; /* XXX unique code */ goto fail; } - bus_dmamap_sync(ring->data_dmat, data->map, + bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); data->m = m; @@ -1364,7 +1361,7 @@ wpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr, * using the traditional bit-bang method. Data is read up until len bytes have * been obtained. */ -static int +static uint16_t wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) { int ntries; @@ -2308,7 +2305,7 @@ wpi_mrr_setup(struct wpi_softc *sc) } /* setup MRR for control frames */ - mrr.which = htole32(WPI_MRR_CTL); + mrr.which = WPI_MRR_CTL; error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); if (error != 0) { device_printf(sc->sc_dev, @@ -2317,7 +2314,7 @@ wpi_mrr_setup(struct wpi_softc *sc) } /* setup MRR for data frames */ - mrr.which = htole32(WPI_MRR_DATA); + mrr.which = WPI_MRR_DATA; error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); if (error != 0) { device_printf(sc->sc_dev, diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/Jamfile b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/Jamfile index 4ad32640c2..a7e3ffc364 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/Jamfile +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/Jamfile @@ -28,11 +28,11 @@ HAIKU_WIFI_FIRMWARE_PACKAGES on iprowifi4965 = iwlwifi-1000-ucode-39.31.5.1 iwlwifi-4965-ucode-228.61.2.24 iwlwifi-5000-ucode-8.83.5.1 iwlwifi-5150-ucode-8.24.2.2 iwlwifi-6000-ucode-9.221.4.1 iwlwifi-6000g2a-ucode-17.168.5.3 - iwlwifi-6050-ucode-41.28.5.1 ; + iwlwifi-6000g2b-ucode-18.168.6.1 iwlwifi-6050-ucode-41.28.5.1 ; HAIKU_WIFI_FIRMWARE_ARCHIVES on iprowifi4965 = iwlwifi-1000-ucode-39.31.5.1.tgz iwlwifi-4965-ucode-228.61.2.24.tgz iwlwifi-5000-ucode-8.83.5.1.tgz iwlwifi-5150-ucode-8.24.2.2.tgz iwlwifi-6000-ucode-9.221.4.1.tgz iwlwifi-6000g2a-ucode-17.168.5.3.tgz - iwlwifi-6050-ucode-41.28.5.1.tgz ; + iwlwifi-6000g2b-ucode-18.168.6.1.tgz iwlwifi-6050-ucode-41.28.5.1.tgz ; HAIKU_WIFI_FIRMWARE_DO_EXTRACT on iprowifi4965 = true ; diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c index 33fde1592f..30f852d177 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c @@ -72,24 +72,65 @@ __FBSDID("$FreeBSD$"); #include #include +struct iwn_ident { + uint16_t vendor; + uint16_t device; + const char *name; +}; + +static const struct iwn_ident iwn_ident_table[] = { + { 0x8086, 0x0082, "Intel(R) Centrino(R) Advanced-N 6205" }, + { 0x8086, 0x0083, "Intel(R) Centrino(R) Wireless-N 1000" }, + { 0x8086, 0x0084, "Intel(R) Centrino(R) Wireless-N 1000" }, + { 0x8086, 0x0085, "Intel(R) Centrino(R) Advanced-N 6205" }, + { 0x8086, 0x0087, "Intel(R) Centrino(R) Advanced-N + WiMAX 6250" }, + { 0x8086, 0x0089, "Intel(R) Centrino(R) Advanced-N + WiMAX 6250" }, + { 0x8086, 0x008a, "Intel(R) Centrino(R) Wireless-N 1030" }, + { 0x8086, 0x008b, "Intel(R) Centrino(R) Wireless-N 1030" }, + { 0x8086, 0x0090, "Intel(R) Centrino(R) Advanced-N 6230" }, + { 0x8086, 0x0091, "Intel(R) Centrino(R) Advanced-N 6230" }, + { 0x8086, 0x0896, "Intel(R) Centrino(R) Wireless-N 130" }, + { 0x8086, 0x4229, "Intel(R) Wireless WiFi Link 4965" }, + { 0x8086, 0x422b, "Intel(R) Centrino(R) Ultimate-N 6300" }, + { 0x8086, 0x422c, "Intel(R) Centrino(R) Advanced-N 6200" }, + { 0x8086, 0x422d, "Intel(R) Wireless WiFi Link 4965" }, + { 0x8086, 0x4230, "Intel(R) Wireless WiFi Link 4965" }, + { 0x8086, 0x4232, "Intel(R) WiFi Link 5100" }, + { 0x8086, 0x4233, "Intel(R) Wireless WiFi Link 4965" }, + { 0x8086, 0x4235, "Intel(R) Ultimate N WiFi Link 5300" }, + { 0x8086, 0x4236, "Intel(R) Ultimate N WiFi Link 5300" }, + { 0x8086, 0x4237, "Intel(R) WiFi Link 5100" }, + { 0x8086, 0x4238, "Intel(R) Centrino(R) Ultimate-N 6300" }, + { 0x8086, 0x4239, "Intel(R) Centrino(R) Advanced-N 6200" }, + { 0x8086, 0x423a, "Intel(R) WiMAX/WiFi Link 5350" }, + { 0x8086, 0x423b, "Intel(R) WiMAX/WiFi Link 5350" }, + { 0x8086, 0x423c, "Intel(R) WiMAX/WiFi Link 5150" }, + { 0x8086, 0x423d, "Intel(R) WiMAX/WiFi Link 5150" }, + { 0, 0, NULL } +}; + static int iwn_probe(device_t); static int iwn_attach(device_t); -static const struct iwn_hal *iwn_hal_attach(struct iwn_softc *); +static int iwn4965_attach(struct iwn_softc *, uint16_t); +static int iwn5000_attach(struct iwn_softc *, uint16_t); static void iwn_radiotap_attach(struct iwn_softc *); +static void iwn_sysctlattach(struct iwn_softc *); static struct ieee80211vap *iwn_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]); static void iwn_vap_delete(struct ieee80211vap *); -static int iwn_cleanup(device_t); static int iwn_detach(device_t); +static int iwn_shutdown(device_t); +static int iwn_suspend(device_t); +static int iwn_resume(device_t); static int iwn_nic_lock(struct iwn_softc *); static int iwn_eeprom_lock(struct iwn_softc *); static int iwn_init_otprom(struct iwn_softc *); static int iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int); static void iwn_dma_map_addr(void *, bus_dma_segment_t *, int, int); static int iwn_dma_contig_alloc(struct iwn_softc *, struct iwn_dma_info *, - void **, bus_size_t, bus_size_t, int); + void **, bus_size_t, bus_size_t); static void iwn_dma_contig_free(struct iwn_dma_info *); static int iwn_alloc_sched(struct iwn_softc *); static void iwn_free_sched(struct iwn_softc *); @@ -114,26 +155,28 @@ static void iwn4965_print_power_group(struct iwn_softc *, int); static void iwn5000_read_eeprom(struct iwn_softc *); static uint32_t iwn_eeprom_channel_flags(struct iwn_eeprom_chan *); static void iwn_read_eeprom_band(struct iwn_softc *, int); -#if 0 /* HT */ static void iwn_read_eeprom_ht40(struct iwn_softc *, int); -#endif -static void iwn_read_eeprom_channels(struct iwn_softc *, int, - uint32_t); +static void iwn_read_eeprom_channels(struct iwn_softc *, int, uint32_t); +static struct iwn_eeprom_chan *iwn_find_eeprom_channel(struct iwn_softc *, + struct ieee80211_channel *); +static int iwn_setregdomain(struct ieee80211com *, + struct ieee80211_regdomain *, int, + struct ieee80211_channel[]); static void iwn_read_eeprom_enhinfo(struct iwn_softc *); static struct ieee80211_node *iwn_node_alloc(struct ieee80211vap *, const uint8_t mac[IEEE80211_ADDR_LEN]); +static void iwn_newassoc(struct ieee80211_node *, int); static int iwn_media_change(struct ifnet *); static int iwn_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static void iwn_calib_timeout(void *); static void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); -static void iwn_timer_timeout(void *); -static void iwn_calib_reset(struct iwn_softc *); static void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); -#if 0 /* HT */ static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); -#endif +static void iwn5000_rx_calib_results(struct iwn_softc *, + struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *, @@ -142,6 +185,7 @@ static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, uint8_t); +static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, void *); static void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *); static void iwn_notif_intr(struct iwn_softc *); static void iwn_wakeup_intr(struct iwn_softc *); @@ -155,23 +199,26 @@ static void iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t, #ifdef notyet static void iwn5000_reset_sched(struct iwn_softc *, int, int); #endif -static uint8_t iwn_plcp_signal(int); static int iwn_tx_data(struct iwn_softc *, struct mbuf *, - struct ieee80211_node *, struct iwn_tx_ring *); + struct ieee80211_node *); +static int iwn_tx_data_raw(struct iwn_softc *, struct mbuf *, + struct ieee80211_node *, + const struct ieee80211_bpf_params *params); static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void iwn_start(struct ifnet *); static void iwn_start_locked(struct ifnet *); -static void iwn_watchdog(struct iwn_softc *sc); +static void iwn_watchdog(void *); static int iwn_ioctl(struct ifnet *, u_long, caddr_t); static int iwn_cmd(struct iwn_softc *, int, const void *, int, int); static int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *, int); static int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *, int); -static int iwn_set_link_quality(struct iwn_softc *, uint8_t, int); +static int iwn_set_link_quality(struct iwn_softc *, + struct ieee80211_node *); static int iwn_add_broadcast_node(struct iwn_softc *, int); -static int iwn_wme_update(struct ieee80211com *); +static int iwn_updateedca(struct ieee80211com *); static void iwn_update_mcast(struct ifnet *); static void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t); static int iwn_set_critical_temp(struct iwn_softc *); @@ -197,35 +244,39 @@ static void iwn_tune_sensitivity(struct iwn_softc *, const struct iwn_rx_stats *); static int iwn_send_sensitivity(struct iwn_softc *); static int iwn_set_pslevel(struct iwn_softc *, int, int, int); +static int iwn_send_btcoex(struct iwn_softc *); +static int iwn_send_advanced_btcoex(struct iwn_softc *); +static int iwn5000_runtime_calib(struct iwn_softc *); static int iwn_config(struct iwn_softc *); +static uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int); static int iwn_scan(struct iwn_softc *); static int iwn_auth(struct iwn_softc *, struct ieee80211vap *vap); static int iwn_run(struct iwn_softc *, struct ieee80211vap *vap); -#if 0 /* HT */ -static int iwn_ampdu_rx_start(struct ieee80211com *, - struct ieee80211_node *, uint8_t); -static void iwn_ampdu_rx_stop(struct ieee80211com *, - struct ieee80211_node *, uint8_t); +static int iwn_ampdu_rx_start(struct ieee80211_node *, + struct ieee80211_rx_ampdu *, int, int, int); +static void iwn_ampdu_rx_stop(struct ieee80211_node *, + struct ieee80211_rx_ampdu *); +static int iwn_addba_request(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int, int, int); +static int iwn_addba_response(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int, int, int); static int iwn_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); -static void iwn_ampdu_tx_stop(struct ieee80211com *, - struct ieee80211_node *, uint8_t); +static void iwn_ampdu_tx_stop(struct ieee80211_node *, + struct ieee80211_tx_ampdu *); static void iwn4965_ampdu_tx_start(struct iwn_softc *, - struct ieee80211_node *, uint8_t, uint16_t); -static void iwn4965_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t); + struct ieee80211_node *, int, uint8_t, uint16_t); +static void iwn4965_ampdu_tx_stop(struct iwn_softc *, int, + uint8_t, uint16_t); static void iwn5000_ampdu_tx_start(struct iwn_softc *, - struct ieee80211_node *, uint8_t, uint16_t); -static void iwn5000_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t); -#endif -static int iwn5000_send_calib_results(struct iwn_softc *); -static int iwn5000_save_calib_result(struct iwn_softc *, - struct iwn_phy_calib *, int, int); -static void iwn5000_free_calib_results(struct iwn_softc *); -static int iwn5000_chrystal_calib(struct iwn_softc *); -static int iwn5000_send_calib_query(struct iwn_softc *, uint32_t); -static int iwn5000_rx_calib_result(struct iwn_softc *, - struct iwn_rx_desc *, struct iwn_rx_data *); + struct ieee80211_node *, int, uint8_t, uint16_t); +static void iwn5000_ampdu_tx_stop(struct iwn_softc *, int, + uint8_t, uint16_t); +static int iwn5000_query_calibration(struct iwn_softc *); +static int iwn5000_send_calibration(struct iwn_softc *); static int iwn5000_send_wimax_coex(struct iwn_softc *); +static int iwn5000_crystal_calib(struct iwn_softc *); +static int iwn5000_temp_offset_calib(struct iwn_softc *); static int iwn4965_post_alive(struct iwn_softc *); static int iwn5000_post_alive(struct iwn_softc *); static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *, @@ -248,27 +299,18 @@ static int iwn5000_nic_config(struct iwn_softc *); static int iwn_hw_prepare(struct iwn_softc *); static int iwn_hw_init(struct iwn_softc *); static void iwn_hw_stop(struct iwn_softc *); +static void iwn_radio_on(void *, int); +static void iwn_radio_off(void *, int); static void iwn_init_locked(struct iwn_softc *); static void iwn_init(void *); static void iwn_stop_locked(struct iwn_softc *); static void iwn_stop(struct iwn_softc *); -static void iwn_scan_start(struct ieee80211com *); -static void iwn_scan_end(struct ieee80211com *); -static void iwn_set_channel(struct ieee80211com *); -static void iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long); -static void iwn_scan_mindwell(struct ieee80211_scan_state *); -static struct iwn_eeprom_chan *iwn_find_eeprom_channel(struct iwn_softc *, - struct ieee80211_channel *); -static int iwn_setregdomain(struct ieee80211com *, - struct ieee80211_regdomain *, int, - struct ieee80211_channel []); +static void iwn_scan_start(struct ieee80211com *); +static void iwn_scan_end(struct ieee80211com *); +static void iwn_set_channel(struct ieee80211com *); +static void iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long); +static void iwn_scan_mindwell(struct ieee80211_scan_state *); static void iwn_hw_reset(void *, int); -static void iwn_radio_on(void *, int); -static void iwn_radio_off(void *, int); -static void iwn_sysctlattach(struct iwn_softc *); -static int iwn_shutdown(device_t); -static int iwn_suspend(device_t); -static int iwn_resume(device_t); #define IWN_DEBUG #ifdef IWN_DEBUG @@ -295,107 +337,77 @@ enum { printf(fmt, __VA_ARGS__); \ } while (0) -static const char *iwn_intr_str(uint8_t); +static const char * +iwn_intr_str(uint8_t cmd) +{ + switch (cmd) { + /* Notifications */ + case IWN_UC_READY: return "UC_READY"; + case IWN_ADD_NODE_DONE: return "ADD_NODE_DONE"; + case IWN_TX_DONE: return "TX_DONE"; + case IWN_START_SCAN: return "START_SCAN"; + case IWN_STOP_SCAN: return "STOP_SCAN"; + case IWN_RX_STATISTICS: return "RX_STATS"; + case IWN_BEACON_STATISTICS: return "BEACON_STATS"; + case IWN_STATE_CHANGED: return "STATE_CHANGED"; + case IWN_BEACON_MISSED: return "BEACON_MISSED"; + case IWN_RX_PHY: return "RX_PHY"; + case IWN_MPDU_RX_DONE: return "MPDU_RX_DONE"; + case IWN_RX_DONE: return "RX_DONE"; + + /* Command Notifications */ + case IWN_CMD_RXON: return "IWN_CMD_RXON"; + case IWN_CMD_RXON_ASSOC: return "IWN_CMD_RXON_ASSOC"; + case IWN_CMD_EDCA_PARAMS: return "IWN_CMD_EDCA_PARAMS"; + case IWN_CMD_TIMING: return "IWN_CMD_TIMING"; + case IWN_CMD_LINK_QUALITY: return "IWN_CMD_LINK_QUALITY"; + case IWN_CMD_SET_LED: return "IWN_CMD_SET_LED"; + case IWN5000_CMD_WIMAX_COEX: return "IWN5000_CMD_WIMAX_COEX"; + case IWN5000_CMD_CALIB_CONFIG: return "IWN5000_CMD_CALIB_CONFIG"; + case IWN5000_CMD_CALIB_RESULT: return "IWN5000_CMD_CALIB_RESULT"; + case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE"; + case IWN_CMD_SET_POWER_MODE: return "IWN_CMD_SET_POWER_MODE"; + case IWN_CMD_SCAN: return "IWN_CMD_SCAN"; + case IWN_CMD_SCAN_RESULTS: return "IWN_CMD_SCAN_RESULTS"; + case IWN_CMD_TXPOWER: return "IWN_CMD_TXPOWER"; + case IWN_CMD_TXPOWER_DBM: return "IWN_CMD_TXPOWER_DBM"; + case IWN5000_CMD_TX_ANT_CONFIG: return "IWN5000_CMD_TX_ANT_CONFIG"; + case IWN_CMD_BT_COEX: return "IWN_CMD_BT_COEX"; + case IWN_CMD_SET_CRITICAL_TEMP: return "IWN_CMD_SET_CRITICAL_TEMP"; + case IWN_CMD_SET_SENSITIVITY: return "IWN_CMD_SET_SENSITIVITY"; + case IWN_CMD_PHY_CALIB: return "IWN_CMD_PHY_CALIB"; + } + return "UNKNOWN INTR NOTIF/CMD"; +} #else #define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0) #endif -struct iwn_ident { - uint16_t vendor; - uint16_t device; - const char *name; +static device_method_t iwn_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, iwn_probe), + DEVMETHOD(device_attach, iwn_attach), + DEVMETHOD(device_detach, iwn_detach), + DEVMETHOD(device_shutdown, iwn_shutdown), + DEVMETHOD(device_suspend, iwn_suspend), + DEVMETHOD(device_resume, iwn_resume), + { 0, 0 } }; -static const struct iwn_ident iwn_ident_table [] = { - { 0x8086, 0x4229, "Intel(R) PRO/Wireless 4965BGN" }, - { 0x8086, 0x422D, "Intel(R) PRO/Wireless 4965BGN" }, - { 0x8086, 0x4230, "Intel(R) PRO/Wireless 4965BGN" }, - { 0x8086, 0x4233, "Intel(R) PRO/Wireless 4965BGN" }, - { 0x8086, 0x4232, "Intel(R) PRO/Wireless 5100" }, - { 0x8086, 0x4237, "Intel(R) PRO/Wireless 5100" }, - { 0x8086, 0x423C, "Intel(R) PRO/Wireless 5150" }, - { 0x8086, 0x423D, "Intel(R) PRO/Wireless 5150" }, - { 0x8086, 0x4235, "Intel(R) PRO/Wireless 5300" }, - { 0x8086, 0x4236, "Intel(R) PRO/Wireless 5300" }, - { 0x8086, 0x423A, "Intel(R) PRO/Wireless 5350" }, - { 0x8086, 0x423B, "Intel(R) PRO/Wireless 5350" }, - { 0x8086, 0x0083, "Intel(R) PRO/Wireless 1000" }, - { 0x8086, 0x0084, "Intel(R) PRO/Wireless 1000" }, - { 0x8086, 0x008D, "Intel(R) PRO/Wireless 6000" }, - { 0x8086, 0x008E, "Intel(R) PRO/Wireless 6000" }, - { 0x8086, 0x4238, "Intel(R) PRO/Wireless 6000" }, - { 0x8086, 0x4239, "Intel(R) PRO/Wireless 6000" }, - { 0x8086, 0x422B, "Intel(R) PRO/Wireless 6000" }, - { 0x8086, 0x422C, "Intel(R) PRO/Wireless 6000" }, - { 0x8086, 0x0087, "Intel(R) PRO/Wireless 6250" }, - { 0x8086, 0x0089, "Intel(R) PRO/Wireless 6250" }, - { 0x8086, 0x0082, "Intel(R) PRO/Wireless 6205a" }, - { 0x8086, 0x0085, "Intel(R) PRO/Wireless 6205a" }, -#ifdef notyet - { 0x8086, 0x008a, "Intel(R) PRO/Wireless 6205b" }, - { 0x8086, 0x008b, "Intel(R) PRO/Wireless 6205b" }, - { 0x8086, 0x008f, "Intel(R) PRO/Wireless 6205b" }, - { 0x8086, 0x0090, "Intel(R) PRO/Wireless 6205b" }, - { 0x8086, 0x0091, "Intel(R) PRO/Wireless 6205b" }, -#endif - { 0, 0, NULL } +static driver_t iwn_driver = { + "iwn", + iwn_methods, + sizeof(struct iwn_softc) }; +static devclass_t iwn_devclass; -static const struct iwn_hal iwn4965_hal = { - iwn4965_load_firmware, - iwn4965_read_eeprom, - iwn4965_post_alive, - iwn4965_nic_config, - iwn4965_update_sched, - iwn4965_get_temperature, - iwn4965_get_rssi, - iwn4965_set_txpower, - iwn4965_init_gains, - iwn4965_set_gains, - iwn4965_add_node, - iwn4965_tx_done, -#if 0 /* HT */ - iwn4965_ampdu_tx_start, - iwn4965_ampdu_tx_stop, -#endif - IWN4965_NTXQUEUES, - IWN4965_NDMACHNLS, - IWN4965_ID_BROADCAST, - IWN4965_RXONSZ, - IWN4965_SCHEDSZ, - IWN4965_FW_TEXT_MAXSZ, - IWN4965_FW_DATA_MAXSZ, - IWN4965_FWSZ, - IWN4965_SCHED_TXFACT -}; +DRIVER_MODULE(iwn, pci, iwn_driver, iwn_devclass, 0, 0); -static const struct iwn_hal iwn5000_hal = { - iwn5000_load_firmware, - iwn5000_read_eeprom, - iwn5000_post_alive, - iwn5000_nic_config, - iwn5000_update_sched, - iwn5000_get_temperature, - iwn5000_get_rssi, - iwn5000_set_txpower, - iwn5000_init_gains, - iwn5000_set_gains, - iwn5000_add_node, - iwn5000_tx_done, -#if 0 /* HT */ - iwn5000_ampdu_tx_start, - iwn5000_ampdu_tx_stop, -#endif - IWN5000_NTXQUEUES, - IWN5000_NDMACHNLS, - IWN5000_ID_BROADCAST, - IWN5000_RXONSZ, - IWN5000_SCHEDSZ, - IWN5000_FW_TEXT_MAXSZ, - IWN5000_FW_DATA_MAXSZ, - IWN5000_FWSZ, - IWN5000_SCHED_TXFACT -}; +MODULE_VERSION(iwn, 1); + +MODULE_DEPEND(iwn, firmware, 1, 1, 1); +MODULE_DEPEND(iwn, pci, 1, 1, 1); +MODULE_DEPEND(iwn, wlan, 1, 1, 1); static int iwn_probe(device_t dev) @@ -418,8 +430,7 @@ iwn_attach(device_t dev) struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); struct ieee80211com *ic; struct ifnet *ifp; - const struct iwn_hal *hal; - uint32_t tmp; + uint32_t reg; int i, error, result; uint8_t macaddr[IEEE80211_ADDR_LEN]; @@ -429,7 +440,7 @@ iwn_attach(device_t dev) * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space. */ - error = pci_find_extcap(dev, PCIY_EXPRESS, &sc->sc_cap_off); + error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); if (error != 0) { device_printf(dev, "PCIe capability structure not found!\n"); return error; @@ -439,12 +450,12 @@ iwn_attach(device_t dev) pci_write_config(dev, 0x41, 0, 1); /* Hardware bug workaround. */ - tmp = pci_read_config(dev, PCIR_COMMAND, 1); - if (tmp & PCIM_CMD_INTxDIS) { + reg = pci_read_config(dev, PCIR_COMMAND, 1); + if (reg & PCIM_CMD_INTxDIS) { DPRINTF(sc, IWN_DEBUG_RESET, "%s: PCIe INTx Disable set\n", __func__); - tmp &= ~PCIM_CMD_INTxDIS; - pci_write_config(dev, PCIR_COMMAND, tmp, 1); + reg &= ~PCIM_CMD_INTxDIS; + pci_write_config(dev, PCIR_COMMAND, reg, 1); } /* Enable bus-mastering. */ @@ -453,48 +464,48 @@ iwn_attach(device_t dev) sc->mem_rid = PCIR_BAR(0); sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); - if (sc->mem == NULL ) { - device_printf(dev, "could not allocate memory resources\n"); + if (sc->mem == NULL) { + device_printf(dev, "can't map mem space\n"); error = ENOMEM; return error; } - sc->sc_st = rman_get_bustag(sc->mem); sc->sc_sh = rman_get_bushandle(sc->mem); + sc->irq_rid = 0; if ((result = pci_msi_count(dev)) == 1 && pci_alloc_msi(dev, &result) == 0) sc->irq_rid = 1; + /* Install interrupt handler. */ sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq == NULL) { - device_printf(dev, "could not allocate interrupt resource\n"); + device_printf(dev, "can't map interrupt\n"); error = ENOMEM; goto fail; } IWN_LOCK_INIT(sc); - callout_init_mtx(&sc->sc_timer_to, &sc->sc_mtx, 0); - TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc ); - TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc ); - TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc ); - /* Attach Hardware Abstraction Layer. */ - hal = iwn_hal_attach(sc); - if (hal == NULL) { - error = ENXIO; /* XXX: Wrong error code? */ + /* Read hardware revision and attach. */ + sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> 4) & 0xf; + if (sc->hw_type == IWN_HW_REV_TYPE_4965) + error = iwn4965_attach(sc, pci_get_device(dev)); + else + error = iwn5000_attach(sc, pci_get_device(dev)); + if (error != 0) { + device_printf(dev, "could not attach device, error %d\n", + error); goto fail; } - error = iwn_hw_prepare(sc); - if (error != 0) { + if ((error = iwn_hw_prepare(sc)) != 0) { device_printf(dev, "hardware not ready, error %d\n", error); goto fail; } /* Allocate DMA memory for firmware transfers. */ - error = iwn_alloc_fwmem(sc); - if (error != 0) { + if ((error = iwn_alloc_fwmem(sc)) != 0) { device_printf(dev, "could not allocate memory for firmware, error %d\n", error); @@ -502,53 +513,80 @@ iwn_attach(device_t dev) } /* Allocate "Keep Warm" page. */ - error = iwn_alloc_kw(sc); - if (error != 0) { + if ((error = iwn_alloc_kw(sc)) != 0) { device_printf(dev, - "could not allocate \"Keep Warm\" page, error %d\n", error); + "could not allocate keep warm page, error %d\n", error); goto fail; } /* Allocate ICT table for 5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965 && (error = iwn_alloc_ict(sc)) != 0) { - device_printf(dev, - "%s: could not allocate ICT table, error %d\n", - __func__, error); - goto fail; - } - - /* Allocate TX scheduler "rings". */ - error = iwn_alloc_sched(sc); - if (error != 0) { - device_printf(dev, - "could not allocate TX scheduler rings, error %d\n", + device_printf(dev, "could not allocate ICT table, error %d\n", error); goto fail; } - /* Allocate TX rings (16 on 4965AGN, 20 on 5000). */ - for (i = 0; i < hal->ntxqs; i++) { - error = iwn_alloc_tx_ring(sc, &sc->txq[i], i); - if (error != 0) { + /* Allocate TX scheduler "rings". */ + if ((error = iwn_alloc_sched(sc)) != 0) { + device_printf(dev, + "could not allocate TX scheduler rings, error %d\n", error); + goto fail; + } + + /* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */ + for (i = 0; i < sc->ntxqs; i++) { + if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { device_printf(dev, - "could not allocate Tx ring %d, error %d\n", - i, error); + "could not allocate TX ring %d, error %d\n", i, + error); goto fail; } } /* Allocate RX ring. */ - error = iwn_alloc_rx_ring(sc, &sc->rxq); - if (error != 0 ){ - device_printf(dev, - "could not allocate Rx ring, error %d\n", error); + if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) { + device_printf(dev, "could not allocate RX ring, error %d\n", + error); goto fail; } /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + goto fail; + } + + ic = ifp->if_l2com; + ic->ic_ifp = ifp; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ + + /* Set device capabilities. */ + ic->ic_caps = + IEEE80211_C_STA /* station mode supported */ + | IEEE80211_C_MONITOR /* monitor mode supported */ + | IEEE80211_C_BGSCAN /* background scanning */ + | IEEE80211_C_TXPMGT /* tx power management */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_WPA + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ +#if 0 + | IEEE80211_C_IBSS /* ibss/adhoc mode */ +#endif + | IEEE80211_C_WME /* WME */ + ; + + /* Read MAC address, channels, etc from EEPROM. */ + if ((error = iwn_read_eeprom(sc, macaddr)) != 0) { + device_printf(dev, "could not read EEPROM, error %d\n", + error); + goto fail; + } + /* Count the number of available chains. */ sc->ntxchains = ((sc->txchainmask >> 2) & 1) + @@ -558,84 +596,37 @@ iwn_attach(device_t dev) ((sc->rxchainmask >> 2) & 1) + ((sc->rxchainmask >> 1) & 1) + ((sc->rxchainmask >> 0) & 1); - - ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); - if (ifp == NULL) { - device_printf(dev, "can not allocate ifnet structure\n"); - goto fail; + if (bootverbose) { + device_printf(dev, "MIMO %dT%dR, %.4s, address %6D\n", + sc->ntxchains, sc->nrxchains, sc->eeprom_domain, + macaddr, ":"); } - ic = ifp->if_l2com; - ic->ic_ifp = ifp; - ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ - ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ - - /* Set device capabilities. */ - ic->ic_caps = - IEEE80211_C_STA /* station mode supported */ - | IEEE80211_C_MONITOR /* monitor mode supported */ - | IEEE80211_C_TXPMGT /* tx power management */ - | IEEE80211_C_SHSLOT /* short slot time supported */ - | IEEE80211_C_WPA - | IEEE80211_C_SHPREAMBLE /* short preamble supported */ - | IEEE80211_C_BGSCAN /* background scanning */ -#if 0 - | IEEE80211_C_IBSS /* ibss/adhoc mode */ -#endif - | IEEE80211_C_WME /* WME */ - ; -#if 0 /* HT */ - /* XXX disable until HT channel setup works */ - ic->ic_htcaps = - IEEE80211_HTCAP_SMPS_ENA /* SM PS mode enabled */ - | IEEE80211_HTCAP_CHWIDTH40 /* 40MHz channel width */ - | IEEE80211_HTCAP_SHORTGI20 /* short GI in 20MHz */ - | IEEE80211_HTCAP_SHORTGI40 /* short GI in 40MHz */ - | IEEE80211_HTCAP_RXSTBC_2STREAM/* 1-2 spatial streams */ - | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */ - /* s/w capabilities */ - | IEEE80211_HTC_HT /* HT operation */ - | IEEE80211_HTC_AMPDU /* tx A-MPDU */ - | IEEE80211_HTC_AMSDU /* tx A-MSDU */ - ; - - /* Set HT capabilities. */ - ic->ic_htcaps = + if (sc->sc_flags & IWN_FLAG_HAS_11N) { + ic->ic_rxstream = sc->nrxchains; + ic->ic_txstream = sc->ntxchains; + ic->ic_htcaps = + IEEE80211_HTCAP_SMPS_OFF /* SMPS mode disabled */ + | IEEE80211_HTCAP_SHORTGI20 /* short GI in 20MHz */ + | IEEE80211_HTCAP_CHWIDTH40 /* 40MHz channel width*/ + | IEEE80211_HTCAP_SHORTGI40 /* short GI in 40MHz */ +#ifdef notyet + | IEEE80211_HTCAP_GREENFIELD #if IWN_RBUF_SIZE == 8192 - IEEE80211_HTCAP_AMSDU7935 | + | IEEE80211_HTCAP_MAXAMSDU_7935 /* max A-MSDU length */ +#else + | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */ #endif - IEEE80211_HTCAP_CBW20_40 | - IEEE80211_HTCAP_SGI20 | - IEEE80211_HTCAP_SGI40; - if (sc->hw_type != IWN_HW_REV_TYPE_4965) - ic->ic_htcaps |= IEEE80211_HTCAP_GF; - if (sc->hw_type == IWN_HW_REV_TYPE_6050) - ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DYN; - else - ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DIS; #endif - - /* Read MAC address, channels, etc from EEPROM. */ - error = iwn_read_eeprom(sc, macaddr); - if (error != 0) { - device_printf(dev, "could not read EEPROM, error %d\n", - error); - goto fail; + /* s/w capabilities */ + | IEEE80211_HTC_HT /* HT operation */ + | IEEE80211_HTC_AMPDU /* tx A-MPDU */ +#ifdef notyet + | IEEE80211_HTC_AMSDU /* tx A-MSDU */ +#endif + ; } - device_printf(sc->sc_dev, "MIMO %dT%dR, %.4s, address %6D\n", - sc->ntxchains, sc->nrxchains, sc->eeprom_domain, - macaddr, ":"); - -#if 0 /* HT */ - /* Set supported HT rates. */ - ic->ic_sup_mcs[0] = 0xff; - if (sc->nrxchains > 1) - ic->ic_sup_mcs[1] = 0xff; - if (sc->nrxchains > 2) - ic->ic_sup_mcs[2] = 0xff; -#endif - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; @@ -651,7 +642,18 @@ iwn_attach(device_t dev) ic->ic_vap_delete = iwn_vap_delete; ic->ic_raw_xmit = iwn_raw_xmit; ic->ic_node_alloc = iwn_node_alloc; - ic->ic_wme.wme_update = iwn_wme_update; + sc->sc_ampdu_rx_start = ic->ic_ampdu_rx_start; + ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; + sc->sc_ampdu_rx_stop = ic->ic_ampdu_rx_stop; + ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; + sc->sc_addba_request = ic->ic_addba_request; + ic->ic_addba_request = iwn_addba_request; + sc->sc_addba_response = ic->ic_addba_response; + ic->ic_addba_response = iwn_addba_response; + sc->sc_addba_stop = ic->ic_addba_stop; + ic->ic_addba_stop = iwn_ampdu_tx_stop; + ic->ic_newassoc = iwn_newassoc; + ic->ic_wme.wme_update = iwn_updateedca; ic->ic_update_mcast = iwn_update_mcast; ic->ic_scan_start = iwn_scan_start; ic->ic_scan_end = iwn_scan_end; @@ -659,14 +661,15 @@ iwn_attach(device_t dev) ic->ic_scan_curchan = iwn_scan_curchan; ic->ic_scan_mindwell = iwn_scan_mindwell; ic->ic_setregdomain = iwn_setregdomain; -#if 0 /* HT */ - ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; - ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; - ic->ic_ampdu_tx_start = iwn_ampdu_tx_start; - ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop; -#endif iwn_radiotap_attach(sc); + + callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); + callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); + TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc); + TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc); + TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc); + iwn_sysctlattach(sc); /* @@ -675,117 +678,141 @@ iwn_attach(device_t dev) error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, iwn_intr, sc, &sc->sc_ih); if (error != 0) { - device_printf(dev, "could not set up interrupt, error %d\n", + device_printf(dev, "can't establish interrupt, error %d\n", error); goto fail; } - ieee80211_announce(ic); + if (bootverbose) + ieee80211_announce(ic); return 0; fail: - iwn_cleanup(dev); + iwn_detach(dev); return error; } -static const struct iwn_hal * -iwn_hal_attach(struct iwn_softc *sc) +static int +iwn4965_attach(struct iwn_softc *sc, uint16_t pid) { - sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> 4) & 0xf; + struct iwn_ops *ops = &sc->ops; + + ops->load_firmware = iwn4965_load_firmware; + ops->read_eeprom = iwn4965_read_eeprom; + ops->post_alive = iwn4965_post_alive; + ops->nic_config = iwn4965_nic_config; + ops->update_sched = iwn4965_update_sched; + ops->get_temperature = iwn4965_get_temperature; + ops->get_rssi = iwn4965_get_rssi; + ops->set_txpower = iwn4965_set_txpower; + ops->init_gains = iwn4965_init_gains; + ops->set_gains = iwn4965_set_gains; + ops->add_node = iwn4965_add_node; + ops->tx_done = iwn4965_tx_done; + ops->ampdu_tx_start = iwn4965_ampdu_tx_start; + ops->ampdu_tx_stop = iwn4965_ampdu_tx_stop; + sc->ntxqs = IWN4965_NTXQUEUES; + sc->firstaggqueue = IWN4965_FIRSTAGGQUEUE; + sc->ndmachnls = IWN4965_NDMACHNLS; + sc->broadcast_id = IWN4965_ID_BROADCAST; + sc->rxonsz = IWN4965_RXONSZ; + sc->schedsz = IWN4965_SCHEDSZ; + sc->fw_text_maxsz = IWN4965_FW_TEXT_MAXSZ; + sc->fw_data_maxsz = IWN4965_FW_DATA_MAXSZ; + sc->fwsz = IWN4965_FWSZ; + sc->sched_txfact_addr = IWN4965_SCHED_TXFACT; + sc->limits = &iwn4965_sensitivity_limits; + sc->fwname = "iwn4965fw"; + /* Override chains masks, ROM is known to be broken. */ + sc->txchainmask = IWN_ANT_AB; + sc->rxchainmask = IWN_ANT_ABC; + + return 0; +} + +static int +iwn5000_attach(struct iwn_softc *sc, uint16_t pid) +{ + struct iwn_ops *ops = &sc->ops; + + ops->load_firmware = iwn5000_load_firmware; + ops->read_eeprom = iwn5000_read_eeprom; + ops->post_alive = iwn5000_post_alive; + ops->nic_config = iwn5000_nic_config; + ops->update_sched = iwn5000_update_sched; + ops->get_temperature = iwn5000_get_temperature; + ops->get_rssi = iwn5000_get_rssi; + ops->set_txpower = iwn5000_set_txpower; + ops->init_gains = iwn5000_init_gains; + ops->set_gains = iwn5000_set_gains; + ops->add_node = iwn5000_add_node; + ops->tx_done = iwn5000_tx_done; + ops->ampdu_tx_start = iwn5000_ampdu_tx_start; + ops->ampdu_tx_stop = iwn5000_ampdu_tx_stop; + sc->ntxqs = IWN5000_NTXQUEUES; + sc->firstaggqueue = IWN5000_FIRSTAGGQUEUE; + sc->ndmachnls = IWN5000_NDMACHNLS; + sc->broadcast_id = IWN5000_ID_BROADCAST; + sc->rxonsz = IWN5000_RXONSZ; + sc->schedsz = IWN5000_SCHEDSZ; + sc->fw_text_maxsz = IWN5000_FW_TEXT_MAXSZ; + sc->fw_data_maxsz = IWN5000_FW_DATA_MAXSZ; + sc->fwsz = IWN5000_FWSZ; + sc->sched_txfact_addr = IWN5000_SCHED_TXFACT; + sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; + sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN; switch (sc->hw_type) { - case IWN_HW_REV_TYPE_4965: - sc->sc_hal = &iwn4965_hal; - sc->limits = &iwn4965_sensitivity_limits; - sc->fwname = "iwn4965fw"; - sc->txchainmask = IWN_ANT_AB; - sc->rxchainmask = IWN_ANT_ABC; - break; case IWN_HW_REV_TYPE_5100: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn5000_sensitivity_limits; sc->fwname = "iwn5000fw"; + /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_B; sc->rxchainmask = IWN_ANT_AB; - sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC | - IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_5150: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn5150_sensitivity_limits; sc->fwname = "iwn5150fw"; - sc->txchainmask = IWN_ANT_A; - sc->rxchainmask = IWN_ANT_AB; - sc->calib_init = IWN_CALIB_DC | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_5300: case IWN_HW_REV_TYPE_5350: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn5000_sensitivity_limits; sc->fwname = "iwn5000fw"; - sc->txchainmask = IWN_ANT_ABC; - sc->rxchainmask = IWN_ANT_ABC; - sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC | - IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_1000: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn1000_sensitivity_limits; sc->fwname = "iwn1000fw"; - sc->txchainmask = IWN_ANT_A; - sc->rxchainmask = IWN_ANT_AB; - sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC | - IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_6000: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn6000_sensitivity_limits; sc->fwname = "iwn6000fw"; - switch (pci_get_device(sc->sc_dev)) { - case 0x422C: - case 0x4239: + if (pid == 0x422c || pid == 0x4239) { sc->sc_flags |= IWN_FLAG_INTERNAL_PA; + /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_BC; sc->rxchainmask = IWN_ANT_BC; - break; - default: - sc->txchainmask = IWN_ANT_ABC; - sc->rxchainmask = IWN_ANT_ABC; - sc->calib_runtime = IWN_CALIB_DC; - break; } - sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_6050: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn6000_sensitivity_limits; sc->fwname = "iwn6050fw"; + /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_AB; - sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; - sc->calib_runtime = IWN_CALIB_DC; break; case IWN_HW_REV_TYPE_6005: - sc->sc_hal = &iwn5000_hal; sc->limits = &iwn6000_sensitivity_limits; - sc->fwname = "iwn6005fw"; - sc->txchainmask = IWN_ANT_AB; - sc->rxchainmask = IWN_ANT_AB; - sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | - IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; - sc->calib_runtime = IWN_CALIB_DC; + if (pid != 0x0082 && pid != 0x0085) { + sc->fwname = "iwn6000g2bfw"; + sc->sc_flags |= IWN_FLAG_ADV_BTCOEX; + } else + sc->fwname = "iwn6000g2afw"; break; default: device_printf(sc->sc_dev, "adapter type %d not supported\n", sc->hw_type); - return NULL; + return ENOTSUP; } - return sc->sc_hal; + return 0; } /* @@ -804,11 +831,24 @@ iwn_radiotap_attach(struct iwn_softc *sc) IWN_RX_RADIOTAP_PRESENT); } +static void +iwn_sysctlattach(struct iwn_softc *sc) +{ + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); + +#ifdef IWN_DEBUG + sc->sc_debug = 0; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "debug", CTLFLAG_RW, &sc->sc_debug, 0, "control debugging printfs"); +#endif +} + static struct ieee80211vap * iwn_vap_create(struct ieee80211com *ic, - const char name[IFNAMSIZ], int unit, int opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t mac[IEEE80211_ADDR_LEN]) + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) { struct iwn_vap *ivp; struct ieee80211vap *vap; @@ -844,12 +884,12 @@ iwn_vap_delete(struct ieee80211vap *vap) } static int -iwn_cleanup(device_t dev) +iwn_detach(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic; - int i; + int qid; if (ifp != NULL) { ic = ifp->if_l2com; @@ -859,23 +899,12 @@ iwn_cleanup(device_t dev) ieee80211_draintask(ic, &sc->sc_radiooff_task); iwn_stop(sc); - callout_drain(&sc->sc_timer_to); + callout_drain(&sc->watchdog_to); + callout_drain(&sc->calib_to); ieee80211_ifdetach(ic); } - iwn5000_free_calib_results(sc); - - /* Free DMA resources. */ - iwn_free_rx_ring(sc, &sc->rxq); - if (sc->sc_hal != NULL) - for (i = 0; i < sc->sc_hal->ntxqs; i++) - iwn_free_tx_ring(sc, &sc->txq[i]); - iwn_free_sched(sc); - iwn_free_kw(sc); - if (sc->ict != NULL) - iwn_free_ict(sc); - iwn_free_fwmem(sc); - + /* Uninstall interrupt handler. */ if (sc->irq != NULL) { bus_teardown_intr(dev, sc->irq, sc->sc_ih); bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); @@ -883,6 +912,16 @@ iwn_cleanup(device_t dev) pci_release_msi(dev); } + /* Free DMA resources. */ + iwn_free_rx_ring(sc, &sc->rxq); + for (qid = 0; qid < sc->ntxqs; qid++) + iwn_free_tx_ring(sc, &sc->txq[qid]); + iwn_free_sched(sc); + iwn_free_kw(sc); + if (sc->ict != NULL) + iwn_free_ict(sc); + iwn_free_fwmem(sc); + if (sc->mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); @@ -894,9 +933,46 @@ iwn_cleanup(device_t dev) } static int -iwn_detach(device_t dev) +iwn_shutdown(device_t dev) { - iwn_cleanup(dev); + struct iwn_softc *sc = device_get_softc(dev); + + iwn_stop(sc); + return 0; +} + +static int +iwn_suspend(device_t dev) +{ + struct iwn_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + iwn_stop(sc); + if (vap != NULL) + ieee80211_stop(vap); + return 0; +} + +static int +iwn_resume(device_t dev) +{ + struct iwn_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + /* Clear device-specific "PCI retry timeout" register (41h). */ + pci_write_config(dev, 0x41, 0, 1); + + if (ifp->if_flags & IFF_UP) { + iwn_init(sc); + if (vap != NULL) + ieee80211_init(vap); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + iwn_start(ifp); + } return 0; } @@ -911,7 +987,7 @@ iwn_nic_lock(struct iwn_softc *sc) /* Spin until we actually get the lock. */ for (ntries = 0; ntries < 1000; ntries++) { if ((IWN_READ(sc, IWN_GP_CNTRL) & - (IWN_GP_CNTRL_MAC_ACCESS_ENA | IWN_GP_CNTRL_SLEEP)) == + (IWN_GP_CNTRL_MAC_ACCESS_ENA | IWN_GP_CNTRL_SLEEP)) == IWN_GP_CNTRL_MAC_ACCESS_ENA) return 0; DELAY(10); @@ -1044,12 +1120,10 @@ iwn_init_otprom(struct iwn_softc *sc) int count, error; /* Wait for clock stabilization before accessing prph. */ - error = iwn_clock_wait(sc); - if (error != 0) + if ((error = iwn_clock_wait(sc)) != 0) return error; - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ); DELAY(5); @@ -1094,9 +1168,9 @@ iwn_init_otprom(struct iwn_softc *sc) static int iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count) { + uint8_t *out = data; uint32_t val, tmp; int ntries; - uint8_t *out = data; addr += sc->prom_base; for (; count > 0; count -= 2, addr++) { @@ -1144,58 +1218,57 @@ iwn_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) static int iwn_dma_contig_alloc(struct iwn_softc *sc, struct iwn_dma_info *dma, - void **kvap, bus_size_t size, bus_size_t alignment, int flags) + void **kvap, bus_size_t size, bus_size_t alignment) { int error; - dma->size = size; dma->tag = NULL; + dma->size = size; error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), alignment, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, - 1, size, flags, NULL, NULL, &dma->tag); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: bus_dma_tag_create failed, error %d\n", - __func__, error); + 1, size, BUS_DMA_NOWAIT, NULL, NULL, &dma->tag); + if (error != 0) goto fail; - } + error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr, - flags | BUS_DMA_ZERO, &dma->map); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: bus_dmamem_alloc failed, error %d\n", __func__, error); + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &dma->map); + if (error != 0) goto fail; - } - error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, - size, iwn_dma_map_addr, &dma->paddr, flags); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: bus_dmamap_load failed, error %d\n", __func__, error); + + error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size, + iwn_dma_map_addr, &dma->paddr, BUS_DMA_NOWAIT); + if (error != 0) goto fail; - } + + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); if (kvap != NULL) *kvap = dma->vaddr; + return 0; -fail: - iwn_dma_contig_free(dma); + +fail: iwn_dma_contig_free(dma); return error; } static void iwn_dma_contig_free(struct iwn_dma_info *dma) { - if (dma->tag != NULL) { - if (dma->map != NULL) { - if (dma->paddr == 0) { - bus_dmamap_sync(dma->tag, dma->map, - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(dma->tag, dma->map); - } + if (dma->map != NULL) { + if (dma->vaddr != NULL) { + bus_dmamap_sync(dma->tag, dma->map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dma->tag, dma->map); bus_dmamem_free(dma->tag, &dma->vaddr, dma->map); + dma->vaddr = NULL; } + bus_dmamap_destroy(dma->tag, dma->map); + dma->map = NULL; + } + if (dma->tag != NULL) { bus_dma_tag_destroy(dma->tag); + dma->tag = NULL; } } @@ -1203,8 +1276,8 @@ static int iwn_alloc_sched(struct iwn_softc *sc) { /* TX scheduler rings must be aligned on a 1KB boundary. */ - return iwn_dma_contig_alloc(sc, &sc->sched_dma, - (void **)&sc->sched, sc->sc_hal->schedsz, 1024, BUS_DMA_NOWAIT); + return iwn_dma_contig_alloc(sc, &sc->sched_dma, (void **)&sc->sched, + sc->schedsz, 1024); } static void @@ -1217,8 +1290,7 @@ static int iwn_alloc_kw(struct iwn_softc *sc) { /* "Keep Warm" page must be aligned on a 4KB boundary. */ - return iwn_dma_contig_alloc(sc, &sc->kw_dma, NULL, 4096, 4096, - BUS_DMA_NOWAIT); + return iwn_dma_contig_alloc(sc, &sc->kw_dma, NULL, 4096, 4096); } static void @@ -1231,8 +1303,8 @@ static int iwn_alloc_ict(struct iwn_softc *sc) { /* ICT table must be aligned on a 4KB boundary. */ - return iwn_dma_contig_alloc(sc, &sc->ict_dma, - (void **)&sc->ict, IWN_ICT_SIZE, 4096, BUS_DMA_NOWAIT); + return iwn_dma_contig_alloc(sc, &sc->ict_dma, (void **)&sc->ict, + IWN_ICT_SIZE, 4096); } static void @@ -1245,8 +1317,7 @@ static int iwn_alloc_fwmem(struct iwn_softc *sc) { /* Must be aligned on a 16-byte boundary. */ - return iwn_dma_contig_alloc(sc, &sc->fw_dma, NULL, - sc->sc_hal->fwsz, 16, BUS_DMA_NOWAIT); + return iwn_dma_contig_alloc(sc, &sc->fw_dma, NULL, sc->fwsz, 16); } static void @@ -1265,33 +1336,33 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) /* Allocate RX descriptors (256-byte aligned). */ size = IWN_RX_RING_COUNT * sizeof (uint32_t); - error = iwn_dma_contig_alloc(sc, &ring->desc_dma, - (void **)&ring->desc, size, 256, BUS_DMA_NOWAIT); + error = iwn_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, + size, 256); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not allocate Rx ring DMA memory, error %d\n", - __func__, error); - goto fail; - } - - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, - BUS_SPACE_MAXADDR, NULL, NULL, MJUMPAGESIZE, 1, - MJUMPAGESIZE, BUS_DMA_NOWAIT, NULL, NULL, &ring->data_dmat); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: bus_dma_tag_create_failed, error %d\n", + "%s: could not allocate RX ring DMA memory, error %d\n", __func__, error); goto fail; } /* Allocate RX status area (16-byte aligned). */ - error = iwn_dma_contig_alloc(sc, &ring->stat_dma, - (void **)&ring->stat, sizeof (struct iwn_rx_status), - 16, BUS_DMA_NOWAIT); + error = iwn_dma_contig_alloc(sc, &ring->stat_dma, (void **)&ring->stat, + sizeof (struct iwn_rx_status), 16); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not allocate Rx status DMA memory, error %d\n", + "%s: could not allocate RX status DMA memory, error %d\n", + __func__, error); + goto fail; + } + + /* Create RX buffer DMA tag. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + IWN_RBUF_SIZE, 1, IWN_RBUF_SIZE, BUS_DMA_NOWAIT, NULL, NULL, + &ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not create RX buf DMA tag, error %d\n", __func__, error); goto fail; } @@ -1306,42 +1377,40 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { device_printf(sc->sc_dev, - "%s: bus_dmamap_create failed, error %d\n", + "%s: could not create RX buf DMA map, error %d\n", __func__, error); goto fail; } - data->m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + data->m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, + IWN_RBUF_SIZE); if (data->m == NULL) { device_printf(sc->sc_dev, - "%s: could not allocate rx mbuf\n", __func__); - error = ENOMEM; + "%s: could not allocate RX mbuf\n", __func__); + error = ENOBUFS; goto fail; } - /* Map page. */ error = bus_dmamap_load(ring->data_dmat, data->map, - mtod(data->m, caddr_t), MJUMPAGESIZE, - iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); + mtod(data->m, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, + &paddr, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { device_printf(sc->sc_dev, - "%s: bus_dmamap_load failed, error %d\n", - __func__, error); - m_freem(data->m); - error = ENOMEM; /* XXX unique code */ + "%s: can't not map mbuf, error %d\n", __func__, + error); goto fail; } - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_PREWRITE); /* Set physical address of RX buffer (256-byte aligned). */ ring->desc[i] = htole32(paddr >> 8); } + bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); + return 0; -fail: - iwn_free_rx_ring(sc, ring); + +fail: iwn_free_rx_ring(sc, ring); return error; } @@ -1359,11 +1428,6 @@ iwn_reset_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) DELAY(10); } iwn_nic_unlock(sc); -#ifdef IWN_DEBUG - if (ntries == 1000) - DPRINTF(sc, IWN_DEBUG_ANY, "%s\n", - "timeout resetting Rx ring"); -#endif } ring->cur = 0; sc->last_rx_valid = 0; @@ -1385,27 +1449,32 @@ iwn_free_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) BUS_DMASYNC_POSTREAD); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); + data->m = NULL; } if (data->map != NULL) bus_dmamap_destroy(ring->data_dmat, data->map); } + if (ring->data_dmat != NULL) { + bus_dma_tag_destroy(ring->data_dmat); + ring->data_dmat = NULL; + } } static int iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) { - bus_size_t size; bus_addr_t paddr; + bus_size_t size; int i, error; ring->qid = qid; ring->queued = 0; ring->cur = 0; - /* Allocate TX descriptors (256-byte aligned.) */ - size = IWN_TX_RING_COUNT * sizeof(struct iwn_tx_desc); - error = iwn_dma_contig_alloc(sc, &ring->desc_dma, - (void **)&ring->desc, size, 256, BUS_DMA_NOWAIT); + /* Allocate TX descriptors (256-byte aligned). */ + size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_desc); + error = iwn_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, + size, 256); if (error != 0) { device_printf(sc->sc_dev, "%s: could not allocate TX ring DMA memory, error %d\n", @@ -1413,16 +1482,9 @@ iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) goto fail; } - /* - * We only use rings 0 through 4 (4 EDCA + cmd) so there is no need - * to allocate commands space for other rings. - */ - if (qid > 4) - return 0; - - size = IWN_TX_RING_COUNT * sizeof(struct iwn_tx_cmd); - error = iwn_dma_contig_alloc(sc, &ring->cmd_dma, - (void **)&ring->cmd, size, 4, BUS_DMA_NOWAIT); + size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_cmd); + error = iwn_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, + size, 4); if (error != 0) { device_printf(sc->sc_dev, "%s: could not allocate TX cmd DMA memory, error %d\n", @@ -1431,12 +1493,12 @@ iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) } error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, - BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, IWN_MAX_SCATTER - 1, - MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, &ring->data_dmat); + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + IWN_MAX_SCATTER - 1, MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, + &ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, - "%s: bus_dma_tag_create_failed, error %d\n", + "%s: could not create TX buf DMA tag, error %d\n", __func__, error); goto fail; } @@ -1452,16 +1514,14 @@ iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { device_printf(sc->sc_dev, - "%s: bus_dmamap_create failed, error %d\n", + "%s: could not create TX buf DMA map, error %d\n", __func__, error); goto fail; } - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_PREWRITE); } return 0; -fail: - iwn_free_tx_ring(sc, ring); + +fail: iwn_free_tx_ring(sc, ring); return error; } @@ -1474,6 +1534,8 @@ iwn_reset_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring) struct iwn_tx_data *data = &ring->data[i]; if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; @@ -1508,6 +1570,10 @@ iwn_free_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring) if (data->map != NULL) bus_dmamap_destroy(ring->data_dmat, data->map); } + if (ring->data_dmat != NULL) { + bus_dma_tag_destroy(ring->data_dmat); + ring->data_dmat = NULL; + } } static void @@ -1520,7 +1586,7 @@ iwn5000_ict_reset(struct iwn_softc *sc) memset(sc->ict, 0, IWN_ICT_SIZE); sc->ict_cur = 0; - /* Set physical address of ICT table (4KB aligned.) */ + /* Set physical address of ICT table (4KB aligned). */ DPRINTF(sc, IWN_DEBUG_RESET, "%s: enabling ICT\n", __func__); IWN_WRITE(sc, IWN_DRAM_INT_TBL, IWN_DRAM_INT_TBL_ENABLE | IWN_DRAM_INT_TBL_WRAP_CHECK | sc->ict_dma.paddr >> 12); @@ -1538,9 +1604,9 @@ iwn5000_ict_reset(struct iwn_softc *sc) static int iwn_read_eeprom(struct iwn_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) { - const struct iwn_hal *hal = sc->sc_hal; - int error; + struct iwn_ops *ops = &sc->ops; uint16_t val; + int error; /* Check whether adapter has an EEPROM or an OTPROM. */ if (sc->hw_type >= IWN_HW_REV_TYPE_1000 && @@ -1550,11 +1616,10 @@ iwn_read_eeprom(struct iwn_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) (sc->sc_flags & IWN_FLAG_HAS_OTPROM) ? "OTPROM" : "EEPROM"); /* Adapter has to be powered on for EEPROM access to work. */ - error = iwn_apm_init(sc); - if (error != 0) { + if ((error = iwn_apm_init(sc)) != 0) { device_printf(sc->sc_dev, - "%s: could not power ON adapter, error %d\n", - __func__, error); + "%s: could not power ON adapter, error %d\n", __func__, + error); return error; } @@ -1562,17 +1627,13 @@ iwn_read_eeprom(struct iwn_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) device_printf(sc->sc_dev, "%s: bad ROM signature\n", __func__); return EIO; } - error = iwn_eeprom_lock(sc); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not lock ROM, error %d\n", + if ((error = iwn_eeprom_lock(sc)) != 0) { + device_printf(sc->sc_dev, "%s: could not lock ROM, error %d\n", __func__, error); return error; } - if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) { - error = iwn_init_otprom(sc); - if (error != 0) { + if ((error = iwn_init_otprom(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not initialize OTPROM, error %d\n", __func__, error); @@ -1580,15 +1641,26 @@ iwn_read_eeprom(struct iwn_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) } } + iwn_read_prom_data(sc, IWN_EEPROM_SKU_CAP, &val, 2); + DPRINTF(sc, IWN_DEBUG_RESET, "SKU capabilities=0x%04x\n", le16toh(val)); + /* Check if HT support is bonded out. */ + if (val & htole16(IWN_EEPROM_SKU_CAP_11N)) + sc->sc_flags |= IWN_FLAG_HAS_11N; + iwn_read_prom_data(sc, IWN_EEPROM_RFCFG, &val, 2); sc->rfcfg = le16toh(val); DPRINTF(sc, IWN_DEBUG_RESET, "radio config=0x%04x\n", sc->rfcfg); + /* Read Tx/Rx chains from ROM unless it's known to be broken. */ + if (sc->txchainmask == 0) + sc->txchainmask = IWN_RFCFG_TXANTMSK(sc->rfcfg); + if (sc->rxchainmask == 0) + sc->rxchainmask = IWN_RFCFG_RXANTMSK(sc->rfcfg); /* Read MAC address. */ iwn_read_prom_data(sc, IWN_EEPROM_MAC, macaddr, 6); /* Read adapter-specific information from EEPROM. */ - hal->read_eeprom(sc); + ops->read_eeprom(sc); iwn_apm_stop(sc); /* Power OFF adapter. */ @@ -1600,14 +1672,14 @@ static void iwn4965_read_eeprom(struct iwn_softc *sc) { uint32_t addr; - int i; uint16_t val; + int i; - /* Read regulatory domain (4 ASCII characters.) */ + /* Read regulatory domain (4 ASCII characters). */ iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4); - /* Read the list of authorized channels (20MHz ones only.) */ - for (i = 0; i < 5; i++) { + /* Read the list of authorized channels (20MHz ones only). */ + for (i = 0; i < 7; i++) { addr = iwn4965_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } @@ -1682,20 +1754,23 @@ static void iwn5000_read_eeprom(struct iwn_softc *sc) { struct iwn5000_eeprom_calib_hdr hdr; - int32_t temp, volt; - uint32_t addr, base; - int i; + int32_t volt; + uint32_t base, addr; uint16_t val; + int i; - /* Read regulatory domain (4 ASCII characters.) */ + /* Read regulatory domain (4 ASCII characters). */ iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); base = le16toh(val); iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN, sc->eeprom_domain, 4); - /* Read the list of authorized channels (20MHz ones only.) */ - for (i = 0; i < 5; i++) { - addr = base + iwn5000_regulatory_bands[i]; + /* Read the list of authorized channels (20MHz ones only). */ + for (i = 0; i < 7; i++) { + if (sc->hw_type >= IWN_HW_REV_TYPE_6000) + addr = base + iwn6000_regulatory_bands[i]; + else + addr = base + iwn5000_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } @@ -1707,19 +1782,25 @@ iwn5000_read_eeprom(struct iwn_softc *sc) base = le16toh(val); iwn_read_prom_data(sc, base, &hdr, sizeof hdr); DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "%s: calib version=%u pa type=%u voltage=%u\n", - __func__, hdr.version, hdr.pa_type, le16toh(hdr.volt)); + "%s: calib version=%u pa type=%u voltage=%u\n", __func__, + hdr.version, hdr.pa_type, le16toh(hdr.volt)); sc->calib_ver = hdr.version; if (sc->hw_type == IWN_HW_REV_TYPE_5150) { /* Compute temperature offset. */ iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); - temp = le16toh(val); + sc->eeprom_temp = le16toh(val); iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2); volt = le16toh(val); - sc->temp_off = temp - (volt / -5); + sc->temp_off = sc->eeprom_temp - (volt / -5); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "temp=%d volt=%d offset=%dK\n", - temp, volt, sc->temp_off); + sc->eeprom_temp, volt, sc->temp_off); + } else { + /* Read crystal calibration. */ + iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, + &sc->eeprom_crystal, sizeof (uint32_t)); + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "crystal calibration 0x%08x\n", + le32toh(sc->eeprom_crystal)); } } @@ -1753,7 +1834,8 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c; - int i, chan, nflags; + uint8_t chan; + int i, nflags; for (i = 0; i < band->nchan; i++) { if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID)) { @@ -1766,46 +1848,39 @@ iwn_read_eeprom_band(struct iwn_softc *sc, int n) chan = band->chan[i]; nflags = iwn_eeprom_channel_flags(&channels[i]); - DPRINTF(sc, IWN_DEBUG_RESET, - "add chan %d flags 0x%x maxpwr %d\n", - chan, channels[i].flags, channels[i].maxpwr); - c = &ic->ic_channels[ic->ic_nchans++]; c->ic_ieee = chan; c->ic_maxregpower = channels[i].maxpwr; c->ic_maxpower = 2*c->ic_maxregpower; - /* Save maximum allowed TX power for this channel. */ - sc->maxpwr[chan] = channels[i].maxpwr; - if (n == 0) { /* 2GHz band */ - c->ic_freq = ieee80211_ieee2mhz(chan, - IEEE80211_CHAN_G); - + c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_G); /* G =>'s B is supported */ c->ic_flags = IEEE80211_CHAN_B | nflags; - c = &ic->ic_channels[ic->ic_nchans++]; c[0] = c[-1]; c->ic_flags = IEEE80211_CHAN_G | nflags; } else { /* 5GHz band */ - c->ic_freq = ieee80211_ieee2mhz(chan, - IEEE80211_CHAN_A); + c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); c->ic_flags = IEEE80211_CHAN_A | nflags; - sc->sc_flags |= IWN_FLAG_HAS_5GHZ; } -#if 0 /* HT */ - /* XXX no constraints on using HT20 */ - /* add HT20, HT40 added separately */ - c = &ic->ic_channels[ic->ic_nchans++]; - c[0] = c[-1]; - c->ic_flags |= IEEE80211_CHAN_HT20; - /* XXX NARROW =>'s 1/2 and 1/4 width? */ -#endif + + /* Save maximum allowed TX power for this channel. */ + sc->maxpwr[chan] = channels[i].maxpwr; + + DPRINTF(sc, IWN_DEBUG_RESET, + "add chan %d flags 0x%x maxpwr %d\n", chan, + channels[i].flags, channels[i].maxpwr); + + if (sc->sc_flags & IWN_FLAG_HAS_11N) { + /* add HT20, HT40 added separately */ + c = &ic->ic_channels[ic->ic_nchans++]; + c[0] = c[-1]; + c->ic_flags |= IEEE80211_CHAN_HT20; + } } } -#if 0 /* HT */ static void iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) { @@ -1814,55 +1889,59 @@ iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c, *cent, *extc; - int i; + uint8_t chan; + int i, nflags; + + if (!(sc->sc_flags & IWN_FLAG_HAS_11N)) + return; for (i = 0; i < band->nchan; i++) { - if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID) || - !(channels[i].flags & IWN_EEPROM_CHAN_WIDE)) { + if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID)) { DPRINTF(sc, IWN_DEBUG_RESET, "skip chan %d flags 0x%x maxpwr %d\n", band->chan[i], channels[i].flags, channels[i].maxpwr); continue; } + chan = band->chan[i]; + nflags = iwn_eeprom_channel_flags(&channels[i]); + /* * Each entry defines an HT40 channel pair; find the * center channel, then the extension channel above. */ - cent = ieee80211_find_channel_byieee(ic, band->chan[i], - band->flags & ~IEEE80211_CHAN_HT); + cent = ieee80211_find_channel_byieee(ic, chan, + (n == 5 ? IEEE80211_CHAN_G : IEEE80211_CHAN_A)); if (cent == NULL) { /* XXX shouldn't happen */ device_printf(sc->sc_dev, - "%s: no entry for channel %d\n", - __func__, band->chan[i]); + "%s: no entry for channel %d\n", __func__, chan); continue; } extc = ieee80211_find_channel(ic, cent->ic_freq+20, - band->flags & ~IEEE80211_CHAN_HT); + (n == 5 ? IEEE80211_CHAN_G : IEEE80211_CHAN_A)); if (extc == NULL) { DPRINTF(sc, IWN_DEBUG_RESET, - "skip chan %d, extension channel not found\n", - band->chan[i]); + "%s: skip chan %d, extension channel not found\n", + __func__, chan); continue; } DPRINTF(sc, IWN_DEBUG_RESET, "add ht40 chan %d flags 0x%x maxpwr %d\n", - band->chan[i], channels[i].flags, channels[i].maxpwr); + chan, channels[i].flags, channels[i].maxpwr); c = &ic->ic_channels[ic->ic_nchans++]; c[0] = cent[0]; c->ic_extieee = extc->ic_ieee; c->ic_flags &= ~IEEE80211_CHAN_HT; - c->ic_flags |= IEEE80211_CHAN_HT40U; + c->ic_flags |= IEEE80211_CHAN_HT40U | nflags; c = &ic->ic_channels[ic->ic_nchans++]; c[0] = extc[0]; c->ic_extieee = cent->ic_ieee; c->ic_flags &= ~IEEE80211_CHAN_HT; - c->ic_flags |= IEEE80211_CHAN_HT40D; + c->ic_flags |= IEEE80211_CHAN_HT40D | nflags; } } -#endif static void iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) @@ -1875,31 +1954,86 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) if (n < 5) iwn_read_eeprom_band(sc, n); -#if 0 /* HT */ else iwn_read_eeprom_ht40(sc, n); -#endif ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); } +static struct iwn_eeprom_chan * +iwn_find_eeprom_channel(struct iwn_softc *sc, struct ieee80211_channel *c) +{ + int band, chan, i, j; + + if (IEEE80211_IS_CHAN_HT40(c)) { + band = IEEE80211_IS_CHAN_5GHZ(c) ? 6 : 5; + if (IEEE80211_IS_CHAN_HT40D(c)) + chan = c->ic_extieee; + else + chan = c->ic_ieee; + for (i = 0; i < iwn_bands[band].nchan; i++) { + if (iwn_bands[band].chan[i] == chan) + return &sc->eeprom_channels[band][i]; + } + } else { + for (j = 0; j < 5; j++) { + for (i = 0; i < iwn_bands[j].nchan; i++) { + if (iwn_bands[j].chan[i] == c->ic_ieee) + return &sc->eeprom_channels[j][i]; + } + } + } + return NULL; +} + +/* + * Enforce flags read from EEPROM. + */ +static int +iwn_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, + int nchan, struct ieee80211_channel chans[]) +{ + struct iwn_softc *sc = ic->ic_ifp->if_softc; + int i; + + for (i = 0; i < nchan; i++) { + struct ieee80211_channel *c = &chans[i]; + struct iwn_eeprom_chan *channel; + + channel = iwn_find_eeprom_channel(sc, c); + if (channel == NULL) { + if_printf(ic->ic_ifp, + "%s: invalid channel %u freq %u/0x%x\n", + __func__, c->ic_ieee, c->ic_freq, c->ic_flags); + return EINVAL; + } + c->ic_flags |= iwn_eeprom_channel_flags(channel); + } + + return 0; +} + #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) static void iwn_read_eeprom_enhinfo(struct iwn_softc *sc) { struct iwn_eeprom_enhinfo enhinfo[35]; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211_channel *c; uint16_t val, base; int8_t maxpwr; - int i; + uint8_t flags; + int i, j; iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); base = le16toh(val); iwn_read_prom_data(sc, base + IWN6000_EEPROM_ENHINFO, enhinfo, sizeof enhinfo); - memset(sc->enh_maxpwr, 0, sizeof sc->enh_maxpwr); for (i = 0; i < nitems(enhinfo); i++) { - if (enhinfo[i].chan == 0 || enhinfo[i].reserved != 0) + flags = enhinfo[i].flags; + if (!(flags & IWN_ENHINFO_VALID)) continue; /* Skip invalid entries. */ maxpwr = 0; @@ -1913,11 +2047,34 @@ iwn_read_eeprom_enhinfo(struct iwn_softc *sc) maxpwr = MAX(maxpwr, enhinfo[i].mimo2); else if (sc->ntxchains == 3) maxpwr = MAX(maxpwr, enhinfo[i].mimo3); - maxpwr /= 2; /* Convert half-dBm to dBm. */ - DPRINTF(sc, IWN_DEBUG_RESET, "enhinfo %d, maxpwr=%d\n", i, - maxpwr); - sc->enh_maxpwr[i] = maxpwr; + for (j = 0; j < ic->ic_nchans; j++) { + c = &ic->ic_channels[j]; + if ((flags & IWN_ENHINFO_5GHZ)) { + if (!IEEE80211_IS_CHAN_A(c)) + continue; + } else if ((flags & IWN_ENHINFO_OFDM)) { + if (!IEEE80211_IS_CHAN_G(c)) + continue; + } else if (!IEEE80211_IS_CHAN_B(c)) + continue; + if ((flags & IWN_ENHINFO_HT40)) { + if (!IEEE80211_IS_CHAN_HT40(c)) + continue; + } else { + if (IEEE80211_IS_CHAN_HT40(c)) + continue; + } + if (enhinfo[i].chan != 0 && + enhinfo[i].chan != c->ic_ieee) + continue; + + DPRINTF(sc, IWN_DEBUG_RESET, + "channel %d(%x), maxpwr %d\n", c->ic_ieee, + c->ic_flags, maxpwr / 2); + c->ic_maxregpower = maxpwr / 2; + c->ic_maxpower = maxpwr; + } } } @@ -1927,10 +2084,82 @@ iwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) return malloc(sizeof (struct iwn_node), M_80211_NODE,M_NOWAIT | M_ZERO); } +static __inline int +rate2plcp(int rate) +{ + switch (rate & 0xff) { + case 12: return 0xd; + case 18: return 0xf; + case 24: return 0x5; + case 36: return 0x7; + case 48: return 0x9; + case 72: return 0xb; + case 96: return 0x1; + case 108: return 0x3; + case 2: return 10; + case 4: return 20; + case 11: return 55; + case 22: return 110; + } + return 0; +} + +static void +iwn_newassoc(struct ieee80211_node *ni, int isnew) +{ +#define RV(v) ((v) & IEEE80211_RATE_VAL) + struct ieee80211com *ic = ni->ni_ic; + struct iwn_softc *sc = ic->ic_ifp->if_softc; + struct iwn_node *wn = (void *)ni; + uint8_t txant1, txant2; + int i, plcp, rate, ridx; + + /* Use the first valid TX antenna. */ + txant1 = IWN_LSB(sc->txchainmask); + txant2 = IWN_LSB(sc->txchainmask & ~txant1); + + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + ridx = ni->ni_rates.rs_nrates - 1; + for (i = ni->ni_htrates.rs_nrates - 1; i >= 0; i--) { + plcp = RV(ni->ni_htrates.rs_rates[i]) | IWN_RFLAG_MCS; + if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + plcp |= IWN_RFLAG_HT40; + if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) + plcp |= IWN_RFLAG_SGI; + } else if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) + plcp |= IWN_RFLAG_SGI; + if (i > 7) + plcp |= IWN_RFLAG_ANT(txant1 | txant2); + else + plcp |= IWN_RFLAG_ANT(txant1); + if (ridx >= 0) { + rate = RV(ni->ni_rates.rs_rates[ridx]); + wn->ridx[rate] = plcp; + } + wn->ridx[IEEE80211_RATE_MCS | i] = plcp; + ridx--; + } + } else { + for (i = 0; i < ni->ni_rates.rs_nrates; i++) { + rate = RV(ni->ni_rates.rs_rates[i]); + plcp = rate2plcp(rate); + ridx = ic->ic_rt->rateCodeToIndex[rate]; + if (ridx < IWN_RIDX_OFDM6 && + IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + plcp |= IWN_RFLAG_CCK; + plcp |= IWN_RFLAG_ANT(txant1); + wn->ridx[rate] = htole32(plcp); + } + } +#undef RV +} + static int iwn_media_change(struct ifnet *ifp) { - int error = ieee80211_media_change(ifp); + int error; + + error = ieee80211_media_change(ifp); /* NB: only the fixed rate can change and that doesn't need a reset */ return (error == ENETRESET ? 0 : error); } @@ -1941,15 +2170,14 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct iwn_vap *ivp = IWN_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct iwn_softc *sc = ic->ic_ifp->if_softc; - int error; + int error = 0; DPRINTF(sc, IWN_DEBUG_STATE, "%s: %s -> %s\n", __func__, - ieee80211_state_name[vap->iv_state], - ieee80211_state_name[nstate]); + ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); IEEE80211_UNLOCK(ic); IWN_LOCK(sc); - callout_stop(&sc->sc_timer_to); + callout_stop(&sc->calib_to); switch (nstate) { case IEEE80211_S_ASSOC: @@ -1966,17 +2194,20 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) */ sc->rxon.associd = 0; sc->rxon.filter &= ~htole32(IWN_FILTER_BSS); - iwn_calib_reset(sc); - error = iwn_auth(sc, vap); + sc->calib.state = IWN_CALIB_STATE_INIT; + + if ((error = iwn_auth(sc, vap)) != 0) { + device_printf(sc->sc_dev, + "%s: could not move to auth state\n", __func__); + } break; case IEEE80211_S_RUN: /* * RUN -> RUN transition; Just restart the timers. */ - if (vap->iv_state == IEEE80211_S_RUN && - vap->iv_opmode != IEEE80211_M_MONITOR) { - iwn_calib_reset(sc); + if (vap->iv_state == IEEE80211_S_RUN) { + sc->calib_cnt = 0; break; } @@ -1985,7 +2216,14 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * which is done with a firmware cmd. We also defer * starting the timers until that work is done. */ - error = iwn_run(sc, vap); + if ((error = iwn_run(sc, vap)) != 0) { + device_printf(sc->sc_dev, + "%s: could not move to run state\n", __func__); + } + break; + + case IEEE80211_S_INIT: + sc->calib.state = IWN_CALIB_STATE_INIT; break; default: @@ -1993,9 +2231,32 @@ iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) } IWN_UNLOCK(sc); IEEE80211_LOCK(ic); + if (error != 0) + return error; return ivp->iv_newstate(vap, nstate, arg); } +static void +iwn_calib_timeout(void *arg) +{ + struct iwn_softc *sc = arg; + + IWN_LOCK_ASSERT(sc); + + /* Force automatic TX power calibration every 60 secs. */ + if (++sc->calib_cnt >= 120) { + uint32_t flags = 0; + + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s\n", + "sending request for statistics"); + (void)iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, + sizeof flags, 1); + sc->calib_cnt = 0; + } + callout_reset(&sc->calib_to, msecs_to_ticks(500), iwn_calib_timeout, + sc); +} + /* * Process an RX_PHY firmware notification. This is usually immediately * followed by an MPDU_RX_DONE notification. @@ -2014,32 +2275,6 @@ iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc, sc->last_rx_valid = 1; } -static void -iwn_timer_timeout(void *arg) -{ - struct iwn_softc *sc = arg; - uint32_t flags = 0; - - IWN_LOCK_ASSERT(sc); - - if (sc->calib_cnt && --sc->calib_cnt == 0) { - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s\n", - "send statistics request"); - (void) iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, - sizeof flags, 1); - sc->calib_cnt = 60; /* do calibration every 60s */ - } - iwn_watchdog(sc); /* NB: piggyback tx watchdog */ - callout_reset(&sc->sc_timer_to, hz, iwn_timer_timeout, sc); -} - -static void -iwn_calib_reset(struct iwn_softc *sc) -{ - callout_reset(&sc->sc_timer_to, hz, iwn_timer_timeout, sc); - sc->calib_cnt = 60; /* do calibration every 60s */ -} - /* * Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification. * Each MPDU_RX_DONE notification must be preceded by an RX_PHY one. @@ -2048,7 +2283,7 @@ static void iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct iwn_rx_ring *ring = &sc->rxq; @@ -2066,10 +2301,8 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, if (!sc->last_rx_valid) { DPRINTF(sc, IWN_DEBUG_ANY, "%s: missing RX_PHY\n", __func__); - ifp->if_ierrors++; return; } - sc->last_rx_valid = 0; stat = &sc->last_rx_stat; } else stat = (struct iwn_rx_stat *)(desc + 1); @@ -2078,9 +2311,8 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, if (stat->cfg_phy_len > IWN_STAT_MAXLEN) { device_printf(sc->sc_dev, - "%s: invalid rx statistic header, len %d\n", - __func__, stat->cfg_phy_len); - ifp->if_ierrors++; + "%s: invalid RX statistic header, len %d\n", __func__, + stat->cfg_phy_len); return; } if (desc->type == IWN_MPDU_RX_DONE) { @@ -2096,7 +2328,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, /* Discard frames with a bad FCS early. */ if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) { - DPRINTF(sc, IWN_DEBUG_RECV, "%s: rx flags error %x\n", + DPRINTF(sc, IWN_DEBUG_RECV, "%s: RX flags error %x\n", __func__, flags); ifp->if_ierrors++; return; @@ -2109,8 +2341,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, return; } - /* XXX don't need mbuf, just dma buffer */ - m1 = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + m1 = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, IWN_RBUF_SIZE); if (m1 == NULL) { DPRINTF(sc, IWN_DEBUG_ANY, "%s: no mbuf to restock ring\n", __func__); @@ -2119,13 +2350,24 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, } bus_dmamap_unload(ring->data_dmat, data->map); - error = bus_dmamap_load(ring->data_dmat, data->map, - mtod(m1, caddr_t), MJUMPAGESIZE, - iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); + error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m1, void *), + IWN_RBUF_SIZE, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { device_printf(sc->sc_dev, "%s: bus_dmamap_load failed, error %d\n", __func__, error); m_freem(m1); + + /* Try to reload the old mbuf. */ + error = bus_dmamap_load(ring->data_dmat, data->map, + mtod(data->m, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, + &paddr, BUS_DMA_NOWAIT); + if (error != 0 && error != EFBIG) { + panic("%s: could not load old RX mbuf", __func__); + } + /* Physical address may have changed. */ + ring->desc[ring->cur] = htole32(paddr >> 8); + bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, + BUS_DMASYNC_PREWRITE); ifp->if_ierrors++; return; } @@ -2142,21 +2384,23 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, m->m_data = head; m->m_pkthdr.len = m->m_len = len; - rssi = hal->get_rssi(sc, stat); - /* Grab a reference to the source node. */ wh = mtod(m, struct ieee80211_frame *); ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); nf = (ni != NULL && ni->ni_vap->iv_state == IEEE80211_S_RUN && (ic->ic_flags & IEEE80211_F_SCAN) == 0) ? sc->noise : -95; + rssi = ops->get_rssi(sc, stat); + if (ieee80211_radiotap_active(ic)) { struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap; - tap->wr_tsft = htole64(stat->tstamp); tap->wr_flags = 0; if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + tap->wr_dbm_antsignal = (int8_t)rssi; + tap->wr_dbm_antnoise = (int8_t)nf; + tap->wr_tsft = stat->tstamp; switch (stat->rate) { /* CCK rates. */ case 10: tap->wr_rate = 2; break; @@ -2175,36 +2419,130 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, /* Unknown rate: should not happen. */ default: tap->wr_rate = 0; } - tap->wr_dbm_antsignal = rssi; - tap->wr_dbm_antnoise = nf; } IWN_UNLOCK(sc); /* Send the frame to the 802.11 layer. */ if (ni != NULL) { - (void) ieee80211_input(ni, m, rssi - nf, nf); + if (ni->ni_flags & IEEE80211_NODE_HT) + m->m_flags |= M_AMPDU; + (void)ieee80211_input(ni, m, rssi - nf, nf); /* Node is no longer needed. */ ieee80211_free_node(ni); } else - (void) ieee80211_input_all(ic, m, rssi - nf, nf); + (void)ieee80211_input_all(ic, m, rssi - nf, nf); IWN_LOCK(sc); } -#if 0 /* HT */ /* Process an incoming Compressed BlockAck. */ static void iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { + struct ifnet *ifp = sc->sc_ifp; + struct iwn_node *wn; + struct ieee80211_node *ni; struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1); struct iwn_tx_ring *txq; + struct ieee80211_tx_ampdu *tap; + uint64_t bitmap; + uint8_t tid; + int ackfailcnt = 0, i, shift; - txq = &sc->txq[letoh16(ba->qid)]; - /* XXX TBD */ + bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); + + txq = &sc->txq[le16toh(ba->qid)]; + tap = sc->qid2tap[le16toh(ba->qid)]; + tid = WME_AC_TO_TID(tap->txa_ac); + ni = tap->txa_ni; + wn = (void *)ni; + + if (wn->agg[tid].bitmap == 0) + return; + + shift = wn->agg[tid].startidx - ((le16toh(ba->seq) >> 4) & 0xff); + if (shift < 0) + shift += 0x100; + + if (wn->agg[tid].nframes > (64 - shift)) + return; + + bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap; + for (i = 0; bitmap; i++) { + if ((bitmap & 1) == 0) { + ifp->if_oerrors++; + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); + } else { + ifp->if_opackets++; + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); + } + bitmap >>= 1; + } +} + +/* + * Process a CALIBRATION_RESULT notification sent by the initialization + * firmware on response to a CMD_CALIB_CONFIG command (5000 only). + */ +static void +iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) +{ + struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); + int len, idx = -1; + + /* Runtime firmware should not send such a notification. */ + if (sc->sc_flags & IWN_FLAG_CALIB_DONE) + return; + + len = (le32toh(desc->len) & 0x3fff) - 4; + bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); + + switch (calib->code) { + case IWN5000_PHY_CALIB_DC: + if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0 && + (sc->hw_type == IWN_HW_REV_TYPE_5150 || + sc->hw_type >= IWN_HW_REV_TYPE_6000) && + sc->hw_type != IWN_HW_REV_TYPE_6050) + idx = 0; + break; + case IWN5000_PHY_CALIB_LO: + idx = 1; + break; + case IWN5000_PHY_CALIB_TX_IQ: + idx = 2; + break; + case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: + if (sc->hw_type < IWN_HW_REV_TYPE_6000 && + sc->hw_type != IWN_HW_REV_TYPE_5150) + idx = 3; + break; + case IWN5000_PHY_CALIB_BASE_BAND: + idx = 4; + break; + } + if (idx == -1) /* Ignore other results. */ + return; + + /* Save calibration result. */ + if (sc->calibcmd[idx].buf != NULL) + free(sc->calibcmd[idx].buf, M_DEVBUF); + sc->calibcmd[idx].buf = malloc(len, M_DEVBUF, M_NOWAIT); + if (sc->calibcmd[idx].buf == NULL) { + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "not enough memory for calibration result %d\n", + calib->code); + return; + } + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "saving calibration result code=%d len=%d\n", calib->code, len); + sc->calibcmd[idx].len = len; + memcpy(sc->calibcmd[idx].buf, calib, len); } -#endif /* * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. @@ -2214,7 +2552,7 @@ static void iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); @@ -2222,24 +2560,26 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); int temp; - /* Beacon stats are meaningful only when associated and not scanning. */ + /* Ignore statistics received during a scan. */ if (vap->iv_state != IEEE80211_S_RUN || (ic->ic_flags & IEEE80211_F_SCAN)) return; bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: cmd %d\n", __func__, desc->type); - iwn_calib_reset(sc); /* Reset TX power calibration timeout. */ + + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received statistics, cmd %d\n", + __func__, desc->type); + sc->calib_cnt = 0; /* Reset TX power calibration timeout. */ /* Test if temperature has changed. */ if (stats->general.temp != sc->rawtemp) { /* Convert "raw" temperature to degC. */ sc->rawtemp = stats->general.temp; - temp = hal->get_temperature(sc); + temp = ops->get_temperature(sc); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: temperature %d\n", __func__, temp); - /* Update TX power if need be (4965AGN only.) */ + /* Update TX power if need be (4965AGN only). */ if (sc->hw_type == IWN_HW_REV_TYPE_4965) iwn4965_power_calibration(sc, temp); } @@ -2272,7 +2612,11 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1); - struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; + struct iwn_tx_ring *ring; + int qid; + + qid = desc->qid & 0xf; + ring = &sc->txq[qid]; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: " "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n", @@ -2281,7 +2625,13 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, le32toh(stat->status)); bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); - iwn_tx_done(sc, desc, stat->ackfailcnt, le32toh(stat->status) & 0xff); + if (qid >= sc->firstaggqueue) { + iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes, + &stat->status); + } else { + iwn_tx_done(sc, desc, stat->ackfailcnt, + le32toh(stat->status) & 0xff); + } } static void @@ -2289,7 +2639,11 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1); - struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; + struct iwn_tx_ring *ring; + int qid; + + qid = desc->qid & 0xf; + ring = &sc->txq[qid]; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: " "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n", @@ -2303,7 +2657,13 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, #endif bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); - iwn_tx_done(sc, desc, stat->ackfailcnt, le16toh(stat->status) & 0xff); + if (qid >= sc->firstaggqueue) { + iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes, + &stat->status); + } else { + iwn_tx_done(sc, desc, stat->ackfailcnt, + le16toh(stat->status) & 0xff); + } } /* @@ -2355,11 +2715,12 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, /* * Update rate control statistics for the node. */ - if (status & 0x80) { + if (status & IWN_TX_FAIL) { ifp->if_oerrors++; ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { + ifp->if_opackets++; ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } @@ -2394,6 +2755,8 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) /* If the command was mapped in an mbuf, free it. */ if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; @@ -2401,12 +2764,103 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) wakeup(&ring->desc[desc->idx]); } +static void +iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, + void *stat) +{ + struct ifnet *ifp = sc->sc_ifp; + struct iwn_tx_ring *ring = &sc->txq[qid]; + struct iwn_tx_data *data; + struct mbuf *m; + struct iwn_node *wn; + struct ieee80211_node *ni; + struct ieee80211vap *vap; + struct ieee80211_tx_ampdu *tap; + uint64_t bitmap; + uint32_t *status = stat; + uint16_t *aggstatus = stat; + uint8_t tid; + int bit, i, lastidx, seqno, shift, start; + +#ifdef NOT_YET + if (nframes == 1) { + if ((*status & 0xff) != 1 && (*status & 0xff) != 2) + printf("ieee80211_send_bar()\n"); + } +#endif + + bitmap = 0; + start = idx; + for (i = 0; i < nframes; i++) { + if (le16toh(aggstatus[i * 2]) & 0xc) + continue; + + idx = le16toh(aggstatus[2*i + 1]) & 0xff; + bit = idx - start; + shift = 0; + if (bit >= 64) { + shift = 0x100 - idx + start; + bit = 0; + start = idx; + } else if (bit <= -64) + bit = 0x100 - start + idx; + else if (bit < 0) { + shift = start - idx; + start = idx; + bit = 0; + } + bitmap = bitmap << shift; + bitmap |= 1ULL << bit; + } + tap = sc->qid2tap[qid]; + tid = WME_AC_TO_TID(tap->txa_ac); + wn = (void *)tap->txa_ni; + wn->agg[tid].bitmap = bitmap; + wn->agg[tid].startidx = start; + wn->agg[tid].nframes = nframes; + + seqno = le32toh(*(status + nframes)) & 0xfff; + for (lastidx = (seqno & 0xff); ring->read != lastidx;) { + data = &ring->data[ring->read]; + + KASSERT(data->ni != NULL, ("no node")); + + /* Unmap and free mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m = data->m, data->m = NULL; + ni = data->ni, data->ni = NULL; + vap = ni->ni_vap; + + if (m->m_flags & M_TXCB) + ieee80211_process_callback(ni, m, 1); + + m_freem(m); + ieee80211_free_node(ni); + + ring->queued--; + ring->read = (ring->read + 1) % IWN_TX_RING_COUNT; + } + + sc->sc_tx_timer = 0; + if (ring->queued < IWN_TX_RING_LOMARK) { + sc->qfullmsk &= ~(1 << ring->qid); + if (sc->qfullmsk == 0 && + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + iwn_start_locked(ifp); + } + } +} + /* * Process an INT_FH_RX or INT_SW_RX interrupt. */ static void iwn_notif_intr(struct iwn_softc *sc) { + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); @@ -2444,16 +2898,14 @@ iwn_notif_intr(struct iwn_softc *sc) iwn_rx_done(sc, desc, data); break; -#if 0 /* HT */ case IWN_RX_COMPRESSED_BA: /* A Compressed BlockAck has been received. */ iwn_rx_compressed_ba(sc, desc, data); break; -#endif case IWN_TX_DONE: /* An 802.11 frame has been transmitted. */ - sc->sc_hal->tx_done(sc, desc, data); + ops->tx_done(sc, desc, data); break; case IWN_RX_STATISTICS: @@ -2471,23 +2923,22 @@ iwn_notif_intr(struct iwn_softc *sc) BUS_DMASYNC_POSTREAD); misses = le32toh(miss->consecutive); - /* XXX not sure why we're notified w/ zero */ - if (misses == 0) - break; DPRINTF(sc, IWN_DEBUG_STATE, "%s: beacons missed %d/%d\n", __func__, misses, le32toh(miss->total)); - /* * If more than 5 consecutive beacons are missed, * reinitialize the sensitivity state machine. */ - if (vap->iv_state == IEEE80211_S_RUN && misses > 5) - (void) iwn_init_sensitivity(sc); - if (misses >= vap->iv_bmissthreshold) { - IWN_UNLOCK(sc); - ieee80211_beacon_miss(ic); - IWN_LOCK(sc); + if (vap->iv_state == IEEE80211_S_RUN && + (ic->ic_flags & IEEE80211_F_SCAN) == 0) { + if (misses > 5) + (void)iwn_init_sensitivity(sc); + if (misses >= vap->iv_bmissthreshold) { + IWN_UNLOCK(sc); + ieee80211_beacon_miss(ic); + IWN_LOCK(sc); + } } break; } @@ -2561,7 +3012,7 @@ iwn_notif_intr(struct iwn_softc *sc) break; } case IWN5000_CALIBRATION_RESULT: - iwn5000_rx_calib_result(sc, desc, data); + iwn5000_rx_calib_results(sc, desc, data); break; case IWN5000_CALIBRATION_DONE: @@ -2592,7 +3043,7 @@ iwn_wakeup_intr(struct iwn_softc *sc) /* Wakeup RX and TX rings. */ IWN_WRITE(sc, IWN_FH_RX_WPTR, sc->rxq.cur & ~7); - for (qid = 0; qid < sc->sc_hal->ntxqs; qid++) { + for (qid = 0; qid < sc->ntxqs; qid++) { struct iwn_tx_ring *ring = &sc->txq[qid]; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | ring->cur); } @@ -2623,7 +3074,6 @@ iwn_rftoggle_intr(struct iwn_softc *sc) static void iwn_fatal_intr(struct iwn_softc *sc) { - const struct iwn_hal *hal = sc->sc_hal; struct iwn_fw_dump dump; int i; @@ -2635,14 +3085,13 @@ iwn_fatal_intr(struct iwn_softc *sc) /* Check that the error log address is valid. */ if (sc->errptr < IWN_FW_DATA_BASE || sc->errptr + sizeof (dump) > - IWN_FW_DATA_BASE + hal->fw_data_maxsz) { - printf("%s: bad firmware error log address 0x%08x\n", - __func__, sc->errptr); + IWN_FW_DATA_BASE + sc->fw_data_maxsz) { + printf("%s: bad firmware error log address 0x%08x\n", __func__, + sc->errptr); return; } if (iwn_nic_lock(sc) != 0) { - printf("%s: could not read firmware error log\n", - __func__); + printf("%s: could not read firmware error log\n", __func__); return; } /* Read firmware error log from SRAM. */ @@ -2651,8 +3100,7 @@ iwn_fatal_intr(struct iwn_softc *sc) iwn_nic_unlock(sc); if (dump.valid == 0) { - printf("%s: firmware error log is empty\n", - __func__); + printf("%s: firmware error log is empty\n", __func__); return; } printf("firmware error log:\n"); @@ -2672,7 +3120,7 @@ iwn_fatal_intr(struct iwn_softc *sc) /* Dump driver status (TX and RX rings) while we're here. */ printf("driver status:\n"); - for (i = 0; i < hal->ntxqs; i++) { + for (i = 0; i < sc->ntxqs; i++) { struct iwn_tx_ring *ring = &sc->txq[i]; printf(" tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); @@ -2738,6 +3186,9 @@ iwn_intr(void *arg) __func__); } if (r1 & (IWN_INT_SW_ERR | IWN_INT_HW_ERR)) { + device_printf(sc->sc_dev, "%s: fatal firmware error\n", + __func__); + /* Dump firmware error log and stop. */ iwn_fatal_intr(sc); ifp->if_flags &= ~IFF_UP; iwn_stop_locked(sc); @@ -2781,7 +3232,7 @@ done: /* * Update TX scheduler ring when transmitting an 802.11 frame (4965AGN and - * 5000 adapters use a slightly different format.) + * 5000 adapters use a slightly different format). */ static void iwn4965_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id, @@ -2806,7 +3257,6 @@ iwn5000_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id, uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx]; *w = htole16(id << 12 | (len + 8)); - bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { @@ -2833,40 +3283,28 @@ iwn5000_reset_sched(struct iwn_softc *sc, int qid, int idx) } #endif -static uint8_t -iwn_plcp_signal(int rate) { - int i; - - for (i = 0; i < IWN_RIDX_MAX + 1; i++) { - if (rate == iwn_rates[i].rate) - return i; - } - - return 0; -} - static int -iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, - struct iwn_tx_ring *ring) +iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; const struct ieee80211_txparam *tp; - const struct iwn_rate *rinfo; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct iwn_node *wn = (void *)ni; + struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; - struct mbuf *mnew; - bus_dma_segment_t segs[IWN_MAX_SCATTER]; + struct mbuf *m1; uint32_t flags; + uint16_t qos; u_int hdrlen; - int totlen, error, pad, nsegs = 0, i, rate; - uint8_t ridx, type, txant; + bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; + uint8_t tid, ridx, txant, type; + int ac, i, totlen, error, pad, nsegs = 0, rate; IWN_LOCK_ASSERT(sc); @@ -2874,6 +3312,27 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + /* Select EDCA Access Category and TX ring for this frame. */ + if (IEEE80211_QOS_HAS_SEQ(wh)) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + ac = M_WME_GETAC(m); + + if (IEEE80211_QOS_HAS_SEQ(wh) && + IEEE80211_AMPDU_RUNNING(&ni->ni_tx_ampdu[ac])) { + struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; + + ring = &sc->txq[*(int *)tap->txa_private]; + *(uint16_t *)wh->i_seq = + htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); + ni->ni_txseqs[tid]++; + } else { + ring = &sc->txq[ac]; + } desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; @@ -2890,17 +3349,17 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, (void) ieee80211_ratectl_rate(ni, NULL, 0); rate = ni->ni_txrate; } - ridx = iwn_plcp_signal(rate); - rinfo = &iwn_rates[ridx]; + ridx = ic->ic_rt->rateCodeToIndex[rate]; /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + /* Retrieve key for TX. */ k = ieee80211_crypto_encap(ni, m); if (k == NULL) { m_freem(m); return ENOBUFS; } - /* Packet header may have moved, reset our local pointer. */ + /* 802.11 header may have moved. */ wh = mtod(m, struct ieee80211_frame *); } totlen = m->m_pkthdr.len; @@ -2909,7 +3368,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rinfo->rate; + tap->wt_rate = rate; if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; @@ -2928,8 +3387,12 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, tx->scratch = 0; /* clear "scratch" area */ flags = 0; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) - flags |= IWN_TX_NEED_ACK; + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) + flags |= IWN_TX_NEED_ACK; + } if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR)) @@ -2962,7 +3425,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) - tx->id = hal->broadcast_id; + tx->id = sc->broadcast_id; else tx->id = wn->id; @@ -2972,7 +3435,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, /* Tell HW to set timestamp in probe responses. */ if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) flags |= IWN_TX_INSERT_TSTAMP; - if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) tx->timeout = htole16(3); @@ -2989,23 +3451,21 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, pad = 0; tx->len = htole16(totlen); - tx->tid = 0; + tx->tid = tid; tx->rts_ntries = 60; tx->data_ntries = 15; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - tx->plcp = rinfo->plcp; - tx->rflags = rinfo->flags; - if (tx->id == hal->broadcast_id) { + tx->rate = wn->ridx[rate]; + if (tx->id == sc->broadcast_id) { /* Group or management frame. */ tx->linkq = 0; /* XXX Alternate between antenna A and B? */ txant = IWN_LSB(sc->txchainmask); - tx->rflags |= IWN_RFLAG_ANT(txant); + tx->rate |= htole32(IWN_RFLAG_ANT(txant)); } else { - tx->linkq = IWN_RIDX_OFDM54 - ridx; + tx->linkq = ni->ni_rates.rs_nrates - ridx - 1; flags |= IWN_TX_LINKQ; /* enable MRR */ } - /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); @@ -3018,26 +3478,30 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, tx->security = 0; tx->flags = htole32(flags); - if (m->m_len > 0) { - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, - m, segs, &nsegs, BUS_DMA_NOWAIT); - if (error == EFBIG) { - /* too many fragments, linearize */ - mnew = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER); - if (mnew == NULL) { - device_printf(sc->sc_dev, - "%s: could not defrag mbuf\n", __func__); - m_freem(m); - return ENOBUFS; - } - m = mnew; - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, - data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + if (error != EFBIG) { + device_printf(sc->sc_dev, + "%s: can't map mbuf (error %d)\n", __func__, error); + m_freem(m); + return error; } + /* Too many DMA segments, linearize mbuf. */ + m1 = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER); + if (m1 == NULL) { + device_printf(sc->sc_dev, + "%s: could not defrag mbuf\n", __func__); + m_freem(m); + return ENOBUFS; + } + m = m1; + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, + segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, - "%s: bus_dmamap_load_mbuf_sg failed, error %d\n", - __func__, error); + "%s: can't map mbuf (error %d)\n", __func__, error); m_freem(m); return error; } @@ -3050,16 +3514,20 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs); /* Fill TX descriptor. */ - desc->nsegs = 1 + nsegs; + desc->nsegs = 1; + if (m->m_len != 0) + desc->nsegs += nsegs; /* First DMA segment is used by the TX command. */ desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr)); desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) | (4 + sizeof (*tx) + hdrlen + pad) << 4); /* Other DMA segments are for data payload. */ + seg = &segs[0]; for (i = 1; i <= nsegs; i++) { - desc->segs[i].addr = htole32(IWN_LOADDR(segs[i - 1].ds_addr)); - desc->segs[i].len = htole16(IWN_HIADDR(segs[i - 1].ds_addr) | - segs[i - 1].ds_len << 4); + desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr)); + desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) | + seg->ds_len << 4); + seg++; } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); @@ -3068,10 +3536,9 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); -#ifdef notyet /* Update TX scheduler. */ - hal->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); -#endif + if (ring->qid >= sc->firstaggqueue) + ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; @@ -3086,25 +3553,23 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, static int iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, - struct ieee80211_node *ni, struct iwn_tx_ring *ring, - const struct ieee80211_bpf_params *params) + struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { - const struct iwn_hal *hal = sc->sc_hal; - const struct iwn_rate *rinfo; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ifp->if_l2com; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; + struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; - struct mbuf *mnew; - bus_addr_t paddr; - bus_dma_segment_t segs[IWN_MAX_SCATTER]; + struct mbuf *m1; + bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; uint32_t flags; u_int hdrlen; - int totlen, error, pad, nsegs = 0, i, rate; + int ac, totlen, error, pad, nsegs = 0, i, rate; uint8_t ridx, type, txant; IWN_LOCK_ASSERT(sc); @@ -3113,18 +3578,20 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + ac = params->ibp_pri & 3; + + ring = &sc->txq[ac]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; /* Choose a TX rate index. */ rate = params->ibp_rate0; - if (!ieee80211_isratevalid(ic->ic_rt, rate)) { + ridx = ic->ic_rt->rateCodeToIndex[rate]; + if (ridx == (uint8_t)-1) { /* XXX fall back to mcast/mgmt rate? */ m_freem(m); return EINVAL; } - ridx = iwn_plcp_signal(rate); - rinfo = &iwn_rates[ridx]; totlen = m->m_pkthdr.len; @@ -3161,6 +3628,7 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, if (type == IEEE80211_FC0_TYPE_MGT) { uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + /* Tell HW to set timestamp in probe responses. */ if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) flags |= IWN_TX_INSERT_TSTAMP; @@ -3190,20 +3658,21 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, tx->len = htole16(totlen); tx->tid = 0; - tx->id = hal->broadcast_id; + tx->id = sc->broadcast_id; tx->rts_ntries = params->ibp_try1; tx->data_ntries = params->ibp_try0; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - tx->plcp = rinfo->plcp; - tx->rflags = rinfo->flags; + tx->rate = htole32(rate2plcp(rate)); + if (ridx < IWN_RIDX_OFDM6 && + IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + tx->rate |= htole32(IWN_RFLAG_CCK); /* Group or management frame. */ tx->linkq = 0; txant = IWN_LSB(sc->txchainmask); - tx->rflags |= IWN_RFLAG_ANT(txant); + tx->rate |= htole32(IWN_RFLAG_ANT(txant)); /* Set physical address of "scratch area". */ - paddr = ring->cmd_dma.paddr + ring->cur * sizeof (struct iwn_tx_cmd); - tx->loaddr = htole32(IWN_LOADDR(paddr)); - tx->hiaddr = IWN_HIADDR(paddr); + tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); + tx->hiaddr = IWN_HIADDR(data->scratch_paddr); /* Copy 802.11 header in TX command. */ memcpy((uint8_t *)(tx + 1), wh, hdrlen); @@ -3213,26 +3682,30 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, tx->security = 0; tx->flags = htole32(flags); - if (m->m_len > 0) { - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, - m, segs, &nsegs, BUS_DMA_NOWAIT); - if (error == EFBIG) { - /* Too many fragments, linearize. */ - mnew = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER); - if (mnew == NULL) { - device_printf(sc->sc_dev, - "%s: could not defrag mbuf\n", __func__); - m_freem(m); - return ENOBUFS; - } - m = mnew; - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, - data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + if (error != EFBIG) { + device_printf(sc->sc_dev, + "%s: can't map mbuf (error %d)\n", __func__, error); + m_freem(m); + return error; } + /* Too many DMA segments, linearize mbuf. */ + m1 = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER); + if (m1 == NULL) { + device_printf(sc->sc_dev, + "%s: could not defrag mbuf\n", __func__); + m_freem(m); + return ENOBUFS; + } + m = m1; + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, + segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, - "%s: bus_dmamap_load_mbuf_sg failed, error %d\n", - __func__, error); + "%s: can't map mbuf (error %d)\n", __func__, error); m_freem(m); return error; } @@ -3245,16 +3718,20 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs); /* Fill TX descriptor. */ - desc->nsegs = 1 + nsegs; + desc->nsegs = 1; + if (m->m_len != 0) + desc->nsegs += nsegs; /* First DMA segment is used by the TX command. */ desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr)); desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) | (4 + sizeof (*tx) + hdrlen + pad) << 4); /* Other DMA segments are for data payload. */ + seg = &segs[0]; for (i = 1; i <= nsegs; i++) { - desc->segs[i].addr = htole32(IWN_LOADDR(segs[i - 1].ds_addr)); - desc->segs[i].len = htole16(IWN_HIADDR(segs[i - 1].ds_addr) | - segs[i - 1].ds_len << 4); + desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr)); + desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) | + seg->ds_len << 4); + seg++; } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); @@ -3263,10 +3740,9 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); -#ifdef notyet /* Update TX scheduler. */ - hal->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); -#endif + if (ring->qid >= sc->firstaggqueue) + ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; @@ -3281,12 +3757,11 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, static int iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) + const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; - struct iwn_tx_ring *txq; int error = 0; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { @@ -3296,29 +3771,26 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, } IWN_LOCK(sc); - if (params == NULL) - txq = &sc->txq[M_WME_GETAC(m)]; - else - txq = &sc->txq[params->ibp_pri & 3]; - if (params == NULL) { /* * Legacy path; interpret frame contents to decide * precisely how to send the frame. */ - error = iwn_tx_data(sc, m, ni, txq); + error = iwn_tx_data(sc, m, ni); } else { /* * Caller supplied explicit parameters to use in * sending the frame. */ - error = iwn_tx_data_raw(sc, m, ni, txq, params); + error = iwn_tx_data_raw(sc, m, ni, params); } if (error != 0) { /* NB: m is reclaimed on tx failure */ ieee80211_free_node(ni); ifp->if_oerrors++; } + sc->sc_tx_timer = 5; + IWN_UNLOCK(sc); return error; } @@ -3338,12 +3810,14 @@ iwn_start_locked(struct ifnet *ifp) { struct iwn_softc *sc = ifp->if_softc; struct ieee80211_node *ni; - struct iwn_tx_ring *txq; struct mbuf *m; - int pri; IWN_LOCK_ASSERT(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) + return; + for (;;) { if (sc->qfullmsk != 0) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -3353,27 +3827,34 @@ iwn_start_locked(struct ifnet *ifp) if (m == NULL) break; ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - pri = M_WME_GETAC(m); - txq = &sc->txq[pri]; - if (iwn_tx_data(sc, m, ni, txq) != 0) { - ifp->if_oerrors++; + if (iwn_tx_data(sc, m, ni) != 0) { ieee80211_free_node(ni); - break; + ifp->if_oerrors++; + continue; } sc->sc_tx_timer = 5; } } static void -iwn_watchdog(struct iwn_softc *sc) +iwn_watchdog(void *arg) { - if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + struct iwn_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - if_printf(ifp, "device timeout\n"); - ieee80211_runtask(ic, &sc->sc_reinit_task); + IWN_LOCK_ASSERT(sc); + + KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); + + if (sc->sc_tx_timer > 0) { + if (--sc->sc_tx_timer == 0) { + if_printf(ifp, "device timeout\n"); + ieee80211_runtask(ic, &sc->sc_reinit_task); + return; + } } + callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); } static int @@ -3386,6 +3867,9 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) int error = 0, startall = 0, stop = 0; switch (cmd) { + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; case SIOCSIFFLAGS: IWN_LOCK(sc); if (ifp->if_flags & IFF_UP) { @@ -3409,9 +3893,6 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; - case SIOCGIFADDR: - error = ether_ioctl(ifp, cmd, data); - break; default: error = EINVAL; break; @@ -3433,7 +3914,8 @@ iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) bus_addr_t paddr; int totlen, error; - IWN_LOCK_ASSERT(sc); + if (async == 0) + IWN_LOCK_ASSERT(sc); desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; @@ -3483,11 +3965,6 @@ iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); -#ifdef notyet - /* Update TX scheduler. */ - sc->sc_hal->update_sched(sc, ring->qid, ring->cur, 0, 0); -#endif - /* Kick command ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); @@ -3521,98 +3998,49 @@ iwn5000_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async) return iwn_cmd(sc, IWN_CMD_ADD_NODE, node, sizeof (*node), async); } -#if 0 /* HT */ -static const uint8_t iwn_ridx_to_plcp[] = { - 10, 20, 55, 110, /* CCK */ - 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, 0x3 /* OFDM R1-R4 */ -}; -static const uint8_t iwn_siso_mcs_to_plcp[] = { - 0, 0, 0, 0, /* CCK */ - 0, 0, 1, 2, 3, 4, 5, 6, 7 /* HT */ -}; -static const uint8_t iwn_mimo_mcs_to_plcp[] = { - 0, 0, 0, 0, /* CCK */ - 8, 8, 9, 10, 11, 12, 13, 14, 15 /* HT */ -}; -#endif -static const uint8_t iwn_prev_ridx[] = { - /* NB: allow fallback from CCK11 to OFDM9 and from OFDM6 to CCK5 */ - 0, 0, 1, 5, /* CCK */ - 2, 4, 3, 6, 7, 8, 9, 10, 10 /* OFDM */ -}; - -/* - * Configure hardware link parameters for the specified - * node operating on the specified channel. - */ static int -iwn_set_link_quality(struct iwn_softc *sc, uint8_t id, int async) +iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; +#define RV(v) ((v) & IEEE80211_RATE_VAL) + struct iwn_node *wn = (void *)ni; + struct ieee80211_rateset *rs = &ni->ni_rates; struct iwn_cmd_link_quality linkq; - const struct iwn_rate *rinfo; - int i; - uint8_t txant, ridx; + uint8_t txant; + int i, rate, txrate; /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); memset(&linkq, 0, sizeof linkq); - linkq.id = id; + linkq.id = wn->id; linkq.antmsk_1stream = txant; linkq.antmsk_2stream = IWN_ANT_AB; - linkq.ampdu_max = 31; + linkq.ampdu_max = 64; linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ -#if 0 /* HT */ - if (IEEE80211_IS_CHAN_HT(c)) - linkq.mimo = 1; -#endif - - if (id == IWN_ID_BSS) - ridx = IWN_RIDX_OFDM54; - else if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) - ridx = IWN_RIDX_OFDM6; + /* Start at highest available bit-rate. */ + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) + txrate = ni->ni_htrates.rs_nrates - 1; else - ridx = IWN_RIDX_CCK1; - + txrate = rs->rs_nrates - 1; for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { - rinfo = &iwn_rates[ridx]; -#if 0 /* HT */ - if (IEEE80211_IS_CHAN_HT40(c)) { - linkq.retry[i].plcp = iwn_mimo_mcs_to_plcp[ridx] - | IWN_RIDX_MCS; - linkq.retry[i].rflags = IWN_RFLAG_HT - | IWN_RFLAG_HT40; - /* XXX shortGI */ - } else if (IEEE80211_IS_CHAN_HT(c)) { - linkq.retry[i].plcp = iwn_siso_mcs_to_plcp[ridx] - | IWN_RIDX_MCS; - linkq.retry[i].rflags = IWN_RFLAG_HT; - /* XXX shortGI */ - } else -#endif - { - linkq.retry[i].plcp = rinfo->plcp; - linkq.retry[i].rflags = rinfo->flags; - } - linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant); - ridx = iwn_prev_ridx[ridx]; + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) + rate = IEEE80211_RATE_MCS | txrate; + else + rate = RV(rs->rs_rates[txrate]); + linkq.retry[i] = wn->ridx[rate]; + + if ((le32toh(wn->ridx[rate]) & IWN_RFLAG_MCS) && + RV(le32toh(wn->ridx[rate])) > 7) + linkq.mimo = i + 1; + + /* Next retry at immediate lower bit-rate. */ + if (txrate > 0) + txrate--; } -#ifdef IWN_DEBUG - if (sc->sc_debug & IWN_DEBUG_STATE) { - printf("%s: set link quality for node %d, mimo %d ssmask %d\n", - __func__, id, linkq.mimo, linkq.antmsk_1stream); - printf("%s:", __func__); - for (i = 0; i < IWN_MAX_TX_RETRIES; i++) - printf(" %d:%x", linkq.retry[i].plcp, - linkq.retry[i].rflags); - printf("\n"); - } -#endif - return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async); + return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1); +#undef RV } /* @@ -3621,50 +4049,70 @@ iwn_set_link_quality(struct iwn_softc *sc, uint8_t id, int async) static int iwn_add_broadcast_node(struct iwn_softc *sc, int async) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct iwn_node_info node; - int error; + struct iwn_cmd_link_quality linkq; + uint8_t txant; + int i, error; memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); - node.id = hal->broadcast_id; + node.id = sc->broadcast_id; DPRINTF(sc, IWN_DEBUG_RESET, "%s: adding broadcast node\n", __func__); - error = hal->add_node(sc, &node, async); - if (error != 0) + if ((error = ops->add_node(sc, &node, async)) != 0) return error; - error = iwn_set_link_quality(sc, hal->broadcast_id, async); - return error; + /* Use the first valid TX antenna. */ + txant = IWN_LSB(sc->txchainmask); + + memset(&linkq, 0, sizeof linkq); + linkq.id = sc->broadcast_id; + linkq.antmsk_1stream = txant; + linkq.antmsk_2stream = IWN_ANT_AB; + linkq.ampdu_max = 64; + linkq.ampdu_threshold = 3; + linkq.ampdu_limit = htole16(4000); /* 4ms */ + + /* Use lowest mandatory bit-rate. */ + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) + linkq.retry[0] = htole32(0xd); + else + linkq.retry[0] = htole32(10 | IWN_RFLAG_CCK); + linkq.retry[0] |= htole32(IWN_RFLAG_ANT(txant)); + /* Use same bit-rate for all TX retries. */ + for (i = 1; i < IWN_MAX_TX_RETRIES; i++) { + linkq.retry[i] = linkq.retry[0]; + } + return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async); } static int -iwn_wme_update(struct ieee80211com *ic) +iwn_updateedca(struct ieee80211com *ic) { #define IWN_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ -#define IWN_TXOP_TO_US(v) (v<<5) struct iwn_softc *sc = ic->ic_ifp->if_softc; struct iwn_edca_params cmd; - int i; + int aci; memset(&cmd, 0, sizeof cmd); cmd.flags = htole32(IWN_EDCA_UPDATE); - for (i = 0; i < WME_NUM_AC; i++) { - const struct wmeParams *wmep = - &ic->ic_wme.wme_chanParams.cap_wmeParams[i]; - cmd.ac[i].aifsn = wmep->wmep_aifsn; - cmd.ac[i].cwmin = htole16(IWN_EXP2(wmep->wmep_logcwmin)); - cmd.ac[i].cwmax = htole16(IWN_EXP2(wmep->wmep_logcwmax)); - cmd.ac[i].txoplimit = - htole16(IWN_TXOP_TO_US(wmep->wmep_txopLimit)); + for (aci = 0; aci < WME_NUM_AC; aci++) { + const struct wmeParams *ac = + &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; + cmd.ac[aci].aifsn = ac->wmep_aifsn; + cmd.ac[aci].cwmin = htole16(IWN_EXP2(ac->wmep_logcwmin)); + cmd.ac[aci].cwmax = htole16(IWN_EXP2(ac->wmep_logcwmax)); + cmd.ac[aci].txoplimit = + htole16(IEEE80211_TXOP_TO_US(ac->wmep_txopLimit)); } IEEE80211_UNLOCK(ic); IWN_LOCK(sc); - (void) iwn_cmd(sc, IWN_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1 /*async*/); + (void)iwn_cmd(sc, IWN_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); IWN_UNLOCK(sc); IEEE80211_LOCK(ic); return 0; -#undef IWN_TXOP_TO_US #undef IWN_EXP2 } @@ -3709,8 +4157,7 @@ iwn_set_critical_temp(struct iwn_softc *sc) temp = 110; memset(&crit, 0, sizeof crit); crit.tempR = htole32(temp); - DPRINTF(sc, IWN_DEBUG_RESET, "setting critical temp to %d\n", - temp); + DPRINTF(sc, IWN_DEBUG_RESET, "setting critical temp to %d\n", temp); return iwn_cmd(sc, IWN_CMD_SET_CRITICAL_TEMP, &crit, sizeof crit, 0); } @@ -3726,7 +4173,7 @@ iwn_set_timing(struct iwn_softc *sc, struct ieee80211_node *ni) cmd.lintval = htole16(10); /* Compute remaining time until next beacon. */ - val = (uint64_t)ni->ni_intval * 1024; /* msecs -> usecs */ + val = (uint64_t)ni->ni_intval * IEEE80211_DUR_TU; mod = le64toh(cmd.tstamp) % val; cmd.binitval = htole32((uint32_t)(val - mod)); @@ -3742,7 +4189,7 @@ iwn4965_power_calibration(struct iwn_softc *sc, int temp) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - /* Adjust TX power if need be (delta >= 3 degC.) */ + /* Adjust TX power if need be (delta >= 3 degC). */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: temperature %d->%d\n", __func__, sc->temp, temp); if (abs(temp - sc->temp) >= 3) { @@ -3769,18 +4216,16 @@ iwn4965_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch, ((y1) + fdivround(((int)(x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) static const int tdiv[IWN_NATTEN_GROUPS] = { 9, 8, 8, 8, 6 }; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; struct iwn_ucode_info *uc = &sc->ucode_info; struct iwn4965_cmd_txpower cmd; struct iwn4965_eeprom_chan_samples *chans; + const uint8_t *rf_gain, *dsp_gain; int32_t vdiff, tdiff; int i, c, grp, maxpwr; - const uint8_t *rf_gain, *dsp_gain; uint8_t chan; - /* Retrieve channel number. */ - chan = ieee80211_chan2ieee(ic, ch); + /* Retrieve current channel from last RXON. */ + chan = sc->rxon.chan; DPRINTF(sc, IWN_DEBUG_RESET, "setting TX power for channel %d\n", chan); @@ -3941,22 +4386,16 @@ iwn4965_get_rssi(struct iwn_softc *sc, struct iwn_rx_stat *stat) agc = (le16toh(phy->agc) >> 7) & 0x7f; rssi = 0; -#if 0 - if (mask & IWN_ANT_A) /* Ant A */ - rssi = max(rssi, phy->rssi[0]); - if (mask & IWN_ATH_B) /* Ant B */ - rssi = max(rssi, phy->rssi[2]); - if (mask & IWN_ANT_C) /* Ant C */ - rssi = max(rssi, phy->rssi[4]); -#else - rssi = max(rssi, phy->rssi[0]); - rssi = max(rssi, phy->rssi[2]); - rssi = max(rssi, phy->rssi[4]); -#endif + if (mask & IWN_ANT_A) + rssi = MAX(rssi, phy->rssi[0]); + if (mask & IWN_ANT_B) + rssi = MAX(rssi, phy->rssi[2]); + if (mask & IWN_ANT_C) + rssi = MAX(rssi, phy->rssi[4]); - DPRINTF(sc, IWN_DEBUG_RECV, "%s: agc %d mask 0x%x rssi %d %d %d " - "result %d\n", __func__, agc, mask, - phy->rssi[0], phy->rssi[2], phy->rssi[4], + DPRINTF(sc, IWN_DEBUG_RECV, + "%s: agc %d mask 0x%x rssi %d %d %d result %d\n", __func__, agc, + mask, phy->rssi[0], phy->rssi[2], phy->rssi[4], rssi - agc - IWN_RSSI_TO_DBM); return rssi - agc - IWN_RSSI_TO_DBM; } @@ -3965,8 +4404,8 @@ static int iwn5000_get_rssi(struct iwn_softc *sc, struct iwn_rx_stat *stat) { struct iwn5000_rx_phystat *phy = (void *)stat->phybuf; - int rssi; uint8_t agc; + int rssi; agc = (le32toh(phy->agc) >> 9) & 0x7f; @@ -3974,8 +4413,8 @@ iwn5000_get_rssi(struct iwn_softc *sc, struct iwn_rx_stat *stat) le16toh(phy->rssi[1]) & 0xff); rssi = MAX(le16toh(phy->rssi[2]) & 0xff, rssi); - DPRINTF(sc, IWN_DEBUG_RECV, "%s: agc %d rssi %d %d %d " - "result %d\n", __func__, agc, + DPRINTF(sc, IWN_DEBUG_RECV, + "%s: agc %d rssi %d %d %d result %d\n", __func__, agc, phy->rssi[0], phy->rssi[1], phy->rssi[2], rssi - agc - IWN_RSSI_TO_DBM); return rssi - agc - IWN_RSSI_TO_DBM; @@ -4014,11 +4453,11 @@ iwn4965_get_temperature(struct iwn_softc *sc) r3 = le32toh(uc->temp[2].chan20MHz); r4 = le32toh(sc->rawtemp); - if (r1 == r3) /* Prevents division by 0 (should not happen.) */ + if (r1 == r3) /* Prevents division by 0 (should not happen). */ return 0; /* Sign-extend 23-bit R4 value to 32-bit. */ - r4 = (r4 << 8) >> 8; + r4 = ((r4 & 0xffffff) ^ 0x800000) - 0x800000; /* Compute temperature in Kelvin. */ temp = (259 * (r4 - r2)) / (r3 - r1); temp = (temp * 97) / 100 + 8; @@ -4035,8 +4474,7 @@ iwn5000_get_temperature(struct iwn_softc *sc) /* * Temperature is not used by the driver for 5000 Series because - * TX power calibration is handled by firmware. We export it to - * users through the sensor framework though. + * TX power calibration is handled by firmware. */ temp = le32toh(sc->rawtemp); if (sc->hw_type == IWN_HW_REV_TYPE_5150) { @@ -4052,7 +4490,7 @@ iwn5000_get_temperature(struct iwn_softc *sc) static int iwn_init_sensitivity(struct iwn_softc *sc) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; uint32_t flags; int error; @@ -4071,18 +4509,17 @@ iwn_init_sensitivity(struct iwn_softc *sc) calib->energy_cck = sc->limits->energy_cck; /* Write initial sensitivity. */ - error = iwn_send_sensitivity(sc); - if (error != 0) + if ((error = iwn_send_sensitivity(sc)) != 0) return error; /* Write initial gains. */ - error = hal->init_gains(sc); - if (error != 0) + if ((error = ops->init_gains(sc)) != 0) return error; /* Request statistics at each beacon interval. */ flags = 0; - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: calibrate phy\n", __func__); + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending request for statistics\n", + __func__); return iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); } @@ -4095,7 +4532,7 @@ static void iwn_collect_noise(struct iwn_softc *sc, const struct iwn_rx_general_stats *stats) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; uint32_t val; int i; @@ -4126,13 +4563,13 @@ iwn_collect_noise(struct iwn_softc *sc, if ((sc->chainmask & sc->txchainmask) == 0) sc->chainmask |= IWN_LSB(sc->txchainmask); - (void)hal->set_gains(sc); + (void)ops->set_gains(sc); calib->state = IWN_CALIB_STATE_RUN; #ifdef notyet /* XXX Disable RX chains with no antennas connected. */ sc->rxon.rxchain = htole16(IWN_RXCHAIN_SEL(sc->chainmask)); - (void)iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, hal->rxonsz, 1); + (void)iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); #endif #if 0 @@ -4162,7 +4599,7 @@ iwn5000_init_gains(struct iwn_softc *sc) struct iwn_phy_calib cmd; memset(&cmd, 0, sizeof cmd); - cmd.code = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; + cmd.code = sc->reset_noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; DPRINTF(sc, IWN_DEBUG_CALIBRATE, @@ -4208,13 +4645,13 @@ iwn5000_set_gains(struct iwn_softc *sc) { struct iwn_calib_state *calib = &sc->calib; struct iwn_phy_calib_gain cmd; - int i, ant, delta, div; + int i, ant, div, delta; /* We collected 20 beacons and !=6050 need a 1.5 factor. */ div = (sc->hw_type == IWN_HW_REV_TYPE_6050) ? 20 : 30; memset(&cmd, 0, sizeof cmd); - cmd.code = IWN5000_PHY_CALIB_NOISE_GAIN; + cmd.code = sc->noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; /* Get first available RX antenna as referential. */ @@ -4269,14 +4706,13 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) int i, needs_update = 0; /* Check that we've been enabled long enough. */ - rxena = le32toh(stats->general.load); - if (rxena == 0) + if ((rxena = le32toh(stats->general.load)) == 0) return; /* Compute number of false alarms since last call for OFDM. */ fa = le32toh(stats->ofdm.bad_plcp) - calib->bad_plcp_ofdm; fa += le32toh(stats->ofdm.fa) - calib->fa_ofdm; - fa *= 200 * 1024; /* 200TU */ + fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ /* Save counters values for next call. */ calib->bad_plcp_ofdm = le32toh(stats->ofdm.bad_plcp); @@ -4333,7 +4769,7 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) /* Compute number of false alarms since last call for CCK. */ fa = le32toh(stats->cck.bad_plcp) - calib->bad_plcp_cck; fa += le32toh(stats->cck.fa) - calib->fa_cck; - fa *= 200 * 1024; /* 200TU */ + fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ /* Save counters values for next call. */ calib->bad_plcp_cck = le32toh(stats->cck.bad_plcp); @@ -4368,7 +4804,7 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) if (calib->cck_state != IWN_CCK_STATE_INIT && (((int32_t)calib->noise_ref - (int32_t)noise_ref) > 2 || - calib->low_fa > 100)) { + calib->low_fa > 100)) { inc(calib->energy_cck, 2, limits->min_energy_cck); dec(calib->cck_x4, 3, limits->min_cck_x4); dec(calib->cck_mrc_x4, 3, limits->min_cck_mrc_x4); @@ -4397,31 +4833,47 @@ static int iwn_send_sensitivity(struct iwn_softc *sc) { struct iwn_calib_state *calib = &sc->calib; - struct iwn_sensitivity_cmd cmd; + struct iwn_enhanced_sensitivity_cmd cmd; + int len; memset(&cmd, 0, sizeof cmd); + len = sizeof (struct iwn_sensitivity_cmd); cmd.which = IWN_SENSITIVITY_WORKTBL; /* OFDM modulation. */ - cmd.corr_ofdm_x1 = htole16(calib->ofdm_x1); - cmd.corr_ofdm_mrc_x1 = htole16(calib->ofdm_mrc_x1); - cmd.corr_ofdm_x4 = htole16(calib->ofdm_x4); - cmd.corr_ofdm_mrc_x4 = htole16(calib->ofdm_mrc_x4); - cmd.energy_ofdm = htole16(sc->limits->energy_ofdm); - cmd.energy_ofdm_th = htole16(62); + cmd.corr_ofdm_x1 = htole16(calib->ofdm_x1); + cmd.corr_ofdm_mrc_x1 = htole16(calib->ofdm_mrc_x1); + cmd.corr_ofdm_x4 = htole16(calib->ofdm_x4); + cmd.corr_ofdm_mrc_x4 = htole16(calib->ofdm_mrc_x4); + cmd.energy_ofdm = htole16(sc->limits->energy_ofdm); + cmd.energy_ofdm_th = htole16(62); /* CCK modulation. */ - cmd.corr_cck_x4 = htole16(calib->cck_x4); - cmd.corr_cck_mrc_x4 = htole16(calib->cck_mrc_x4); - cmd.energy_cck = htole16(calib->energy_cck); + cmd.corr_cck_x4 = htole16(calib->cck_x4); + cmd.corr_cck_mrc_x4 = htole16(calib->cck_mrc_x4); + cmd.energy_cck = htole16(calib->energy_cck); /* Barker modulation: use default values. */ - cmd.corr_barker = htole16(190); - cmd.corr_barker_mrc = htole16(390); + cmd.corr_barker = htole16(190); + cmd.corr_barker_mrc = htole16(390); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: set sensitivity %d/%d/%d/%d/%d/%d/%d\n", __func__, calib->ofdm_x1, calib->ofdm_mrc_x1, calib->ofdm_x4, calib->ofdm_mrc_x4, calib->cck_x4, calib->cck_mrc_x4, calib->energy_cck); - return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, sizeof cmd, 1); + + if (!(sc->sc_flags & IWN_FLAG_ENH_SENS)) + goto send; + /* Enhanced sensitivity settings. */ + len = sizeof (struct iwn_enhanced_sensitivity_cmd); + cmd.ofdm_det_slope_mrc = htole16(668); + cmd.ofdm_det_icept_mrc = htole16(4); + cmd.ofdm_det_slope = htole16(486); + cmd.ofdm_det_icept = htole16(37); + cmd.cck_det_slope_mrc = htole16(853); + cmd.cck_det_icept_mrc = htole16(4); + cmd.cck_det_slope = htole16(476); + cmd.cck_det_icept = htole16(99); +send: + return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, len, 1); } /* @@ -4431,10 +4883,10 @@ iwn_send_sensitivity(struct iwn_softc *sc) static int iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async) { - const struct iwn_pmgt *pmgt; struct iwn_pmgt_cmd cmd; + const struct iwn_pmgt *pmgt; uint32_t max, skip_dtim; - uint32_t tmp; + uint32_t reg; int i; /* Select which PS parameters to use. */ @@ -4451,8 +4903,8 @@ iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async) if (level == 5) cmd.flags |= htole16(IWN_PS_FAST_PD); /* Retrieve PCIe Active State Power Management (ASPM). */ - tmp = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); - if (!(tmp & 0x1)) /* L0s Entry disabled. */ + reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); + if (!(reg & 0x1)) /* L0s Entry disabled. */ cmd.flags |= htole16(IWN_PS_PCI_PMGT); cmd.rxtimeout = htole32(pmgt->rxtimeout * 1024); cmd.txtimeout = htole32(pmgt->txtimeout * 1024); @@ -4479,18 +4931,122 @@ iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async) return iwn_cmd(sc, IWN_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async); } +static int +iwn_send_btcoex(struct iwn_softc *sc) +{ + struct iwn_bluetooth cmd; + + memset(&cmd, 0, sizeof cmd); + cmd.flags = IWN_BT_COEX_CHAN_ANN | IWN_BT_COEX_BT_PRIO; + cmd.lead_time = IWN_BT_LEAD_TIME_DEF; + cmd.max_kill = IWN_BT_MAX_KILL_DEF; + DPRINTF(sc, IWN_DEBUG_RESET, "%s: configuring bluetooth coexistence\n", + __func__); + return iwn_cmd(sc, IWN_CMD_BT_COEX, &cmd, sizeof(cmd), 0); +} + +static int +iwn_send_advanced_btcoex(struct iwn_softc *sc) +{ + static const uint32_t btcoex_3wire[12] = { + 0xaaaaaaaa, 0xaaaaaaaa, 0xaeaaaaaa, 0xaaaaaaaa, + 0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa, + 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000, + }; + struct iwn6000_btcoex_config btconfig; + struct iwn_btcoex_priotable btprio; + struct iwn_btcoex_prot btprot; + int error, i; + + memset(&btconfig, 0, sizeof btconfig); + btconfig.flags = 145; + btconfig.max_kill = 5; + btconfig.bt3_t7_timer = 1; + btconfig.kill_ack = htole32(0xffff0000); + btconfig.kill_cts = htole32(0xffff0000); + btconfig.sample_time = 2; + btconfig.bt3_t2_timer = 0xc; + for (i = 0; i < 12; i++) + btconfig.lookup_table[i] = htole32(btcoex_3wire[i]); + btconfig.valid = htole16(0xff); + btconfig.prio_boost = 0xf0; + DPRINTF(sc, IWN_DEBUG_RESET, + "%s: configuring advanced bluetooth coexistence\n", __func__); + error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1); + if (error != 0) + return error; + + memset(&btprio, 0, sizeof btprio); + btprio.calib_init1 = 0x6; + btprio.calib_init2 = 0x7; + btprio.calib_periodic_low1 = 0x2; + btprio.calib_periodic_low2 = 0x3; + btprio.calib_periodic_high1 = 0x4; + btprio.calib_periodic_high2 = 0x5; + btprio.dtim = 0x6; + btprio.scan52 = 0x8; + btprio.scan24 = 0xa; + error = iwn_cmd(sc, IWN_CMD_BT_COEX_PRIOTABLE, &btprio, sizeof(btprio), + 1); + if (error != 0) + return error; + + /* Force BT state machine change. */ + memset(&btprot, 0, sizeof btprio); + btprot.open = 1; + btprot.type = 1; + error = iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1); + if (error != 0) + return error; + btprot.open = 0; + return iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1); +} + +static int +iwn5000_runtime_calib(struct iwn_softc *sc) +{ + struct iwn5000_calib_config cmd; + + memset(&cmd, 0, sizeof cmd); + cmd.ucode.once.enable = 0xffffffff; + cmd.ucode.once.start = IWN5000_CALIB_DC; + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "%s: configuring runtime calibration\n", __func__); + return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0); +} + static int iwn_config(struct iwn_softc *sc) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct iwn_bluetooth bluetooth; uint32_t txmask; - int error; uint16_t rxchain; + int error; - /* Configure valid TX chains for 5000 Series. */ + if (sc->hw_type == IWN_HW_REV_TYPE_6005) { + /* Set radio temperature sensor offset. */ + error = iwn5000_temp_offset_calib(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not set temperature offset\n", __func__); + return error; + } + } + + if (sc->hw_type == IWN_HW_REV_TYPE_6050) { + /* Configure runtime DC calibration. */ + error = iwn5000_runtime_calib(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not configure runtime calibration\n", + __func__); + return error; + } + } + + /* Configure valid TX chains for >=5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965) { txmask = htole32(sc->txchainmask); DPRINTF(sc, IWN_DEBUG_RESET, @@ -4506,13 +5062,10 @@ iwn_config(struct iwn_softc *sc) } /* Configure bluetooth coexistence. */ - memset(&bluetooth, 0, sizeof bluetooth); - bluetooth.flags = IWN_BT_COEX_CHAN_ANN | IWN_BT_COEX_BT_PRIO; - bluetooth.lead_time = IWN_BT_LEAD_TIME_DEF; - bluetooth.max_kill = IWN_BT_MAX_KILL_DEF; - DPRINTF(sc, IWN_DEBUG_RESET, "%s: config bluetooth coexistence\n", - __func__); - error = iwn_cmd(sc, IWN_CMD_BT_COEX, &bluetooth, sizeof bluetooth, 0); + if (sc->sc_flags & IWN_FLAG_ADV_BTCOEX) + error = iwn_send_advanced_btcoex(sc); + else + error = iwn_send_btcoex(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure bluetooth coexistence, error %d\n", @@ -4553,38 +5106,34 @@ iwn_config(struct iwn_softc *sc) IWN_RXCHAIN_IDLE_COUNT(2); sc->rxon.rxchain = htole16(rxchain); DPRINTF(sc, IWN_DEBUG_RESET, "%s: setting configuration\n", __func__); - error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, hal->rxonsz, 0); + error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 0); if (error != 0) { - device_printf(sc->sc_dev, - "%s: RXON command failed\n", __func__); + device_printf(sc->sc_dev, "%s: RXON command failed\n", + __func__); return error; } - error = iwn_add_broadcast_node(sc, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not add broadcast node\n", __func__); + if ((error = iwn_add_broadcast_node(sc, 0)) != 0) { + device_printf(sc->sc_dev, "%s: could not add broadcast node\n", + __func__); return error; } /* Configuration has changed, set TX power accordingly. */ - error = hal->set_txpower(sc, ic->ic_curchan, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not set TX power\n", __func__); + if ((error = ops->set_txpower(sc, ic->ic_curchan, 0)) != 0) { + device_printf(sc->sc_dev, "%s: could not set TX power\n", + __func__); return error; } - error = iwn_set_critical_temp(sc); - if (error != 0) { + if ((error = iwn_set_critical_temp(sc)) != 0) { device_printf(sc->sc_dev, - "%s: ccould not set critical temperature\n", __func__); + "%s: could not set critical temperature\n", __func__); return error; } /* Set power saving level to CAM during initialization. */ - error = iwn_set_pslevel(sc, 0, 0, 0); - if (error != 0) { + if ((error = iwn_set_pslevel(sc, 0, 0, 0)) != 0) { device_printf(sc->sc_dev, "%s: could not set power saving level\n", __func__); return error; @@ -4592,12 +5141,25 @@ iwn_config(struct iwn_softc *sc) return 0; } +/* + * Add an ssid element to a frame. + */ +static uint8_t * +ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) +{ + *frm++ = IEEE80211_ELEMID_SSID; + *frm++ = len; + memcpy(frm, ssid, len); + return frm + len; +} + static int iwn_scan(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_scan_state *ss = ic->ic_scan; /*XXX*/ + struct ieee80211_node *ni = ss->ss_vap->iv_bss; struct iwn_scan_hdr *hdr; struct iwn_cmd_data *tx; struct iwn_scan_essid *essid; @@ -4605,9 +5167,10 @@ iwn_scan(struct iwn_softc *sc) struct ieee80211_frame *wh; struct ieee80211_rateset *rs; struct ieee80211_channel *c; - int buflen, error, nrates; + uint8_t *buf, *frm; uint16_t rxchain; - uint8_t *buf, *frm, txant; + uint8_t txant; + int buflen, error; buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); if (buf == NULL) { @@ -4617,7 +5180,6 @@ iwn_scan(struct iwn_softc *sc) return ENOMEM; } hdr = (struct iwn_scan_hdr *)buf; - /* * Move to the next channel if no frames are received within 10ms * after sending the probe request. @@ -4633,7 +5195,7 @@ iwn_scan(struct iwn_softc *sc) if (IEEE80211_IS_CHAN_A(ic->ic_curchan) && sc->hw_type == IWN_HW_REV_TYPE_4965) { /* Ant A must be avoided in 5GHz because of an HW bug. */ - rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_BC); + rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_B); } else /* Use all available RX antennas. */ rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask); hdr->rxchain = htole16(rxchain); @@ -4641,23 +5203,27 @@ iwn_scan(struct iwn_softc *sc) tx = (struct iwn_cmd_data *)(hdr + 1); tx->flags = htole32(IWN_TX_AUTO_SEQ); - tx->id = sc->sc_hal->broadcast_id; + tx->id = sc->broadcast_id; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) { + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { /* Send probe requests at 6Mbps. */ - tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp; + tx->rate = htole32(0xd); rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; } else { hdr->flags = htole32(IWN_RXON_24GHZ | IWN_RXON_AUTO); - /* Send probe requests at 1Mbps. */ - tx->plcp = iwn_rates[IWN_RIDX_CCK1].plcp; - tx->rflags = IWN_RFLAG_CCK; + if (sc->hw_type == IWN_HW_REV_TYPE_4965 && + sc->rxon.associd && sc->rxon.chan > 14) + tx->rate = htole32(0xd); + else { + /* Send probe requests at 1Mbps. */ + tx->rate = htole32(10 | IWN_RFLAG_CCK); + } rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; } /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); - tx->rflags |= IWN_RFLAG_ANT(txant); + tx->rate |= htole32(IWN_RFLAG_ANT(txant)); essid = (struct iwn_scan_essid *)(tx + 1); if (ss->ss_ssid[0].len != 0) { @@ -4665,7 +5231,6 @@ iwn_scan(struct iwn_softc *sc) essid[0].len = ss->ss_ssid[0].len; memcpy(essid[0].data, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len); } - /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. @@ -4681,30 +5246,12 @@ iwn_scan(struct iwn_softc *sc) *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ frm = (uint8_t *)(wh + 1); - - /* Add SSID IE. */ - *frm++ = IEEE80211_ELEMID_SSID; - *frm++ = ss->ss_ssid[0].len; - memcpy(frm, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len); - frm += ss->ss_ssid[0].len; - - /* Add supported rates IE. */ - *frm++ = IEEE80211_ELEMID_RATES; - nrates = rs->rs_nrates; - if (nrates > IEEE80211_RATE_SIZE) - nrates = IEEE80211_RATE_SIZE; - *frm++ = nrates; - memcpy(frm, rs->rs_rates, nrates); - frm += nrates; - - /* Add supported xrates IE. */ - if (rs->rs_nrates > IEEE80211_RATE_SIZE) { - nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; - *frm++ = IEEE80211_ELEMID_XRATES; - *frm++ = (uint8_t)nrates; - memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); - frm += nrates; - } + frm = ieee80211_add_ssid(frm, NULL, 0); + frm = ieee80211_add_rates(frm, rs); + if (rs->rs_nrates > IEEE80211_RATE_SIZE) + frm = ieee80211_add_xrates(frm, rs); + if (ic->ic_htcaps & IEEE80211_HTC_HT) + frm = ieee80211_add_htcap(frm, ni); /* Set length of probe request. */ tx->len = htole16(frm - (uint8_t *)wh); @@ -4766,17 +5313,15 @@ iwn_scan(struct iwn_softc *sc) static int iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; int error; - sc->calib.state = IWN_CALIB_STATE_INIT; - /* Update adapter configuration. */ IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); - sc->rxon.chan = htole16(ieee80211_chan2ieee(ic, ni->ni_chan)); + sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); @@ -4791,70 +5336,56 @@ iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) sc->rxon.cck_mask = 0x03; sc->rxon.ofdm_mask = 0; } else { - /* XXX assume 802.11b/g */ + /* Assume 802.11b/g. */ sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } - DPRINTF(sc, IWN_DEBUG_STATE, - "%s: config chan %d mode %d flags 0x%x cck 0x%x ofdm 0x%x " - "ht_single 0x%x ht_dual 0x%x rxchain 0x%x " - "myaddr %6D wlap %6D bssid %6D associd %d filter 0x%x\n", - __func__, - le16toh(sc->rxon.chan), sc->rxon.mode, le32toh(sc->rxon.flags), - sc->rxon.cck_mask, sc->rxon.ofdm_mask, - sc->rxon.ht_single_mask, sc->rxon.ht_dual_mask, - le16toh(sc->rxon.rxchain), - sc->rxon.myaddr, ":", sc->rxon.wlap, ":", sc->rxon.bssid, ":", - le16toh(sc->rxon.associd), le32toh(sc->rxon.filter)); - error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, hal->rxonsz, 1); + DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n", + sc->rxon.chan, sc->rxon.flags, sc->rxon.cck_mask, + sc->rxon.ofdm_mask); + error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) { - device_printf(sc->sc_dev, - "%s: RXON command failed, error %d\n", __func__, error); + device_printf(sc->sc_dev, "%s: RXON command failed, error %d\n", + __func__, error); return error; } /* Configuration has changed, set TX power accordingly. */ - error = hal->set_txpower(sc, ni->ni_chan, 1); - if (error != 0) { + if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) { device_printf(sc->sc_dev, - "%s: could not set Tx power, error %d\n", __func__, error); + "%s: could not set TX power, error %d\n", __func__, error); return error; } /* * Reconfiguring RXON clears the firmware nodes table so we must * add the broadcast node again. */ - error = iwn_add_broadcast_node(sc, 1); - if (error != 0) { + if ((error = iwn_add_broadcast_node(sc, 1)) != 0) { device_printf(sc->sc_dev, - "%s: could not add broadcast node, error %d\n", - __func__, error); + "%s: could not add broadcast node, error %d\n", __func__, + error); return error; } return 0; } -/* - * Configure the adapter for associated state. - */ static int iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) { -#define MS(v,x) (((v) & x) >> x##_S) - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; struct iwn_node_info node; + uint32_t htflags = 0; int error; if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Link LED blinks while monitoring. */ - iwn_set_led(sc, IWN_LED_LINK, 20, 20); + iwn_set_led(sc, IWN_LED_LINK, 5, 5); return 0; } - error = iwn_set_timing(sc, ni); - if (error != 0) { + if ((error = iwn_set_timing(sc, ni)) != 0) { device_printf(sc->sc_dev, "%s: could not set timing, error %d\n", __func__, error); return error; @@ -4862,15 +5393,11 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) /* Update adapter configuration. */ IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); - sc->rxon.chan = htole16(ieee80211_chan2ieee(ic, ni->ni_chan)); sc->rxon.associd = htole16(IEEE80211_AID(ni->ni_associd)); - /* Short preamble and slot time are negotiated when associating. */ - sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE | IWN_RXON_SHSLOT); - sc->rxon.flags |= htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); + sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); + sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); - else - sc->rxon.flags &= ~htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon.flags |= htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) @@ -4882,139 +5409,153 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) sc->rxon.cck_mask = 0x03; sc->rxon.ofdm_mask = 0; } else { - /* XXX assume 802.11b/g */ + /* Assume 802.11b/g. */ sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } -#if 0 /* HT */ if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { - sc->rxon.flags &= ~htole32(IWN_RXON_HT); - if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan)) - sc->rxon.flags |= htole32(IWN_RXON_HT40U); - else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan)) - sc->rxon.flags |= htole32(IWN_RXON_HT40D); - else - sc->rxon.flags |= htole32(IWN_RXON_HT20); - sc->rxon.rxchain = htole16( - IWN_RXCHAIN_VALID(3) - | IWN_RXCHAIN_MIMO_COUNT(3) - | IWN_RXCHAIN_IDLE_COUNT(1) - | IWN_RXCHAIN_MIMO_FORCE); - - maxrxampdu = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU); - ampdudensity = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); - } else - maxrxampdu = ampdudensity = 0; -#endif + htflags |= IWN_RXON_HT_PROTMODE(ic->ic_curhtprotmode); + if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + switch (ic->ic_curhtprotmode) { + case IEEE80211_HTINFO_OPMODE_HT20PR: + htflags |= IWN_RXON_HT_MODEPURE40; + break; + default: + htflags |= IWN_RXON_HT_MODEMIXED; + break; + } + } + if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan)) + htflags |= IWN_RXON_HT_HT40MINUS; + } + sc->rxon.flags |= htole32(htflags); sc->rxon.filter |= htole32(IWN_FILTER_BSS); - - DPRINTF(sc, IWN_DEBUG_STATE, - "%s: config chan %d mode %d flags 0x%x cck 0x%x ofdm 0x%x " - "ht_single 0x%x ht_dual 0x%x rxchain 0x%x " - "myaddr %6D wlap %6D bssid %6D associd %d filter 0x%x\n", - __func__, - le16toh(sc->rxon.chan), sc->rxon.mode, le32toh(sc->rxon.flags), - sc->rxon.cck_mask, sc->rxon.ofdm_mask, - sc->rxon.ht_single_mask, sc->rxon.ht_dual_mask, - le16toh(sc->rxon.rxchain), - sc->rxon.myaddr, ":", sc->rxon.wlap, ":", sc->rxon.bssid, ":", - le16toh(sc->rxon.associd), le32toh(sc->rxon.filter)); - error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, hal->rxonsz, 1); + DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x\n", + sc->rxon.chan, sc->rxon.flags); + error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not update configuration, error %d\n", - __func__, error); + "%s: could not update configuration, error %d\n", __func__, + error); return error; } /* Configuration has changed, set TX power accordingly. */ - error = hal->set_txpower(sc, ni->ni_chan, 1); - if (error != 0) { + if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) { device_printf(sc->sc_dev, - "%s: could not set Tx power, error %d\n", __func__, error); + "%s: could not set TX power, error %d\n", __func__, error); return error; } + /* Fake a join to initialize the TX rate. */ + ((struct iwn_node *)ni)->id = IWN_ID_BSS; + iwn_newassoc(ni, 1); + /* Add BSS node. */ memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); node.id = IWN_ID_BSS; -#ifdef notyet - node.htflags = htole32(IWN_AMDPU_SIZE_FACTOR(3) | - IWN_AMDPU_DENSITY(5)); /* 2us */ -#endif - DPRINTF(sc, IWN_DEBUG_STATE, "%s: add BSS node, id %d htflags 0x%x\n", - __func__, node.id, le32toh(node.htflags)); - error = hal->add_node(sc, &node, 1); - if (error != 0) { - device_printf(sc->sc_dev, "could not add BSS node\n"); - return error; + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) { + case IEEE80211_HTCAP_SMPS_ENA: + node.htflags |= htole32(IWN_SMPS_MIMO_DIS); + break; + case IEEE80211_HTCAP_SMPS_DYNAMIC: + node.htflags |= htole32(IWN_SMPS_MIMO_PROT); + break; + } + node.htflags |= htole32(IWN_AMDPU_SIZE_FACTOR(3) | + IWN_AMDPU_DENSITY(5)); /* 4us */ + if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) + node.htflags |= htole32(IWN_NODE_HT40); } - DPRINTF(sc, IWN_DEBUG_STATE, "setting link quality for node %d\n", - node.id); - error = iwn_set_link_quality(sc, node.id, 1); + DPRINTF(sc, IWN_DEBUG_STATE, "%s: adding BSS node\n", __func__); + error = ops->add_node(sc, &node, 1); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not setup MRR for node %d, error %d\n", + "%s: could not add BSS node, error %d\n", __func__, error); + return error; + } + DPRINTF(sc, IWN_DEBUG_STATE, "%s: setting link quality for node %d\n", + __func__, node.id); + if ((error = iwn_set_link_quality(sc, ni)) != 0) { + device_printf(sc->sc_dev, + "%s: could not setup link quality for node %d, error %d\n", __func__, node.id, error); return error; } - error = iwn_init_sensitivity(sc); - if (error != 0) { + if ((error = iwn_init_sensitivity(sc)) != 0) { device_printf(sc->sc_dev, - "%s: could not set sensitivity, error %d\n", - __func__, error); + "%s: could not set sensitivity, error %d\n", __func__, + error); return error; } - /* Start periodic calibration timer. */ sc->calib.state = IWN_CALIB_STATE_ASSOC; - iwn_calib_reset(sc); + sc->calib_cnt = 0; + callout_reset(&sc->calib_to, msecs_to_ticks(500), iwn_calib_timeout, + sc); /* Link LED always on while associated. */ iwn_set_led(sc, IWN_LED_LINK, 0, 1); - return 0; -#undef MS } -#if 0 /* HT */ /* * This function is called by upper layer when an ADDBA request is received * from another STA and before the ADDBA response is sent. */ static int -iwn_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, - uint8_t tid) +iwn_ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap, + int baparamset, int batimeout, int baseqctl) { - struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; - struct iwn_softc *sc = ic->ic_softc; +#define MS(_v, _f) (((_v) & _f) >> _f##_S) + struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; + struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (void *)ni; struct iwn_node_info node; + uint16_t ssn; + uint8_t tid; + int error; + + tid = MS(le16toh(baparamset), IEEE80211_BAPS_TID); + ssn = MS(le16toh(baseqctl), IEEE80211_BASEQ_START); memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_ADDBA; node.addba_tid = tid; - node.addba_ssn = htole16(ba->ba_winstart); + node.addba_ssn = htole16(ssn); DPRINTF(sc, IWN_DEBUG_RECV, "ADDBA RA=%d TID=%d SSN=%d\n", - wn->id, tid, ba->ba_winstart)); - return sc->sc_hal->add_node(sc, &node, 1); + wn->id, tid, ssn); + error = ops->add_node(sc, &node, 1); + if (error != 0) + return error; + return sc->sc_ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl); +#undef MS } /* * This function is called by upper layer on teardown of an HT-immediate - * Block Ack agreement (eg. uppon receipt of a DELBA frame.) + * Block Ack agreement (eg. uppon receipt of a DELBA frame). */ static void -iwn_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, - uint8_t tid) +iwn_ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap) { - struct iwn_softc *sc = ic->ic_softc; + struct ieee80211com *ic = ni->ni_ic; + struct iwn_softc *sc = ic->ic_ifp->if_softc; + struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (void *)ni; struct iwn_node_info node; + uint8_t tid; + + /* XXX: tid as an argument */ + for (tid = 0; tid < WME_NUM_TID; tid++) { + if (&ni->ni_rx_ampdu[tid] == rap) + break; + } memset(&node, 0, sizeof node); node.id = wn->id; @@ -5022,7 +5563,58 @@ iwn_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, node.flags = IWN_FLAG_SET_DELBA; node.delba_tid = tid; DPRINTF(sc, IWN_DEBUG_RECV, "DELBA RA=%d TID=%d\n", wn->id, tid); - (void)sc->sc_hal->add_node(sc, &node, 1); + (void)ops->add_node(sc, &node, 1); + sc->sc_ampdu_rx_stop(ni, rap); +} + +static int +iwn_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, + int dialogtoken, int baparamset, int batimeout) +{ + struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; + int qid; + + for (qid = sc->firstaggqueue; qid < sc->ntxqs; qid++) { + if (sc->qid2tap[qid] == NULL) + break; + } + if (qid == sc->ntxqs) { + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: not free aggregation queue\n", + __func__); + return 0; + } + tap->txa_private = malloc(sizeof(int), M_DEVBUF, M_NOWAIT); + if (tap->txa_private == NULL) { + device_printf(sc->sc_dev, + "%s: failed to alloc TX aggregation structure\n", __func__); + return 0; + } + sc->qid2tap[qid] = tap; + *(int *)tap->txa_private = qid; + return sc->sc_addba_request(ni, tap, dialogtoken, baparamset, + batimeout); +} + +static int +iwn_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, + int code, int baparamset, int batimeout) +{ + struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; + int qid = *(int *)tap->txa_private; + uint8_t tid = WME_AC_TO_TID(tap->txa_ac); + int ret; + + if (code == IEEE80211_STATUS_SUCCESS) { + ni->ni_txseqs[tid] = tap->txa_start & 0xfff; + ret = iwn_ampdu_tx_start(ni->ni_ic, ni, tid); + if (ret != 1) + return ret; + } else { + sc->qid2tap[qid] = NULL; + free(tap->txa_private, M_DEVBUF); + tap->txa_private = NULL; + } + return sc->sc_addba_response(ni, tap, code, baparamset, batimeout); } /* @@ -5033,12 +5625,12 @@ static int iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { - struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; - struct iwn_softc *sc = ic->ic_softc; - const struct iwn_hal *hal = sc->sc_hal; + struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)]; + struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; + struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (void *)ni; struct iwn_node_info node; - int error; + int error, qid; /* Enable TX for the specified RA/TID. */ wn->disable_tid &= ~(1 << tid); @@ -5047,38 +5639,47 @@ iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DISABLE_TID; node.disable_tid = htole16(wn->disable_tid); - error = hal->add_node(sc, &node, 1); + error = ops->add_node(sc, &node, 1); if (error != 0) - return error; + return 0; if ((error = iwn_nic_lock(sc)) != 0) - return error; - hal->ampdu_tx_start(sc, ni, tid, ba->ba_winstart); + return 0; + qid = *(int *)tap->txa_private; + ops->ampdu_tx_start(sc, ni, qid, tid, tap->txa_start & 0xfff); iwn_nic_unlock(sc); - return 0; + + iwn_set_link_quality(sc, ni); + return 1; } static void -iwn_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, - uint8_t tid) +iwn_ampdu_tx_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { - struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; - struct iwn_softc *sc = ic->ic_softc; - int error; + struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; + struct iwn_ops *ops = &sc->ops; + uint8_t tid = WME_AC_TO_TID(tap->txa_ac); + int qid; - error = iwn_nic_lock(sc); - if (error != 0) + if (tap->txa_private == NULL) return; - sc->sc_hal->ampdu_tx_stop(sc, tid, ba->ba_winstart); + + qid = *(int *)tap->txa_private; + if (iwn_nic_lock(sc) != 0) + return; + ops->ampdu_tx_stop(sc, qid, tid, tap->txa_start & 0xfff); iwn_nic_unlock(sc); + sc->qid2tap[qid] = NULL; + free(tap->txa_private, M_DEVBUF); + tap->txa_private = NULL; + sc->sc_addba_stop(ni, tap); } static void iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, - uint8_t tid, uint16_t ssn) + int qid, uint8_t tid, uint16_t ssn) { struct iwn_node *wn = (void *)ni; - int qid = 7 + tid; /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), @@ -5092,6 +5693,7 @@ iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, iwn_prph_setbits(sc, IWN4965_SCHED_QCHAIN_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ + sc->txq[qid].cur = sc->txq[qid].read = (ssn & 0xff); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff)); iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn); @@ -5112,10 +5714,8 @@ iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, } static void -iwn4965_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) +iwn4965_ampdu_tx_stop(struct iwn_softc *sc, int qid, uint8_t tid, uint16_t ssn) { - int qid = 7 + tid; - /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_CHGACT); @@ -5134,10 +5734,9 @@ iwn4965_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) static void iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, - uint8_t tid, uint16_t ssn) + int qid, uint8_t tid, uint16_t ssn) { struct iwn_node *wn = (void *)ni; - int qid = 10 + tid; /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), @@ -5154,6 +5753,7 @@ iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, iwn_prph_setbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ + sc->txq[qid].cur = sc->txq[qid].read = (ssn & 0xff); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff)); iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn); @@ -5170,10 +5770,8 @@ iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, } static void -iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) +iwn5000_ampdu_tx_stop(struct iwn_softc *sc, int qid, uint8_t tid, uint16_t ssn) { - int qid = 10 + tid; - /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_CHGACT); @@ -5192,203 +5790,59 @@ iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid]); } -#endif /* - * Send calibration results to the runtime firmware. These results were - * obtained on first boot from the initialization firmware, or by reading - * the EEPROM for crystal calibration. + * Query calibration tables from the initialization firmware. We do this + * only once at first boot. Called from a process context. */ static int -iwn5000_send_calib_results(struct iwn_softc *sc) +iwn5000_query_calibration(struct iwn_softc *sc) { - struct iwn_calib_info *calib_result; - int idx, error; - - for (idx = 0; idx < IWN_CALIB_NUM; idx++) { - calib_result = &sc->calib_results[idx]; - - /* No support for this type of calibration. */ - if ((sc->calib_init & (1 << idx)) == 0) - continue; - - /* No calibration result available. */ - if (calib_result->buf == NULL) - continue; - - DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "%s: send calibration result idx=%d, len=%d\n", - __func__, idx, calib_result->len); - - error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, calib_result->buf, - calib_result->len, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not send calibration result " - "idx=%d, error=%d\n", - __func__, idx, error); - return error; - } - } - return 0; -} - -/* - * Save calibration result at the given index. The index determines - * in which order the results are sent to the runtime firmware. - */ -static int -iwn5000_save_calib_result(struct iwn_softc *sc, struct iwn_phy_calib *calib, - int len, int idx) -{ - struct iwn_calib_info *calib_result = &sc->calib_results[idx]; - - DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "%s: saving calibration result code=%d, idx=%d, len=%d\n", - __func__, calib->code, idx, len); - - if (calib_result->buf != NULL) - free(calib_result->buf, M_DEVBUF); - - calib_result->buf = malloc(len, M_DEVBUF, M_NOWAIT); - if (calib_result->buf == NULL) { - device_printf(sc->sc_dev, - "%s: not enough memory for calibration result " - "code=%d, len=%d\n", __func__, calib->code, len); - return ENOMEM; - } - - calib_result->len = len; - memcpy(calib_result->buf, calib, len); - return 0; -} - -static void -iwn5000_free_calib_results(struct iwn_softc *sc) -{ - struct iwn_calib_info *calib_result; - int idx; - - for (idx = 0; idx < IWN_CALIB_NUM; idx++) { - calib_result = &sc->calib_results[idx]; - - if (calib_result->buf != NULL) - free(calib_result->buf, M_DEVBUF); - - calib_result->buf = NULL; - calib_result->len = 0; - } -} - -/* - * Obtain the crystal calibration result from the EEPROM. - */ -static int -iwn5000_chrystal_calib(struct iwn_softc *sc) -{ - struct iwn5000_phy_calib_crystal cmd; - uint32_t base, crystal; - uint16_t val; - - /* Read crystal calibration. */ - iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2); - base = le16toh(val); - iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, &crystal, - sizeof(uint32_t)); - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: crystal calibration=0x%08x\n", - __func__, le32toh(crystal)); - - memset(&cmd, 0, sizeof cmd); - cmd.code = IWN5000_PHY_CALIB_CRYSTAL; - cmd.ngroups = 1; - cmd.isvalid = 1; - cmd.cap_pin[0] = le32toh(crystal) & 0xff; - cmd.cap_pin[1] = (le32toh(crystal) >> 16) & 0xff; - - return iwn5000_save_calib_result(sc, (struct iwn_phy_calib *)&cmd, - sizeof cmd, IWN_CALIB_IDX_XTAL); -} - -/* - * Query calibration results from the initialization firmware. We do this - * only once at first boot. - */ -static int -iwn5000_send_calib_query(struct iwn_softc *sc, uint32_t cfg) -{ -#define CALIB_INIT_CFG 0xffffffff; struct iwn5000_calib_config cmd; int error; memset(&cmd, 0, sizeof cmd); - cmd.ucode.once.enable = CALIB_INIT_CFG; - if (cfg == 0) { - cmd.ucode.once.start = CALIB_INIT_CFG; - cmd.ucode.once.send = CALIB_INIT_CFG; - cmd.ucode.flags = CALIB_INIT_CFG; - } else - cmd.ucode.once.start = cfg; - - DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "%s: query calibration results, cfg %x\n", __func__, cfg); - + cmd.ucode.once.enable = 0xffffffff; + cmd.ucode.once.start = 0xffffffff; + cmd.ucode.once.send = 0xffffffff; + cmd.ucode.flags = 0xffffffff; + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n", + __func__); error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0); if (error != 0) return error; /* Wait at most two seconds for calibration to complete. */ if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) - error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", 2 * hz); - + error = msleep(sc, &sc->sc_mtx, PCATCH, "iwncal", 2 * hz); return error; -#undef CALIB_INIT_CFG } /* - * Process a CALIBRATION_RESULT notification sent by the initialization - * firmware on response to a CMD_CALIB_CONFIG command. + * Send calibration results to the runtime firmware. These results were + * obtained on first boot from the initialization firmware. */ static int -iwn5000_rx_calib_result(struct iwn_softc *sc, struct iwn_rx_desc *desc, - struct iwn_rx_data *data) +iwn5000_send_calibration(struct iwn_softc *sc) { -#define FRAME_SIZE_MASK 0x3fff - struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); - int len, idx; + int idx, error; - bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); - len = (le32toh(desc->len) & FRAME_SIZE_MASK); - - /* Remove length field itself. */ - len -= 4; - - /* - * Determine the order in which the results will be send to the - * runtime firmware. - */ - switch (calib->code) { - case IWN5000_PHY_CALIB_DC: - idx = IWN_CALIB_IDX_DC; - break; - case IWN5000_PHY_CALIB_LO: - idx = IWN_CALIB_IDX_LO; - break; - case IWN5000_PHY_CALIB_TX_IQ: - idx = IWN_CALIB_IDX_TX_IQ; - break; - case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: - idx = IWN_CALIB_IDX_TX_IQ_PERIODIC; - break; - case IWN5000_PHY_CALIB_BASE_BAND: - idx = IWN_CALIB_IDX_BASE_BAND; - break; - default: + for (idx = 0; idx < 5; idx++) { + if (sc->calibcmd[idx].buf == NULL) + continue; /* No results available. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "%s: unknown calibration code=%d\n", __func__, calib->code); - return EINVAL; + "send calibration result idx=%d len=%d\n", idx, + sc->calibcmd[idx].len); + error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf, + sc->calibcmd[idx].len, 0); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not send calibration result, error %d\n", + __func__, error); + return error; + } } - return iwn5000_save_calib_result(sc, calib, len, idx); -#undef FRAME_SIZE_MASK + return 0; } static int @@ -5418,9 +5872,43 @@ iwn5000_send_wimax_coex(struct iwn_softc *sc) return iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0); } +static int +iwn5000_crystal_calib(struct iwn_softc *sc) +{ + struct iwn5000_phy_calib_crystal cmd; + + memset(&cmd, 0, sizeof cmd); + cmd.code = IWN5000_PHY_CALIB_CRYSTAL; + cmd.ngroups = 1; + cmd.isvalid = 1; + cmd.cap_pin[0] = le32toh(sc->eeprom_crystal) & 0xff; + cmd.cap_pin[1] = (le32toh(sc->eeprom_crystal) >> 16) & 0xff; + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "sending crystal calibration %d, %d\n", + cmd.cap_pin[0], cmd.cap_pin[1]); + return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); +} + +static int +iwn5000_temp_offset_calib(struct iwn_softc *sc) +{ + struct iwn5000_phy_calib_temp_offset cmd; + + memset(&cmd, 0, sizeof cmd); + cmd.code = IWN5000_PHY_CALIB_TEMP_OFFSET; + cmd.ngroups = 1; + cmd.isvalid = 1; + if (sc->eeprom_temp != 0) + cmd.offset = htole16(sc->eeprom_temp); + else + cmd.offset = htole16(IWN_DEFAULT_TEMP_OFFSET); + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "setting radio sensor offset to %d\n", + le16toh(cmd.offset)); + return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); +} + /* * This function is called after the runtime firmware notifies us of its - * readiness (called in a process context.) + * readiness (called in a process context). */ static int iwn4965_post_alive(struct iwn_softc *sc) @@ -5435,7 +5923,7 @@ iwn4965_post_alive(struct iwn_softc *sc) iwn_mem_set_region_4(sc, sc->sched_base + IWN4965_SCHED_CTX_OFF, 0, IWN4965_SCHED_CTX_LEN / sizeof (uint32_t)); - /* Set physical address of TX scheduler rings (1KB aligned.) */ + /* Set physical address of TX scheduler rings (1KB aligned). */ iwn_prph_write(sc, IWN4965_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10); IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); @@ -5473,7 +5961,7 @@ iwn4965_post_alive(struct iwn_softc *sc) /* * This function is called after the initialization or runtime firmware - * notifies us of its readiness (called in a process context.) + * notifies us of its readiness (called in a process context). */ static int iwn5000_post_alive(struct iwn_softc *sc) @@ -5485,8 +5973,7 @@ iwn5000_post_alive(struct iwn_softc *sc) iwn5000_ict_reset(sc); #endif - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; /* Clear TX scheduler state in SRAM. */ @@ -5494,7 +5981,7 @@ iwn5000_post_alive(struct iwn_softc *sc) iwn_mem_set_region_4(sc, sc->sched_base + IWN5000_SCHED_CTX_OFF, 0, IWN5000_SCHED_CTX_LEN / sizeof (uint32_t)); - /* Set physical address of TX scheduler rings (1KB aligned.) */ + /* Set physical address of TX scheduler rings (1KB aligned). */ iwn_prph_write(sc, IWN5000_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10); IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); @@ -5536,40 +6023,24 @@ iwn5000_post_alive(struct iwn_softc *sc) __func__, error); return error; } - - if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) { - /* - * Start calibration by setting and sending the chrystal - * calibration first, this must be done before we are able - * to query the other calibration results. - */ - error = iwn5000_chrystal_calib(sc); + if (sc->hw_type != IWN_HW_REV_TYPE_5150) { + /* Perform crystal calibration. */ + error = iwn5000_crystal_calib(sc); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not set chrystal calibration, " - "error=%d\n", __func__, error); - return error; - } - error = iwn5000_send_calib_results(sc); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not send chrystal calibration, " - "error=%d\n", __func__, error); - return error; - } - - /* - * Query other calibration results from the initialization - * firmware. - */ - error = iwn5000_send_calib_query(sc, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not query calibration, error=%d\n", + "%s: crystal calibration failed, error %d\n", + __func__, error); + return error; + } + } + if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) { + /* Query calibration from the initialization firmware. */ + if ((error = iwn5000_query_calibration(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not query calibration, error %d\n", __func__, error); return error; } - /* * We have the calibration results now, reboot with the * runtime firmware (call ourselves recursively!) @@ -5577,31 +6048,15 @@ iwn5000_post_alive(struct iwn_softc *sc) iwn_hw_stop(sc); error = iwn_hw_init(sc); } else { - /* - * Send calibration results obtained from the initialization - * firmware to the runtime firmware. - */ - error = iwn5000_send_calib_results(sc); - - /* - * Tell the runtime firmware to do certain calibration types. - */ - if (sc->calib_runtime != 0) { - error = iwn5000_send_calib_query(sc, sc->calib_runtime); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not send query calibration, " - "error=%d, cfg=%x\n", __func__, error, - sc->calib_runtime); - } - } + /* Send calibration results to runtime firmware. */ + error = iwn5000_send_calibration(sc); } return error; } /* * The firmware boot code is small and is intended to be copied directly into - * the NIC internal memory (no DMA transfer.) + * the NIC internal memory (no DMA transfer). */ static int iwn4965_load_bootcode(struct iwn_softc *sc, const uint8_t *ucode, int size) @@ -5610,8 +6065,7 @@ iwn4965_load_bootcode(struct iwn_softc *sc, const uint8_t *ucode, int size) size /= sizeof (uint32_t); - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; /* Copy microcode image into NIC memory. */ @@ -5655,14 +6109,13 @@ iwn4965_load_firmware(struct iwn_softc *sc) /* Copy initialization sections into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, fw->init.data, fw->init.datasz); - bus_dmamap_sync(sc->fw_dma.tag, dma->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ, fw->init.text, fw->init.textsz); - bus_dmamap_sync(sc->fw_dma.tag, dma->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); /* Tell adapter where to find initialization sections. */ - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->init.datasz); @@ -5682,8 +6135,7 @@ iwn4965_load_firmware(struct iwn_softc *sc) IWN_WRITE(sc, IWN_RESET, 0); /* Wait at most one second for first alive notification. */ - error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz); - if (error) { + if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz)) != 0) { device_printf(sc->sc_dev, "%s: timeout waiting for adapter to initialize, error %d\n", __func__, error); @@ -5696,16 +6148,14 @@ iwn4965_load_firmware(struct iwn_softc *sc) /* Copy runtime sections into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, fw->main.data, fw->main.datasz); - bus_dmamap_sync(sc->fw_dma.tag, dma->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ, fw->main.text, fw->main.textsz); - bus_dmamap_sync(sc->fw_dma.tag, dma->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); /* Tell adapter where to find runtime sections. */ - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; - iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->main.datasz); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR, @@ -5726,10 +6176,9 @@ iwn5000_load_firmware_section(struct iwn_softc *sc, uint32_t dst, /* Copy firmware section into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, section, size); - bus_dmamap_sync(sc->fw_dma.tag, dma->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL), @@ -5752,7 +6201,7 @@ iwn5000_load_firmware_section(struct iwn_softc *sc, uint32_t dst, iwn_nic_unlock(sc); /* Wait at most five seconds for FH DMA transfer to complete. */ - return msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz); + return msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", 5 * hz); } static int @@ -5797,7 +6246,7 @@ iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) size_t hdrlen = 24; uint32_t rev; - ptr = (const uint32_t *)sc->fw_fp->data; + ptr = (const uint32_t *)fw->data; rev = le32toh(*ptr++); /* Check firmware API version. */ @@ -5812,8 +6261,7 @@ iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) ptr++; } if (fw->size < hdrlen) { - device_printf(sc->sc_dev, - "%s: firmware file too short: %zu bytes\n", + device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } @@ -5826,8 +6274,7 @@ iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) /* Check that all firmware sections fit. */ if (fw->size < hdrlen + fw->main.textsz + fw->main.datasz + fw->init.textsz + fw->init.datasz + fw->boot.textsz) { - device_printf(sc->sc_dev, - "%s: firmware file too short: %zu bytes\n", + device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } @@ -5838,14 +6285,13 @@ iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) fw->init.text = fw->main.data + fw->main.datasz; fw->init.data = fw->init.text + fw->init.textsz; fw->boot.text = fw->init.data + fw->init.datasz; - return 0; } /* * Extract text and data sections from a TLV firmware image. */ -int +static int iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, uint16_t alt) { @@ -5853,21 +6299,21 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, const struct iwn_fw_tlv *tlv; const uint8_t *ptr, *end; uint64_t altmask; - uint32_t len; + uint32_t len, tmp; if (fw->size < sizeof (*hdr)) { - device_printf(sc->sc_dev, - "%s: firmware file too short: %zu bytes\n", + device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } hdr = (const struct iwn_fw_tlv_hdr *)fw->data; if (hdr->signature != htole32(IWN_FW_SIGNATURE)) { - device_printf(sc->sc_dev, - "%s: bad firmware file signature 0x%08x\n", + device_printf(sc->sc_dev, "%s: bad firmware signature 0x%08x\n", __func__, le32toh(hdr->signature)); return EINVAL; } + DPRINTF(sc, IWN_DEBUG_RESET, "FW: \"%.64s\", build 0x%x\n", hdr->descr, + le32toh(hdr->build)); /* * Select the closest supported alternative that is less than @@ -5876,6 +6322,7 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, altmask = le64toh(hdr->altmask); while (alt > 0 && !(altmask & (1ULL << alt))) alt--; /* Downgrade. */ + DPRINTF(sc, IWN_DEBUG_RESET, "using alternative %d\n", alt); ptr = (const uint8_t *)(hdr + 1); end = (const uint8_t *)(fw->data + fw->size); @@ -5888,8 +6335,8 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, ptr += sizeof (*tlv); if (ptr + len > end) { device_printf(sc->sc_dev, - "%s: firmware file too short: %zu bytes\n", - __func__, fw->size); + "%s: firmware too short: %zu bytes\n", __func__, + fw->size); return EINVAL; } /* Skip other alternatives. */ @@ -5917,13 +6364,23 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, fw->boot.text = ptr; fw->boot.textsz = len; break; + case IWN_FW_TLV_ENH_SENS: + if (!len) + sc->sc_flags |= IWN_FLAG_ENH_SENS; + break; + case IWN_FW_TLV_PHY_CALIB: + tmp = htole32(*ptr); + if (tmp < 253) { + sc->reset_noise_gain = tmp; + sc->noise_gain = tmp + 1; + } + break; default: DPRINTF(sc, IWN_DEBUG_RESET, - "%s: TLV type %d not handled\n", - __func__, le16toh(tlv->type)); + "TLV type %d not handled\n", le16toh(tlv->type)); break; } -next: /* TLV fields are 32-bit aligned. */ + next: /* TLV fields are 32-bit aligned. */ ptr += (len + 3) & ~3; } return 0; @@ -5932,7 +6389,6 @@ next: /* TLV fields are 32-bit aligned. */ static int iwn_read_firmware(struct iwn_softc *sc) { - const struct iwn_hal *hal = sc->sc_hal; struct iwn_fw_info *fw = &sc->fw; int error; @@ -5943,9 +6399,8 @@ iwn_read_firmware(struct iwn_softc *sc) /* Read firmware image from filesystem. */ sc->fw_fp = firmware_get(sc->fwname); if (sc->fw_fp == NULL) { - device_printf(sc->sc_dev, - "%s: could not load firmare image \"%s\"\n", __func__, - sc->fwname); + device_printf(sc->sc_dev, "%s: could not read firmware %s\n", + __func__, sc->fwname); IWN_LOCK(sc); return EINVAL; } @@ -5954,9 +6409,10 @@ iwn_read_firmware(struct iwn_softc *sc) fw->size = sc->fw_fp->datasize; fw->data = (const uint8_t *)sc->fw_fp->data; if (fw->size < sizeof (uint32_t)) { - device_printf(sc->sc_dev, - "%s: firmware file too short: %zu bytes\n", + device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); + firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); + sc->fw_fp = NULL; return EINVAL; } @@ -5967,19 +6423,24 @@ iwn_read_firmware(struct iwn_softc *sc) error = iwn_read_firmware_tlv(sc, fw, 1); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not read firmware sections\n", __func__); + "%s: could not read firmware sections, error %d\n", + __func__, error); + firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); + sc->fw_fp = NULL; return error; } /* Make sure text and data sections fit in hardware memory. */ - if (fw->main.textsz > hal->fw_text_maxsz || - fw->main.datasz > hal->fw_data_maxsz || - fw->init.textsz > hal->fw_text_maxsz || - fw->init.datasz > hal->fw_data_maxsz || + if (fw->main.textsz > sc->fw_text_maxsz || + fw->main.datasz > sc->fw_data_maxsz || + fw->init.textsz > sc->fw_text_maxsz || + fw->init.datasz > sc->fw_data_maxsz || fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ || (fw->boot.textsz & 3) != 0) { - device_printf(sc->sc_dev, - "%s: firmware sections too large\n", __func__); + device_printf(sc->sc_dev, "%s: firmware sections too large\n", + __func__); + firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); + sc->fw_fp = NULL; return EINVAL; } @@ -6009,24 +6470,24 @@ iwn_clock_wait(struct iwn_softc *sc) static int iwn_apm_init(struct iwn_softc *sc) { - uint32_t tmp; + uint32_t reg; int error; - /* Disable L0s exit timer (NMI bug workaround.) */ + /* Disable L0s exit timer (NMI bug workaround). */ IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_DIS_L0S_TIMER); - /* Don't wait for ICH L0s (ICH bug workaround.) */ + /* Don't wait for ICH L0s (ICH bug workaround). */ IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_L1A_NO_L0S_RX); - /* Set FH wait threshold to max (HW bug under stress workaround.) */ + /* Set FH wait threshold to max (HW bug under stress workaround). */ IWN_SETBITS(sc, IWN_DBG_HPET_MEM, 0xffff0000); /* Enable HAP INTA to move adapter from L1a to L0s. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_HAP_WAKE_L1A); /* Retrieve PCIe Active State Power Management (ASPM). */ - tmp = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); + reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ - if (tmp & 0x02) /* L1 Entry enabled. */ + if (reg & 0x02) /* L1 Entry enabled. */ IWN_SETBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); else IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); @@ -6036,16 +6497,13 @@ iwn_apm_init(struct iwn_softc *sc) IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT); /* Wait for clock stabilization before accessing prph. */ - error = iwn_clock_wait(sc); - if (error != 0) + if ((error = iwn_clock_wait(sc)) != 0) return error; - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; - if (sc->hw_type == IWN_HW_REV_TYPE_4965) { - /* Enable DMA and BSM (Bootstrap State Machine.) */ + /* Enable DMA and BSM (Bootstrap State Machine). */ iwn_prph_write(sc, IWN_APMG_CLK_EN, IWN_APMG_CLK_CTRL_DMA_CLK_RQT | IWN_APMG_CLK_CTRL_BSM_CLK_RQT); @@ -6055,7 +6513,6 @@ iwn_apm_init(struct iwn_softc *sc) IWN_APMG_CLK_CTRL_DMA_CLK_RQT); } DELAY(20); - /* Disable L1-Active. */ iwn_prph_setbits(sc, IWN_APMG_PCI_STT, IWN_APMG_PCI_STT_L1A_DIS); iwn_nic_unlock(sc); @@ -6075,8 +6532,7 @@ iwn_apm_stop_master(struct iwn_softc *sc) return; DELAY(10); } - device_printf(sc->sc_dev, "%s: timeout waiting for master\n", - __func__); + device_printf(sc->sc_dev, "%s: timeout waiting for master\n", __func__); } static void @@ -6125,8 +6581,7 @@ iwn5000_nic_config(struct iwn_softc *sc) IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI); - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_EARLY_PWROFF_DIS); @@ -6147,10 +6602,13 @@ iwn5000_nic_config(struct iwn_softc *sc) /* Use internal power amplifier only. */ IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA); } - if (sc->hw_type == IWN_HW_REV_TYPE_6050 && sc->calib_ver >= 6) { + if ((sc->hw_type == IWN_HW_REV_TYPE_6050 || + sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) { /* Indicate that ROM calibration version is >=6. */ IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); } + if (sc->hw_type == IWN_HW_REV_TYPE_6005) + IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2); return 0; } @@ -6196,41 +6654,37 @@ iwn_hw_prepare(struct iwn_softc *sc) static int iwn_hw_init(struct iwn_softc *sc) { - const struct iwn_hal *hal = sc->sc_hal; + struct iwn_ops *ops = &sc->ops; int error, chnl, qid; /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); - error = iwn_apm_init(sc); - if (error != 0) { + if ((error = iwn_apm_init(sc)) != 0) { device_printf(sc->sc_dev, - "%s: could not power ON adapter, error %d\n", - __func__, error); + "%s: could not power ON adapter, error %d\n", __func__, + error); return error; } /* Select VMAIN power source. */ - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_PWR_SRC_MASK); iwn_nic_unlock(sc); /* Perform adapter-specific initialization. */ - error = hal->nic_config(sc); - if (error != 0) + if ((error = ops->nic_config(sc)) != 0) return error; /* Initialize RX ring. */ - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0); IWN_WRITE(sc, IWN_FH_RX_WPTR, 0); - /* Set physical address of RX ring (256-byte aligned.) */ + /* Set physical address of RX ring (256-byte aligned). */ IWN_WRITE(sc, IWN_FH_RX_BASE, sc->rxq.desc_dma.paddr >> 8); - /* Set physical address of RX status (16-byte aligned.) */ + /* Set physical address of RX status (16-byte aligned). */ IWN_WRITE(sc, IWN_FH_STATUS_WPTR, sc->rxq.stat_dma.paddr >> 4); /* Enable RX. */ IWN_WRITE(sc, IWN_FH_RX_CONFIG, @@ -6243,28 +6697,27 @@ iwn_hw_init(struct iwn_softc *sc) iwn_nic_unlock(sc); IWN_WRITE(sc, IWN_FH_RX_WPTR, (IWN_RX_RING_COUNT - 1) & ~7); - error = iwn_nic_lock(sc); - if (error != 0) + if ((error = iwn_nic_lock(sc)) != 0) return error; /* Initialize TX scheduler. */ - iwn_prph_write(sc, hal->sched_txfact_addr, 0); + iwn_prph_write(sc, sc->sched_txfact_addr, 0); - /* Set physical address of "keep warm" page (16-byte aligned.) */ + /* Set physical address of "keep warm" page (16-byte aligned). */ IWN_WRITE(sc, IWN_FH_KW_ADDR, sc->kw_dma.paddr >> 4); /* Initialize TX rings. */ - for (qid = 0; qid < hal->ntxqs; qid++) { + for (qid = 0; qid < sc->ntxqs; qid++) { struct iwn_tx_ring *txq = &sc->txq[qid]; - /* Set physical address of TX ring (256-byte aligned.) */ + /* Set physical address of TX ring (256-byte aligned). */ IWN_WRITE(sc, IWN_FH_CBBC_QUEUE(qid), txq->desc_dma.paddr >> 8); } iwn_nic_unlock(sc); /* Enable DMA channels. */ - for (chnl = 0; chnl < hal->ndmachnls; chnl++) { + for (chnl = 0; chnl < sc->ndmachnls; chnl++) { IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), IWN_FH_TX_CONFIG_DMA_ENA | IWN_FH_TX_CONFIG_DMA_CREDIT_ENA); @@ -6285,30 +6738,30 @@ iwn_hw_init(struct iwn_softc *sc) IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); - error = hal->load_firmware(sc); - if (error != 0) { + /* Enable shadow registers. */ + if (sc->hw_type >= IWN_HW_REV_TYPE_6000) + IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff); + + if ((error = ops->load_firmware(sc)) != 0) { device_printf(sc->sc_dev, - "%s: could not load firmware, error %d\n", - __func__, error); + "%s: could not load firmware, error %d\n", __func__, + error); return error; } /* Wait at most one second for firmware alive notification. */ - error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz); - if (error != 0) { + if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz)) != 0) { device_printf(sc->sc_dev, "%s: timeout waiting for adapter to initialize, error %d\n", __func__, error); return error; } /* Do post-firmware initialization. */ - return hal->post_alive(sc); + return ops->post_alive(sc); } static void iwn_hw_stop(struct iwn_softc *sc) { - const struct iwn_hal *hal = sc->sc_hal; - uint32_t tmp; int chnl, qid, ntries; IWN_WRITE(sc, IWN_RESET, IWN_RESET_NEVO); @@ -6323,15 +6776,14 @@ iwn_hw_stop(struct iwn_softc *sc) iwn_nic_unlock(sc); /* Stop TX scheduler. */ - iwn_prph_write(sc, hal->sched_txfact_addr, 0); + iwn_prph_write(sc, sc->sched_txfact_addr, 0); /* Stop all DMA channels. */ if (iwn_nic_lock(sc) == 0) { - for (chnl = 0; chnl < hal->ndmachnls; chnl++) { + for (chnl = 0; chnl < sc->ndmachnls; chnl++) { IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), 0); for (ntries = 0; ntries < 200; ntries++) { - tmp = IWN_READ(sc, IWN_FH_TX_STATUS); - if ((tmp & IWN_FH_TX_STATUS_IDLE(chnl)) == + if (IWN_READ(sc, IWN_FH_TX_STATUS) & IWN_FH_TX_STATUS_IDLE(chnl)) break; DELAY(10); @@ -6344,7 +6796,7 @@ iwn_hw_stop(struct iwn_softc *sc) iwn_reset_rx_ring(sc, &sc->rxq); /* Reset all TX rings. */ - for (qid = 0; qid < hal->ntxqs; qid++) + for (qid = 0; qid < sc->ntxqs; qid++) iwn_reset_tx_ring(sc, &sc->txq[qid]); if (iwn_nic_lock(sc) == 0) { @@ -6353,11 +6805,43 @@ iwn_hw_stop(struct iwn_softc *sc) iwn_nic_unlock(sc); } DELAY(5); - /* Power OFF adapter. */ iwn_apm_stop(sc); } +static void +iwn_radio_on(void *arg0, int pending) +{ + struct iwn_softc *sc = arg0; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + if (vap != NULL) { + iwn_init(sc); + ieee80211_init(vap); + } +} + +static void +iwn_radio_off(void *arg0, int pending) +{ + struct iwn_softc *sc = arg0; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + iwn_stop(sc); + if (vap != NULL) + ieee80211_stop(vap); + + /* Enable interrupts to get RF toggle notification. */ + IWN_LOCK(sc); + IWN_WRITE(sc, IWN_INT, 0xffffffff); + IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); + IWN_UNLOCK(sc); +} + static void iwn_init_locked(struct iwn_softc *sc) { @@ -6366,9 +6850,8 @@ iwn_init_locked(struct iwn_softc *sc) IWN_LOCK_ASSERT(sc); - error = iwn_hw_prepare(sc); - if (error != 0) { - device_printf(sc->sc_dev, "%s: hardware not ready, eror %d\n", + if ((error = iwn_hw_prepare(sc)) != 0) { + device_printf(sc->sc_dev, "%s: hardware not ready, error %d\n", __func__, error); goto fail; } @@ -6381,7 +6864,6 @@ iwn_init_locked(struct iwn_softc *sc) if (!(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)) { device_printf(sc->sc_dev, "radio is disabled by hardware switch\n"); - /* Enable interrupts to get RF toggle notifications. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); @@ -6389,11 +6871,10 @@ iwn_init_locked(struct iwn_softc *sc) } /* Read firmware images from the filesystem. */ - error = iwn_read_firmware(sc); - if (error != 0) { + if ((error = iwn_read_firmware(sc)) != 0) { device_printf(sc->sc_dev, - "%s: could not read firmware, error %d\n", - __func__, error); + "%s: could not read firmware, error %d\n", __func__, + error); goto fail; } @@ -6403,27 +6884,26 @@ iwn_init_locked(struct iwn_softc *sc) sc->fw_fp = NULL; if (error != 0) { device_printf(sc->sc_dev, - "%s: could not initialize hardware, error %d\n", - __func__, error); + "%s: could not initialize hardware, error %d\n", __func__, + error); goto fail; } /* Configure adapter now that it is ready. */ - error = iwn_config(sc); - if (error != 0) { + if ((error = iwn_config(sc)) != 0) { device_printf(sc->sc_dev, - "%s: could not configure device, error %d\n", - __func__, error); + "%s: could not configure device, error %d\n", __func__, + error); goto fail; } ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; + callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); return; -fail: - iwn_stop_locked(sc); +fail: iwn_stop_locked(sc); } static void @@ -6449,7 +6929,8 @@ iwn_stop_locked(struct iwn_softc *sc) IWN_LOCK_ASSERT(sc); sc->sc_tx_timer = 0; - callout_stop(&sc->sc_timer_to); + callout_stop(&sc->watchdog_to); + callout_stop(&sc->calib_to); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* Power OFF hardware. */ @@ -6506,12 +6987,24 @@ iwn_set_channel(struct ieee80211com *ic) const struct ieee80211_channel *c = ic->ic_curchan; struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; + int error; IWN_LOCK(sc); sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); + + /* + * Only need to set the channel in Monitor mode. AP scanning and auth + * are already taken care of by their respective firmware commands. + */ + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + error = iwn_config(sc); + if (error != 0) + device_printf(sc->sc_dev, + "%s: error %d settting channel\n", __func__, error); + } IWN_UNLOCK(sc); } @@ -6543,48 +7036,6 @@ iwn_scan_mindwell(struct ieee80211_scan_state *ss) /* NB: don't try to abort scan; wait for firmware to finish */ } -static struct iwn_eeprom_chan * -iwn_find_eeprom_channel(struct iwn_softc *sc, struct ieee80211_channel *c) -{ - int i, j; - - for (j = 0; j < 7; j++) { - for (i = 0; i < iwn_bands[j].nchan; i++) { - if (iwn_bands[j].chan[i] == c->ic_ieee) - return &sc->eeprom_channels[j][i]; - } - } - - return NULL; -} - -/* - * Enforce flags read from EEPROM. - */ -static int -iwn_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, - int nchan, struct ieee80211_channel chans[]) -{ - struct iwn_softc *sc = ic->ic_ifp->if_softc; - int i; - - for (i = 0; i < nchan; i++) { - struct ieee80211_channel *c = &chans[i]; - struct iwn_eeprom_chan *channel; - - channel = iwn_find_eeprom_channel(sc, c); - if (channel == NULL) { - if_printf(ic->ic_ifp, - "%s: invalid channel %u freq %u/0x%x\n", - __func__, c->ic_ieee, c->ic_freq, c->ic_flags); - return EINVAL; - } - c->ic_flags |= iwn_eeprom_channel_flags(channel); - } - - return 0; -} - static void iwn_hw_reset(void *arg0, int pending) { @@ -6596,161 +7047,3 @@ iwn_hw_reset(void *arg0, int pending) iwn_init(sc); ieee80211_notify_radio(ic, 1); } - -static void -iwn_radio_on(void *arg0, int pending) -{ - struct iwn_softc *sc = arg0; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - if (vap != NULL) { - iwn_init(sc); - ieee80211_init(vap); - } -} - -static void -iwn_radio_off(void *arg0, int pending) -{ - struct iwn_softc *sc = arg0; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - iwn_stop(sc); - if (vap != NULL) - ieee80211_stop(vap); - - /* Enable interrupts to get RF toggle notification. */ - IWN_LOCK(sc); - IWN_WRITE(sc, IWN_INT, 0xffffffff); - IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); - IWN_UNLOCK(sc); -} - -static void -iwn_sysctlattach(struct iwn_softc *sc) -{ - struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); - struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); - -#ifdef IWN_DEBUG - sc->sc_debug = 0; - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "debug", CTLFLAG_RW, &sc->sc_debug, 0, "control debugging printfs"); -#endif -} - -static int -iwn_shutdown(device_t dev) -{ - struct iwn_softc *sc = device_get_softc(dev); - - iwn_stop(sc); - return 0; -} - -static int -iwn_suspend(device_t dev) -{ - struct iwn_softc *sc = device_get_softc(dev); - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - iwn_stop(sc); - if (vap != NULL) - ieee80211_stop(vap); - return 0; -} - -static int -iwn_resume(device_t dev) -{ - struct iwn_softc *sc = device_get_softc(dev); - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - /* Clear device-specific "PCI retry timeout" register (41h). */ - pci_write_config(dev, 0x41, 0, 1); - - if (ifp->if_flags & IFF_UP) { - iwn_init(sc); - if (vap != NULL) - ieee80211_init(vap); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - iwn_start(ifp); - } - return 0; -} - -#ifdef IWN_DEBUG -static const char * -iwn_intr_str(uint8_t cmd) -{ - switch (cmd) { - /* Notifications */ - case IWN_UC_READY: return "UC_READY"; - case IWN_ADD_NODE_DONE: return "ADD_NODE_DONE"; - case IWN_TX_DONE: return "TX_DONE"; - case IWN_START_SCAN: return "START_SCAN"; - case IWN_STOP_SCAN: return "STOP_SCAN"; - case IWN_RX_STATISTICS: return "RX_STATS"; - case IWN_BEACON_STATISTICS: return "BEACON_STATS"; - case IWN_STATE_CHANGED: return "STATE_CHANGED"; - case IWN_BEACON_MISSED: return "BEACON_MISSED"; - case IWN_RX_PHY: return "RX_PHY"; - case IWN_MPDU_RX_DONE: return "MPDU_RX_DONE"; - case IWN_RX_DONE: return "RX_DONE"; - - /* Command Notifications */ - case IWN_CMD_RXON: return "IWN_CMD_RXON"; - case IWN_CMD_RXON_ASSOC: return "IWN_CMD_RXON_ASSOC"; - case IWN_CMD_EDCA_PARAMS: return "IWN_CMD_EDCA_PARAMS"; - case IWN_CMD_TIMING: return "IWN_CMD_TIMING"; - case IWN_CMD_LINK_QUALITY: return "IWN_CMD_LINK_QUALITY"; - case IWN_CMD_SET_LED: return "IWN_CMD_SET_LED"; - case IWN5000_CMD_WIMAX_COEX: return "IWN5000_CMD_WIMAX_COEX"; - case IWN5000_CMD_CALIB_CONFIG: return "IWN5000_CMD_CALIB_CONFIG"; - case IWN5000_CMD_CALIB_RESULT: return "IWN5000_CMD_CALIB_RESULT"; - case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE"; - case IWN_CMD_SET_POWER_MODE: return "IWN_CMD_SET_POWER_MODE"; - case IWN_CMD_SCAN: return "IWN_CMD_SCAN"; - case IWN_CMD_SCAN_RESULTS: return "IWN_CMD_SCAN_RESULTS"; - case IWN_CMD_TXPOWER: return "IWN_CMD_TXPOWER"; - case IWN_CMD_TXPOWER_DBM: return "IWN_CMD_TXPOWER_DBM"; - case IWN5000_CMD_TX_ANT_CONFIG: return "IWN5000_CMD_TX_ANT_CONFIG"; - case IWN_CMD_BT_COEX: return "IWN_CMD_BT_COEX"; - case IWN_CMD_SET_CRITICAL_TEMP: return "IWN_CMD_SET_CRITICAL_TEMP"; - case IWN_CMD_SET_SENSITIVITY: return "IWN_CMD_SET_SENSITIVITY"; - case IWN_CMD_PHY_CALIB: return "IWN_CMD_PHY_CALIB"; - } - return "UNKNOWN INTR NOTIF/CMD"; -} -#endif /* IWN_DEBUG */ - -static device_method_t iwn_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, iwn_probe), - DEVMETHOD(device_attach, iwn_attach), - DEVMETHOD(device_detach, iwn_detach), - DEVMETHOD(device_shutdown, iwn_shutdown), - DEVMETHOD(device_suspend, iwn_suspend), - DEVMETHOD(device_resume, iwn_resume), - { 0, 0 } -}; - -static driver_t iwn_driver = { - "iwn", - iwn_methods, - sizeof (struct iwn_softc) -}; -static devclass_t iwn_devclass; - -DRIVER_MODULE(iwn, pci, iwn_driver, iwn_devclass, 0, 0); -MODULE_DEPEND(iwn, pci, 1, 1, 1); -MODULE_DEPEND(iwn, firmware, 1, 1, 1); -MODULE_DEPEND(iwn, wlan, 1, 1, 1); diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h index c0230091ef..062125fb3a 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnreg.h @@ -27,6 +27,9 @@ #define IWN4965_NTXQUEUES 16 #define IWN5000_NTXQUEUES 20 +#define IWN4965_FIRSTAGGQUEUE 7 +#define IWN5000_FIRSTAGGQUEUE 10 + #define IWN4965_NDMACHNLS 7 #define IWN5000_NDMACHNLS 8 @@ -50,9 +53,6 @@ #define IWN_HIADDR(paddr) (0) #endif -/* Base Address Register. */ -#define IWN_PCI_BAR0 PCI_MAPREG_START - /* * Control and status registers. */ @@ -73,6 +73,7 @@ #define IWN_UCODE_GP1_CLR 0x05c #define IWN_LED 0x094 #define IWN_DRAM_INT_TBL 0x0a0 +#define IWN_SHADOW_REG_CTRL 0x0a8 #define IWN_GIO_CHICKEN 0x100 #define IWN_ANA_PLL 0x20c #define IWN_HW_REV_WA 0x22c @@ -82,10 +83,10 @@ #define IWN_MEM_WADDR 0x410 #define IWN_MEM_WDATA 0x418 #define IWN_MEM_RDATA 0x41c -#define IWN_PRPH_WADDR 0x444 -#define IWN_PRPH_RADDR 0x448 -#define IWN_PRPH_WDATA 0x44c -#define IWN_PRPH_RDATA 0x450 +#define IWN_PRPH_WADDR 0x444 +#define IWN_PRPH_RADDR 0x448 +#define IWN_PRPH_WDATA 0x44c +#define IWN_PRPH_RDATA 0x450 #define IWN_HBUS_TARG_WRPTR 0x460 /* @@ -218,6 +219,7 @@ #define IWN_GP_DRIVER_RADIO_2X2_HYB (1 << 0) #define IWN_GP_DRIVER_RADIO_2X2_IPA (2 << 0) #define IWN_GP_DRIVER_CALIB_VER6 (1 << 2) +#define IWN_GP_DRIVER_6050_1X2 (1 << 3) /* Possible flags for register IWN_UCODE_GP1_CLR. */ #define IWN_UCODE_GP1_RFKILL (1 << 1) @@ -286,8 +288,7 @@ #define IWN_FH_TX_CHICKEN_SCHED_RETRY (1 << 1) /* Possible flags for register IWN_FH_TX_STATUS. */ -#define IWN_FH_TX_STATUS_IDLE(chnl) \ - (1 << ((chnl) + 24) | 1 << ((chnl) + 16)) +#define IWN_FH_TX_STATUS_IDLE(chnl) (1 << ((chnl) + 16)) /* Possible flags for register IWN_FH_RX_CONFIG. */ #define IWN_FH_RX_CONFIG_ENA (1 << 31) @@ -436,6 +437,8 @@ struct iwn_tx_cmd { #define IWN_CMD_SET_CRITICAL_TEMP 164 #define IWN_CMD_SET_SENSITIVITY 168 #define IWN_CMD_PHY_CALIB 176 +#define IWN_CMD_BT_COEX_PRIOTABLE 204 +#define IWN_CMD_BT_COEX_PROT 205 uint8_t flags; uint8_t idx; @@ -489,6 +492,10 @@ struct iwn_rxon { #define IWN_RXON_ANTENNA_A (1 << 8) #define IWN_RXON_ANTENNA_B (1 << 9) #define IWN_RXON_TSF (1 << 15) +#define IWN_RXON_HT_HT40MINUS (1 << 22) +#define IWN_RXON_HT_PROTMODE(x) (x << 23) +#define IWN_RXON_HT_MODEPURE40 (1 << 25) +#define IWN_RXON_HT_MODEMIXED (2 << 25) #define IWN_RXON_CTS_TO_SELF (1 << 30) uint32_t filter; @@ -588,7 +595,10 @@ struct iwn_node_info { uint8_t txmic[8]; uint32_t htflags; +#define IWN_SMPS_MIMO_PROT (1 << 17) #define IWN_AMDPU_SIZE_FACTOR(x) ((x) << 19) +#define IWN_NODE_HT40 (1 << 21) +#define IWN_SMPS_MIMO_DIS (1 << 22) #define IWN_AMDPU_DENSITY(x) ((x) << 23) uint32_t mask; @@ -625,8 +635,13 @@ struct iwn4965_node_info { uint32_t reserved7; } __packed; -#define IWN_RFLAG_CCK (1 << 1) -#define IWN_RFLAG_ANT(x) ((x) << 6) +#define IWN_RFLAG_MCS (1 << 8) +#define IWN_RFLAG_CCK (1 << 9) +#define IWN_RFLAG_GREENFIELD (1 << 10) +#define IWN_RFLAG_HT40 (1 << 11) +#define IWN_RFLAG_DUPLICATE (1 << 12) +#define IWN_RFLAG_SGI (1 << 13) +#define IWN_RFLAG_ANT(x) ((x) << 14) /* Structure for command IWN_CMD_TX_DATA. */ struct iwn_cmd_data { @@ -647,9 +662,7 @@ struct iwn_cmd_data { #define IWN_TX_NEED_PADDING (1 << 20) uint32_t scratch; - uint8_t plcp; - uint8_t rflags; - uint16_t xrflags; + uint32_t rate; uint8_t id; uint8_t security; @@ -690,11 +703,7 @@ struct iwn_cmd_link_quality { uint8_t ampdu_threshold; uint8_t ampdu_max; uint32_t reserved2; - struct { - uint8_t plcp; - uint8_t rflags; - uint16_t xrflags; - } __packed retry[IWN_MAX_TX_RETRIES]; + uint32_t retry[IWN_MAX_TX_RETRIES]; uint32_t reserved3; } __packed; @@ -730,6 +739,8 @@ struct iwn5000_wimax_coex { struct iwn5000_calib_elem { uint32_t enable; uint32_t start; +#define IWN5000_CALIB_DC (1 << 1) + uint32_t send; uint32_t apply; uint32_t reserved; @@ -831,7 +842,7 @@ struct iwn5000_cmd_txpower { uint8_t reserved; } __packed; -/* Structure for command IWN_CMD_BLUETOOTH. */ +/* Structures for command IWN_CMD_BLUETOOTH. */ struct iwn_bluetooth { uint8_t flags; #define IWN_BT_COEX_CHAN_ANN (1 << 0) @@ -849,6 +860,43 @@ struct iwn_bluetooth { uint32_t kill_cts; } __packed; +struct iwn6000_btcoex_config { + uint8_t flags; + uint8_t lead_time; + uint8_t max_kill; + uint8_t bt3_t7_timer; + uint32_t kill_ack; + uint32_t kill_cts; + uint8_t sample_time; + uint8_t bt3_t2_timer; + uint16_t bt4_reaction; + uint32_t lookup_table[12]; + uint16_t bt4_decision; + uint16_t valid; + uint8_t prio_boost; + uint8_t tx_prio_boost; + uint16_t rx_prio_boost; +} __packed; + +struct iwn_btcoex_priotable { + uint8_t calib_init1; + uint8_t calib_init2; + uint8_t calib_periodic_low1; + uint8_t calib_periodic_low2; + uint8_t calib_periodic_high1; + uint8_t calib_periodic_high2; + uint8_t dtim; + uint8_t scan52; + uint8_t scan24; + uint8_t reserved[7]; +} __packed; + +struct iwn_btcoex_prot { + uint8_t open; + uint8_t type; + uint8_t reserved[2]; +} __packed; + /* Structure for command IWN_CMD_SET_CRITICAL_TEMP. */ struct iwn_critical_temp { uint32_t reserved; @@ -860,7 +908,7 @@ struct iwn_critical_temp { #define IWN_CTOMUK(c) (((c) * 1000000) + 273150000) } __packed; -/* Structure for command IWN_CMD_SET_SENSITIVITY. */ +/* Structures for command IWN_CMD_SET_SENSITIVITY. */ struct iwn_sensitivity_cmd { uint16_t which; #define IWN_SENSITIVITY_DEFAULTTBL 0 @@ -879,6 +927,34 @@ struct iwn_sensitivity_cmd { uint16_t energy_ofdm_th; } __packed; +struct iwn_enhanced_sensitivity_cmd { + uint16_t which; + uint16_t energy_cck; + uint16_t energy_ofdm; + uint16_t corr_ofdm_x1; + uint16_t corr_ofdm_mrc_x1; + uint16_t corr_cck_mrc_x4; + uint16_t corr_ofdm_x4; + uint16_t corr_ofdm_mrc_x4; + uint16_t corr_barker; + uint16_t corr_barker_mrc; + uint16_t corr_cck_x4; + uint16_t energy_ofdm_th; + /* "Enhanced" part. */ + uint16_t ina_det_ofdm; + uint16_t ina_det_cck; + uint16_t corr_11_9_en; + uint16_t ofdm_det_slope_mrc; + uint16_t ofdm_det_icept_mrc; + uint16_t ofdm_det_slope; + uint16_t ofdm_det_icept; + uint16_t cck_det_slope_mrc; + uint16_t cck_det_icept_mrc; + uint16_t cck_det_slope; + uint16_t cck_det_icept; + uint16_t reserved; +} __packed; + /* Structures for command IWN_CMD_PHY_CALIB. */ struct iwn_phy_calib { uint8_t code; @@ -889,6 +965,8 @@ struct iwn_phy_calib { #define IWN5000_PHY_CALIB_CRYSTAL 15 #define IWN5000_PHY_CALIB_BASE_BAND 16 #define IWN5000_PHY_CALIB_TX_IQ_PERIODIC 17 +#define IWN5000_PHY_CALIB_TEMP_OFFSET 18 + #define IWN5000_PHY_CALIB_RESET_NOISE_GAIN 18 #define IWN5000_PHY_CALIB_NOISE_GAIN 19 @@ -907,6 +985,17 @@ struct iwn5000_phy_calib_crystal { uint8_t reserved[2]; } __packed; +struct iwn5000_phy_calib_temp_offset { + uint8_t code; + uint8_t group; + uint8_t ngroups; + uint8_t isvalid; + int16_t offset; +#define IWN_DEFAULT_TEMP_OFFSET 2700 + + uint16_t reserved; +} __packed; + struct iwn_phy_calib_gain { uint8_t code; uint8_t group; @@ -987,9 +1076,7 @@ struct iwn4965_tx_stat { uint8_t btkillcnt; uint8_t rtsfailcnt; uint8_t ackfailcnt; - uint8_t rate; - uint8_t rflags; - uint16_t xrflags; + uint32_t rate; uint16_t duration; uint16_t reserved; uint32_t power[2]; @@ -1001,9 +1088,7 @@ struct iwn5000_tx_stat { uint8_t btkillcnt; uint8_t rtsfailcnt; uint8_t ackfailcnt; - uint8_t rate; - uint8_t rflags; - uint16_t xrflags; + uint32_t rate; uint16_t duration; uint16_t reserved; uint32_t power[2]; @@ -1058,9 +1143,7 @@ struct iwn_rx_stat { uint16_t chan; uint8_t phybuf[32]; - uint8_t rate; - uint8_t rflags; - uint16_t xrflags; + uint32_t rate; uint16_t len; uint16_t reserve3; } __packed; @@ -1283,6 +1366,8 @@ struct iwn_fw_tlv { #define IWN_FW_TLV_INIT_DATA 4 #define IWN_FW_TLV_BOOT_TEXT 5 #define IWN_FW_TLV_PBREQ_MAXLEN 6 +#define IWN_FW_TLV_ENH_SENS 14 +#define IWN_FW_TLV_PHY_CALIB 15 uint16_t alt; uint32_t len; @@ -1300,6 +1385,7 @@ struct iwn_fw_tlv { * Offsets into EEPROM. */ #define IWN_EEPROM_MAC 0x015 +#define IWN_EEPROM_SKU_CAP 0x045 #define IWN_EEPROM_RFCFG 0x048 #define IWN4965_EEPROM_DOMAIN 0x060 #define IWN4965_EEPROM_BAND1 0x063 @@ -1322,12 +1408,18 @@ struct iwn_fw_tlv { #define IWN5000_EEPROM_BAND4 0x02e #define IWN5000_EEPROM_BAND5 0x03a #define IWN5000_EEPROM_BAND6 0x041 +#define IWN6000_EEPROM_BAND6 0x040 #define IWN5000_EEPROM_BAND7 0x049 #define IWN6000_EEPROM_ENHINFO 0x054 #define IWN5000_EEPROM_CRYSTAL 0x128 #define IWN5000_EEPROM_TEMP 0x12a #define IWN5000_EEPROM_VOLT 0x12b +/* Possible flags for IWN_EEPROM_SKU_CAP. */ +#define IWN_EEPROM_SKU_CAP_11N (1 << 6) +#define IWN_EEPROM_SKU_CAP_AMT (1 << 7) +#define IWN_EEPROM_SKU_CAP_IPAN (1 << 8) + /* Possible flags for IWN_EEPROM_RFCFG. */ #define IWN_RFCFG_TYPE(x) (((x) >> 0) & 0x3) #define IWN_RFCFG_STEP(x) (((x) >> 2) & 0x3) @@ -1346,7 +1438,17 @@ struct iwn_eeprom_chan { } __packed; struct iwn_eeprom_enhinfo { - uint16_t chan; + uint8_t flags; +#define IWN_ENHINFO_VALID 0x01 +#define IWN_ENHINFO_5GHZ 0x02 +#define IWN_ENHINFO_OFDM 0x04 +#define IWN_ENHINFO_HT40 0x08 +#define IWN_ENHINFO_HTAP 0x10 +#define IWN_ENHINFO_RES1 0x20 +#define IWN_ENHINFO_RES2 0x40 +#define IWN_ENHINFO_COMMON 0x80 + + uint8_t chan; int8_t chain[3]; /* max power in half-dBm */ uint8_t reserved; int8_t mimo2; /* max power in half-dBm */ @@ -1400,6 +1502,16 @@ static const uint32_t iwn5000_regulatory_bands[IWN_NBANDS] = { IWN5000_EEPROM_BAND7 }; +static const uint32_t iwn6000_regulatory_bands[IWN_NBANDS] = { + IWN5000_EEPROM_BAND1, + IWN5000_EEPROM_BAND2, + IWN5000_EEPROM_BAND3, + IWN5000_EEPROM_BAND4, + IWN5000_EEPROM_BAND5, + IWN6000_EEPROM_BAND6, + IWN5000_EEPROM_BAND7 +}; + #define IWN_CHAN_BANDS_COUNT 7 #define IWN_MAX_CHAN_PER_BAND 14 static const struct iwn_chan_band { @@ -1419,35 +1531,13 @@ static const struct iwn_chan_band { { 11, { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 } } }; -#define IWN1000_OTP_NBLOCKS 3 -#define IWN6000_OTP_NBLOCKS 4 +#define IWN1000_OTP_NBLOCKS 3 +#define IWN6000_OTP_NBLOCKS 4 #define IWN6050_OTP_NBLOCKS 7 /* HW rate indices. */ -#define IWN_RIDX_CCK1 0 -#define IWN_RIDX_CCK11 3 -#define IWN_RIDX_OFDM6 4 -#define IWN_RIDX_OFDM54 11 - -static const struct iwn_rate { - uint8_t rate; - uint8_t plcp; - uint8_t flags; -} iwn_rates[IWN_RIDX_MAX + 1] = { - { 2, 10, IWN_RFLAG_CCK }, - { 4, 20, IWN_RFLAG_CCK }, - { 11, 55, IWN_RFLAG_CCK }, - { 22, 110, IWN_RFLAG_CCK }, - { 12, 0xd, 0 }, - { 18, 0xf, 0 }, - { 24, 0x5, 0 }, - { 36, 0x7, 0 }, - { 48, 0x9, 0 }, - { 72, 0xb, 0 }, - { 96, 0x1, 0 }, - { 108, 0x3, 0 }, - { 120, 0x3, 0 } -}; +#define IWN_RIDX_CCK1 0 +#define IWN_RIDX_OFDM6 4 #define IWN4965_MAX_PWR_INDEX 107 @@ -1611,13 +1701,13 @@ static const struct iwn_sensitivity_limits iwn5150_sensitivity_limits = { static const struct iwn_sensitivity_limits iwn1000_sensitivity_limits = { 120, 155, 240, 290, - 90, 120, + 90, 120, 170, 210, 125, 200, 170, 400, - 95, - 95, - 95 + 95, + 95, + 95 }; static const struct iwn_sensitivity_limits iwn6000_sensitivity_limits = { diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h index ff1e068b90..5288781307 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwnvar.h @@ -78,6 +78,7 @@ struct iwn_tx_ring { int qid; int queued; int cur; + int read; }; struct iwn_softc; @@ -101,7 +102,12 @@ struct iwn_node { struct ieee80211_node ni; /* must be the first */ uint16_t disable_tid; uint8_t id; - uint8_t ridx[IEEE80211_RATE_MAXSIZE]; + uint32_t ridx[256]; + struct { + uint64_t bitmap; + int startidx; + int nframes; + } agg[IEEE80211_TID_SIZE]; }; struct iwn_calib_state { @@ -157,7 +163,7 @@ struct iwn_fw_info { struct iwn_fw_part boot; }; -struct iwn_hal { +struct iwn_ops { int (*load_firmware)(struct iwn_softc *); void (*read_eeprom)(struct iwn_softc *); int (*post_alive)(struct iwn_softc *); @@ -174,21 +180,10 @@ struct iwn_hal { int); void (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); -#if 0 /* HT */ void (*ampdu_tx_start)(struct iwn_softc *, - struct ieee80211_node *, uint8_t, uint16_t); - void (*ampdu_tx_stop)(struct iwn_softc *, uint8_t, + struct ieee80211_node *, int, uint8_t, uint16_t); + void (*ampdu_tx_stop)(struct iwn_softc *, int, uint8_t, uint16_t); -#endif - int ntxqs; - int ndmachnls; - uint8_t broadcast_id; - int rxonsz; - int schedsz; - uint32_t fw_text_maxsz; - uint32_t fw_data_maxsz; - uint32_t fwsz; - bus_size_t sched_txfact_addr; }; struct iwn_vap { @@ -201,31 +196,40 @@ struct iwn_vap { #define IWN_VAP(_vap) ((struct iwn_vap *)(_vap)) struct iwn_softc { + device_t sc_dev; + struct ifnet *sc_ifp; int sc_debug; - /* Locks */ struct mtx sc_mtx; - /* Bus */ - device_t sc_dev; - int mem_rid; - int irq_rid; - struct resource *mem; - struct resource *irq; - u_int sc_flags; -#define IWN_FLAG_HAS_5GHZ (1 << 0) #define IWN_FLAG_HAS_OTPROM (1 << 1) #define IWN_FLAG_CALIB_DONE (1 << 2) #define IWN_FLAG_USE_ICT (1 << 3) #define IWN_FLAG_INTERNAL_PA (1 << 4) +#define IWN_FLAG_HAS_11N (1 << 6) +#define IWN_FLAG_ENH_SENS (1 << 7) +#define IWN_FLAG_ADV_BTCOEX (1 << 8) uint8_t hw_type; - const struct iwn_hal *sc_hal; + + struct iwn_ops ops; const char *fwname; const struct iwn_sensitivity_limits *limits; + int ntxqs; + int firstaggqueue; + int ndmachnls; + uint8_t broadcast_id; + int rxonsz; + int schedsz; + uint32_t fw_text_maxsz; + uint32_t fw_data_maxsz; + uint32_t fwsz; + bus_size_t sched_txfact_addr; + uint32_t reset_noise_gain; + uint32_t noise_gain; /* TX scheduler rings. */ struct iwn_dma_info sched_dma; @@ -250,37 +254,28 @@ struct iwn_softc { struct iwn_tx_ring txq[IWN5000_NTXQUEUES]; struct iwn_rx_ring rxq; + int mem_rid; + struct resource *mem; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; + int irq_rid; + struct resource *irq; void *sc_ih; bus_size_t sc_sz; int sc_cap_off; /* PCIe Capabilities. */ /* Tasks used by the driver */ - struct task sc_reinit_task; + struct task sc_reinit_task; struct task sc_radioon_task; struct task sc_radiooff_task; + struct callout calib_to; int calib_cnt; struct iwn_calib_state calib; - u_int calib_init; - u_int calib_runtime; -#define IWN_CALIB_XTAL (1 << IWN_CALIB_IDX_XTAL) -#define IWN_CALIB_DC (1 << IWN_CALIB_IDX_DC) -#define IWN_CALIB_LO (1 << IWN_CALIB_IDX_LO) -#define IWN_CALIB_TX_IQ (1 << IWN_CALIB_IDX_TX_IQ) -#define IWN_CALIB_TX_IQ_PERIODIC (1 << IWN_CALIB_IDX_TX_IQ_PERIODIC) -#define IWN_CALIB_BASE_BAND (1 << IWN_CALIB_IDX_BASE_BAND) -#define IWN_CALIB_NUM 6 - struct iwn_calib_info calib_results[IWN_CALIB_NUM]; -#define IWN_CALIB_IDX_XTAL 0 -#define IWN_CALIB_IDX_DC 1 -#define IWN_CALIB_IDX_LO 2 -#define IWN_CALIB_IDX_TX_IQ 3 -#define IWN_CALIB_IDX_TX_IQ_PERIODIC 4 -#define IWN_CALIB_IDX_BASE_BAND 5 + struct callout watchdog_to; struct iwn_fw_info fw; + struct iwn_calib_info calibcmd[5]; uint32_t errptr; struct iwn_rx_stat last_rx_stat; @@ -299,11 +294,12 @@ struct iwn_softc { uint16_t rfcfg; uint8_t calib_ver; char eeprom_domain[4]; + uint32_t eeprom_crystal; + int16_t eeprom_temp; int16_t eeprom_voltage; int8_t maxpwr2GHz; int8_t maxpwr5GHz; int8_t maxpwr[IEEE80211_CHAN_MAX]; - int8_t enh_maxpwr[35]; int32_t temp_off; uint32_t int_mask; @@ -313,9 +309,22 @@ struct iwn_softc { uint8_t rxchainmask; uint8_t chainmask; - struct callout sc_timer_to; int sc_tx_timer; + struct ieee80211_tx_ampdu *qid2tap[IWN5000_NTXQUEUES]; + + int (*sc_ampdu_rx_start)(struct ieee80211_node *, + struct ieee80211_rx_ampdu *, int, int, int); + void (*sc_ampdu_rx_stop)(struct ieee80211_node *, + struct ieee80211_rx_ampdu *); + int (*sc_addba_request)(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int, int, int); + int (*sc_addba_response)(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int, int, int); + void (*sc_addba_stop)(struct ieee80211_node *, + struct ieee80211_tx_ampdu *); + + struct iwn_rx_radiotap_header sc_rxtap; struct iwn_tx_radiotap_header sc_txtap; diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/glue.c b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/glue.c index 3e87128923..26292bb5d1 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/glue.c +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/glue.c @@ -24,13 +24,14 @@ NO_HAIKU_FBSD_MII_DRIVER(); NO_HAIKU_REENABLE_INTERRUPTS(); HAIKU_DRIVER_REQUIREMENTS(FBSD_TASKQUEUES | FBSD_WLAN); HAIKU_FIRMWARE_VERSION(44417); -HAIKU_FIRMWARE_NAME_MAP(7) = { +HAIKU_FIRMWARE_NAME_MAP(8) = { {"iwn1000fw", "iwlwifi-1000-5.ucode"}, {"iwn4965fw", "iwlwifi-4965-2.ucode"}, {"iwn5000fw", "iwlwifi-5000-5.ucode"}, {"iwn5150fw", "iwlwifi-5150-2.ucode"}, {"iwn6000fw", "iwlwifi-6000-4.ucode"}, - {"iwn6005fw", "iwlwifi-6000g2a-5.ucode"}, + {"iwn6000g2afw", "iwlwifi-6000g2a-5.ucode"}, + {"iwn6000g2bfw", "iwlwifi-6000g2b-6.ucode"}, {"iwn6050fw", "iwlwifi-6050-5.ucode"} }; diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.c b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.c index d547cfce12..ae6ef88265 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.c +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.c @@ -135,7 +135,7 @@ static int malo_setup_hwdma(struct malo_softc *); static void malo_txq_init(struct malo_softc *, struct malo_txq *, int); static void malo_tx_cleanupq(struct malo_softc *, struct malo_txq *); static void malo_start(struct ifnet *); -static void malo_watchdog(struct ifnet *); +static void malo_watchdog(void *); static int malo_ioctl(struct ifnet *, u_long, caddr_t); static void malo_updateslot(struct ifnet *); static int malo_newstate(struct ieee80211vap *, enum ieee80211_state, int); @@ -168,8 +168,8 @@ malo_bar0_read4(struct malo_softc *sc, bus_size_t off) static void malo_bar0_write4(struct malo_softc *sc, bus_size_t off, uint32_t val) { - DPRINTF(sc, MALO_DEBUG_FW, "%s: off 0x%zx val 0x%x\n", - __func__, off, val); + DPRINTF(sc, MALO_DEBUG_FW, "%s: off 0x%jx val 0x%x\n", + __func__, (intmax_t)off, val); bus_space_write_4(sc->malo_io0t, sc->malo_io0h, off, val); } @@ -191,6 +191,7 @@ malo_attach(uint16_t devid, struct malo_softc *sc) ic = ifp->if_l2com; MALO_LOCK_INIT(sc); + callout_init_mtx(&sc->malo_watchdog_timer, &sc->malo_mtx, 0); /* set these up early for if_printf use */ if_initname(ifp, device_get_name(sc->malo_dev), @@ -272,7 +273,6 @@ malo_attach(uint16_t devid, struct malo_softc *sc) ifp->if_softc = sc; ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; ifp->if_start = malo_start; - ifp->if_watchdog = malo_watchdog; ifp->if_ioctl = malo_ioctl; ifp->if_init = malo_init; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); @@ -1076,7 +1076,7 @@ malo_tx_proc(void *arg, int npending) if (nreaped != 0) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - ifp->if_timer = 0; + sc->malo_timer = 0; malo_start(ifp); } } @@ -1260,7 +1260,7 @@ malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, MALO_TXDESC_SYNC(txq, ds, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ifp->if_opackets++; - ifp->if_timer = 5; + sc->malo_timer = 5; MALO_TXQ_UNLOCK(txq); return 0; #undef IEEE80211_DIR_DSTODS @@ -1339,10 +1339,17 @@ malo_start(struct ifnet *ifp) } static void -malo_watchdog(struct ifnet *ifp) +malo_watchdog(void *arg) { - struct malo_softc *sc = ifp->if_softc; + struct malo_softc *sc; + struct ifnet *ifp; + sc = arg; + callout_reset(&sc->malo_watchdog_timer, hz, malo_watchdog, sc); + if (sc->malo_timer == 0 || --sc->malo_timer > 0) + return; + + ifp = sc->malo_ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && !sc->malo_invalid) { if_printf(ifp, "watchdog timeout\n"); @@ -1536,6 +1543,7 @@ malo_init_locked(struct malo_softc *sc) ifp->if_drv_flags |= IFF_DRV_RUNNING; malo_hal_intrset(mh, sc->malo_imask); + callout_reset(&sc->malo_watchdog_timer, hz, malo_watchdog, sc); } static void @@ -1699,7 +1707,8 @@ malo_stop_locked(struct ifnet *ifp, int disable) * is gone (invalid). */ ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - ifp->if_timer = 0; + callout_stop(&sc->malo_watchdog_timer); + sc->malo_timer = 0; /* diable interrupt. */ malo_hal_intrset(mh, 0); /* turn off the radio. */ @@ -2241,6 +2250,7 @@ malo_detach(struct malo_softc *sc) * Other than that, it's straightforward... */ ieee80211_ifdetach(ic); + callout_drain(&sc->malo_watchdog_timer); malo_dma_cleanup(sc); malo_tx_cleanup(sc); malo_hal_detach(sc->malo_mh); diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.h b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.h index 7e3a7e89e4..bac290c633 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.h +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo.h @@ -550,6 +550,8 @@ struct malo_softc { struct malo_txq malo_txq[MALO_NUM_TX_QUEUES]; struct task malo_txtask; /* tx int processing */ + struct callout malo_watchdog_timer; + int malo_timer; struct malo_tx_radiotap_header malo_tx_th; struct malo_rx_radiotap_header malo_rx_th; diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo_pci.c b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo_pci.c index 65aac7ca63..9c2027b924 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo_pci.c +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malo_pci.c @@ -149,21 +149,6 @@ malo_pci_probe(device_t dev) #undef N } -static int -malo_pci_setup(device_t dev) -{ - - /* - * Enable memory mapping and bus mastering. - */ - if (pci_enable_busmaster(dev) != 0) - return -1; - if (pci_enable_io(dev, SYS_RES_MEMORY) != 0) - return -1; - - return 0; -} - static int malo_pci_attach(device_t dev) { @@ -173,11 +158,7 @@ malo_pci_attach(device_t dev) sc->malo_dev = dev; - /* - * Enable memory mapping and bus mastering. - */ - if (malo_pci_setup(dev)) - return (ENXIO); + pci_enable_busmaster(dev); /* * Setup memory-mapping of PCI registers. @@ -194,7 +175,7 @@ malo_pci_attach(device_t dev) */ sc->malo_invalid = 1; - if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { + if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { msic = pci_msi_count(dev); if (bootverbose) device_printf(dev, "MSI count : %d\n", msic); @@ -342,9 +323,6 @@ malo_pci_resume(device_t dev) { struct malo_pci_softc *psc = device_get_softc(dev); - if (!malo_pci_setup(dev)) - return ENXIO; - malo_resume(&psc->malo_sc); return (0); diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malohal.h b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malohal.h index 80c27ace43..fb962cc8dd 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malohal.h +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8335/dev/malo/if_malohal.h @@ -133,7 +133,7 @@ struct malo_hal_hwstats { /* * Set Antenna Configuration (legacy operation). * - * The RX antenna can be selected using the the bitmask + * The RX antenna can be selected using the bitmask * ant (bit 0 = antenna 1, bit 1 = antenna 2, etc.) * (diversity?XXX) */ diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwl.c b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwl.c index 0c030746c4..0d47661c4e 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwl.c +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwl.c @@ -98,7 +98,7 @@ static void mwl_start(struct ifnet *); static int mwl_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static int mwl_media_change(struct ifnet *); -static void mwl_watchdog(struct ifnet *); +static void mwl_watchdog(void *); static int mwl_ioctl(struct ifnet *, u_long, caddr_t); static void mwl_radar_proc(void *, int); static void mwl_chanswitch_proc(void *, int); @@ -304,7 +304,7 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { - device_printf(sc->sc_dev, "can not if_alloc()\n"); + device_printf(sc->sc_dev, "cannot if_alloc()\n"); return ENOSPC; } ic = ifp->if_l2com; @@ -360,6 +360,7 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) goto bad1; callout_init(&sc->sc_timer, CALLOUT_MPSAFE); + callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); sc->sc_tq = taskqueue_create("mwl_taskq", M_NOWAIT, taskqueue_thread_enqueue, &sc->sc_tq); @@ -401,7 +402,6 @@ mwl_attach(uint16_t devid, struct mwl_softc *sc) ifp->if_softc = sc; ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; ifp->if_start = mwl_start; - ifp->if_watchdog = mwl_watchdog; ifp->if_ioctl = mwl_ioctl; ifp->if_init = mwl_init; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); @@ -558,6 +558,7 @@ mwl_detach(struct mwl_softc *sc) * Other than that, it's straightforward... */ ieee80211_ifdetach(ic); + callout_drain(&sc->sc_watchdog); mwl_dma_cleanup(sc); mwl_tx_cleanup(sc); mwl_hal_detach(sc->sc_mh); @@ -1218,6 +1219,7 @@ mwl_init_locked(struct mwl_softc *sc) ifp->if_drv_flags |= IFF_DRV_RUNNING; mwl_hal_intrset(mh, sc->sc_imask); + callout_reset(&sc->sc_watchdog, hz, mwl_watchdog, sc); return 0; } @@ -1255,7 +1257,8 @@ mwl_stop_locked(struct ifnet *ifp, int disable) * Shutdown the hardware and driver. */ ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - ifp->if_timer = 0; + callout_stop(&sc->sc_watchdog); + sc->sc_tx_timer = 0; mwl_draintxq(sc); } } @@ -1742,6 +1745,10 @@ mwl_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, * WEP keys when the sta reaches AUTH state. */ macaddr = vap->iv_bss->ni_bssid; + if ((k->wk_flags & IEEE80211_KEY_GROUP) == 0) { + /* XXX plumb to local sta db too for static key wep */ + mwl_hal_keyset(hvap, &hk, vap->iv_myaddr); + } } else if (vap->iv_opmode == IEEE80211_M_WDS && vap->iv_state != IEEE80211_S_RUN) { /* @@ -2303,8 +2310,10 @@ mwl_dma_setup(struct mwl_softc *sc) int error, i; error = mwl_rxdma_setup(sc); - if (error != 0) + if (error != 0) { + mwl_rxdma_cleanup(sc); return error; + } for (i = 0; i < MWL_NUM_TX_QUEUES; i++) { error = mwl_txdma_setup(sc, &sc->sc_txq[i]); @@ -3409,7 +3418,7 @@ mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf * MWL_TXDESC_SYNC(txq, ds, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ifp->if_opackets++; - ifp->if_timer = 5; + sc->sc_tx_timer = 5; MWL_TXQ_UNLOCK(txq); return 0; @@ -3556,7 +3565,7 @@ mwl_tx_proc(void *arg, int npending) if (nreaped != 0) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - ifp->if_timer = 0; + sc->sc_tx_timer = 0; if (!IFQ_IS_EMPTY(&ifp->if_snd)) { /* NB: kick fw; the tx thread may have been preempted */ mwl_hal_txstart(sc->sc_mh, 0); @@ -3622,7 +3631,7 @@ mwl_draintxq(struct mwl_softc *sc) for (i = 0; i < MWL_NUM_TX_QUEUES; i++) mwl_tx_draintxq(sc, &sc->sc_txq[i]); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - ifp->if_timer = 0; + sc->sc_tx_timer = 0; } #ifdef MWL_DIAGAPI @@ -4768,10 +4777,17 @@ mwl_txq_dump(struct mwl_txq *txq) #endif static void -mwl_watchdog(struct ifnet *ifp) +mwl_watchdog(void *arg) { - struct mwl_softc *sc = ifp->if_softc; + struct mwl_softc *sc; + struct ifnet *ifp; + sc = arg; + callout_reset(&sc->sc_watchdog, hz, mwl_watchdog, sc); + if (sc->sc_tx_timer == 0 || --sc->sc_tx_timer > 0) + return; + + ifp = sc->sc_ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && !sc->sc_invalid) { if (mwl_hal_setkeepalive(sc->sc_mh)) if_printf(ifp, "transmit timeout (firmware hung?)\n"); diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwlvar.h b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwlvar.h index ada1e8a402..0c43434739 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwlvar.h +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/if_mwlvar.h @@ -255,6 +255,8 @@ struct mwl_softc { bus_space_tag_t sc_io1t; struct mtx sc_mtx; /* master lock (recursive) */ struct taskqueue *sc_tq; /* private task queue */ + struct callout sc_watchdog; + int sc_tx_timer; unsigned int sc_invalid : 1, /* disable hardware accesses */ sc_recvsetup:1, /* recv setup */ sc_csapending:1,/* 11h channel switch pending */ diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.c b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.c index 78b05ee717..18992c2f68 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.c +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.c @@ -279,7 +279,7 @@ mwl_hal_attach(device_t dev, uint16_t devid, hvap->vap_type = MWL_HAL_STA; hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_CLIENT); hvap->macid = i; - for (i++; i < MWL_MBSS_STA_MAX; i++) { + for (i++; i < MWL_MBSS_MAX; i++) { hvap = &mh->mh_vaps[i]; hvap->vap_type = MWL_HAL_STA; hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_CLIENT); diff --git a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.h b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.h index ab6b7d0176..25b8b07c48 100644 --- a/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.h +++ b/src/add-ons/kernel/drivers/network/wlan/marvell88w8363/dev/mwl/mwlhal.h @@ -291,7 +291,7 @@ int mwl_hal_setradio(struct mwl_hal *mh, int onoff, MWL_HAL_PREAMBLE preamble); /* * Set Antenna Configuration (legacy operation). * - * The RX antenna can be selected using the the bitmask + * The RX antenna can be selected using the bitmask * ant (bit 0 = antenna 1, bit 1 = antenna 2, etc.) * (diversity?XXX) */ diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c index 7f8502d427..33667becf5 100644 --- a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c @@ -144,7 +144,8 @@ static void rt2560_enable_tsf_sync(struct rt2560_softc *); static void rt2560_enable_tsf(struct rt2560_softc *); static void rt2560_update_plcp(struct rt2560_softc *); static void rt2560_update_slot(struct ifnet *); -static void rt2560_set_basicrates(struct rt2560_softc *); +static void rt2560_set_basicrates(struct rt2560_softc *, + const struct ieee80211_rateset *); static void rt2560_update_led(struct rt2560_softc *, int, int); static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); static void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); @@ -779,7 +780,7 @@ rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (vap->iv_opmode != IEEE80211_M_MONITOR) { rt2560_update_plcp(sc); - rt2560_set_basicrates(sc); + rt2560_set_basicrates(sc, &ni->ni_rates); rt2560_set_bssid(sc, ni->ni_bssid); } @@ -2355,22 +2356,29 @@ rt2560_update_slot(struct ifnet *ifp) } static void -rt2560_set_basicrates(struct rt2560_softc *sc) +rt2560_set_basicrates(struct rt2560_softc *sc, + const struct ieee80211_rateset *rs) { +#define RV(r) ((r) & IEEE80211_RATE_VAL) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; + uint32_t mask = 0; + uint8_t rate; + int i; - /* update basic rate set */ - if (ic->ic_curmode == IEEE80211_MODE_11B) { - /* 11b basic rates: 1, 2Mbps */ - RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); - } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { - /* 11a basic rates: 6, 12, 24Mbps */ - RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); - } else { - /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ - RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); + for (i = 0; i < rs->rs_nrates; i++) { + rate = rs->rs_rates[i]; + + if (!(rate & IEEE80211_RATE_BASIC)) + continue; + + mask |= 1 << ic->ic_rt->rateCodeToIndex[RV(rate)]; } + + RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); + + DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); +#undef RV } static void diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661.c b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661.c index d785c1c80b..0adc8990d4 100644 --- a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661.c +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661.c @@ -1917,7 +1917,7 @@ rt2661_set_basicrates(struct rt2661_softc *sc, struct ieee80211com *ic = ifp->if_l2com; uint32_t mask = 0; uint8_t rate; - int i, j; + int i; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; @@ -1925,13 +1925,7 @@ rt2661_set_basicrates(struct rt2661_softc *sc, if (!(rate & IEEE80211_RATE_BASIC)) continue; - /* - * Find h/w rate index. We know it exists because the rate - * set has already been negotiated. - */ - for (j = 0; ic->ic_sup_rates[IEEE80211_MODE_11G].rs_rates[j] != RV(rate); j++); - - mask |= 1 << j; + mask |= 1 << ic->ic_rt->rateCodeToIndex[RV(rate)]; } RAL_WRITE(sc, RT2661_TXRX_CSR5, mask); diff --git a/src/add-ons/kernel/drivers/network/wlan/wavelanwifi/dev/wi/if_wi.c b/src/add-ons/kernel/drivers/network/wlan/wavelanwifi/dev/wi/if_wi.c index f29c30d381..e46b74866b 100644 --- a/src/add-ons/kernel/drivers/network/wlan/wavelanwifi/dev/wi/if_wi.c +++ b/src/add-ons/kernel/drivers/network/wlan/wavelanwifi/dev/wi/if_wi.c @@ -295,7 +295,7 @@ wi_attach(device_t dev) SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pri_version", CTLFLAG_RD, &sc->sc_pri_firmware_ver, 0, "Primary Firmware version"); - SYSCTL_ADD_XINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "nic_id", + SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "nic_id", CTLFLAG_RD, &sc->sc_nic_id, 0, "NIC id"); SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "nic_name", CTLFLAG_RD, sc->sc_nic_name, 0, "NIC name"); diff --git a/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h b/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h index 0e78e10959..7cbc684fef 100644 --- a/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h +++ b/src/libs/compat/freebsd_wlan/net80211/_ieee80211.h @@ -133,7 +133,7 @@ enum ieee80211_roamingmode { */ struct ieee80211_channel { uint32_t ic_flags; /* see below */ - uint16_t ic_freq; /* setting in Mhz */ + uint16_t ic_freq; /* setting in MHz */ uint8_t ic_ieee; /* IEEE channel number */ int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */ int8_t ic_maxpower; /* maximum tx power in .5 dBm */ @@ -335,7 +335,7 @@ struct ieee80211_rateset { * the structure such that it can be used interchangeably * with an ieee80211_rateset (modulo structure size). */ -#define IEEE80211_HTRATE_MAXSIZE 127 +#define IEEE80211_HTRATE_MAXSIZE 77 struct ieee80211_htrateset { uint8_t rs_nrates; @@ -387,9 +387,16 @@ struct ieee80211_regdomain { /* * MIMO antenna/radio state. */ + +#define IEEE80211_MAX_CHAINS 3 +#define IEEE80211_MAX_EVM_PILOTS 6 + +/* + * XXX This doesn't yet export both ctl/ext chain details + */ struct ieee80211_mimo_info { - int8_t rssi[3]; /* per-antenna rssi */ - int8_t noise[3]; /* per-antenna noise floor */ + int8_t rssi[IEEE80211_MAX_CHAINS]; /* per-antenna rssi */ + int8_t noise[IEEE80211_MAX_CHAINS]; /* per-antenna noise floor */ uint8_t pad[2]; uint32_t evm[3]; /* EVM data */ }; diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211.c index fff964f61f..a03904176c 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211.c @@ -203,6 +203,15 @@ ieee80211_chan_init(struct ieee80211com *ic) DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); + /* + * Setup required information to fill the mcsset field, if driver did + * not. Assume a 2T2R setup for historic reasons. + */ + if (ic->ic_rxstream == 0) + ic->ic_rxstream = 2; + if (ic->ic_txstream == 0) + ic->ic_txstream = 2; + /* * Set auto mode to reset active channel state and any desired channel. */ @@ -413,6 +422,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, vap->iv_flags_ven = ic->ic_flags_ven; vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; vap->iv_htcaps = ic->ic_htcaps; + vap->iv_htextcaps = ic->ic_htextcaps; vap->iv_opmode = opmode; vap->iv_caps |= ieee80211_opcap[opmode]; switch (opmode) { @@ -1073,10 +1083,18 @@ ieee80211_media_setup(struct ieee80211com *ic, isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { addmedia(media, caps, addsta, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); - /* XXX could walk htrates */ - /* XXX known array size */ - if (ieee80211_htrates[15].ht40_rate_400ns > maxrate) - maxrate = ieee80211_htrates[15].ht40_rate_400ns; + i = ic->ic_txstream * 8 - 1; + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) + rate = ieee80211_htrates[i].ht40_rate_400ns; + else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)) + rate = ieee80211_htrates[i].ht40_rate_800ns; + else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)) + rate = ieee80211_htrates[i].ht20_rate_400ns; + else + rate = ieee80211_htrates[i].ht20_rate_800ns; + if (rate > maxrate) + maxrate = rate; } return maxrate; } @@ -1519,6 +1537,67 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode m { 13, IFM_IEEE80211_MCS }, { 14, IFM_IEEE80211_MCS }, { 15, IFM_IEEE80211_MCS }, + { 16, IFM_IEEE80211_MCS }, + { 17, IFM_IEEE80211_MCS }, + { 18, IFM_IEEE80211_MCS }, + { 19, IFM_IEEE80211_MCS }, + { 20, IFM_IEEE80211_MCS }, + { 21, IFM_IEEE80211_MCS }, + { 22, IFM_IEEE80211_MCS }, + { 23, IFM_IEEE80211_MCS }, + { 24, IFM_IEEE80211_MCS }, + { 25, IFM_IEEE80211_MCS }, + { 26, IFM_IEEE80211_MCS }, + { 27, IFM_IEEE80211_MCS }, + { 28, IFM_IEEE80211_MCS }, + { 29, IFM_IEEE80211_MCS }, + { 30, IFM_IEEE80211_MCS }, + { 31, IFM_IEEE80211_MCS }, + { 32, IFM_IEEE80211_MCS }, + { 33, IFM_IEEE80211_MCS }, + { 34, IFM_IEEE80211_MCS }, + { 35, IFM_IEEE80211_MCS }, + { 36, IFM_IEEE80211_MCS }, + { 37, IFM_IEEE80211_MCS }, + { 38, IFM_IEEE80211_MCS }, + { 39, IFM_IEEE80211_MCS }, + { 40, IFM_IEEE80211_MCS }, + { 41, IFM_IEEE80211_MCS }, + { 42, IFM_IEEE80211_MCS }, + { 43, IFM_IEEE80211_MCS }, + { 44, IFM_IEEE80211_MCS }, + { 45, IFM_IEEE80211_MCS }, + { 46, IFM_IEEE80211_MCS }, + { 47, IFM_IEEE80211_MCS }, + { 48, IFM_IEEE80211_MCS }, + { 49, IFM_IEEE80211_MCS }, + { 50, IFM_IEEE80211_MCS }, + { 51, IFM_IEEE80211_MCS }, + { 52, IFM_IEEE80211_MCS }, + { 53, IFM_IEEE80211_MCS }, + { 54, IFM_IEEE80211_MCS }, + { 55, IFM_IEEE80211_MCS }, + { 56, IFM_IEEE80211_MCS }, + { 57, IFM_IEEE80211_MCS }, + { 58, IFM_IEEE80211_MCS }, + { 59, IFM_IEEE80211_MCS }, + { 60, IFM_IEEE80211_MCS }, + { 61, IFM_IEEE80211_MCS }, + { 62, IFM_IEEE80211_MCS }, + { 63, IFM_IEEE80211_MCS }, + { 64, IFM_IEEE80211_MCS }, + { 65, IFM_IEEE80211_MCS }, + { 66, IFM_IEEE80211_MCS }, + { 67, IFM_IEEE80211_MCS }, + { 68, IFM_IEEE80211_MCS }, + { 69, IFM_IEEE80211_MCS }, + { 70, IFM_IEEE80211_MCS }, + { 71, IFM_IEEE80211_MCS }, + { 72, IFM_IEEE80211_MCS }, + { 73, IFM_IEEE80211_MCS }, + { 74, IFM_IEEE80211_MCS }, + { 75, IFM_IEEE80211_MCS }, + { 76, IFM_IEEE80211_MCS }, }; int m; diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211.h index c1bce85328..49716b3d80 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211.h @@ -131,6 +131,7 @@ struct ieee80211_qosframe_addr4 { #define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 #define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 #define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 +#define IEEE80211_FC0_SUBTYPE_ACTION_NOACK 0xe0 /* for TYPE_CTL */ #define IEEE80211_FC0_SUBTYPE_BAR 0x80 #define IEEE80211_FC0_SUBTYPE_BA 0x90 diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_acl.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_acl.c index cb20b87e73..da505e3b9d 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_acl.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_acl.c @@ -77,7 +77,7 @@ struct acl { struct aclstate { acl_lock_t as_lock; int as_policy; - int as_nacls; + uint32_t as_nacls; TAILQ_HEAD(, acl) as_list; /* list of all ACL's */ LIST_HEAD(, acl) as_hash[ACL_HASHSIZE]; struct ieee80211vap *as_vap; @@ -289,7 +289,8 @@ acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq) struct aclstate *as = vap->iv_as; struct acl *acl; struct ieee80211req_maclist *ap; - int error, space, i; + int error; + uint32_t i, space; switch (ireq->i_val) { case IEEE80211_MACCMD_POLICY: diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_adhoc.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_adhoc.c index d3b43bd572..8d9bcce589 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_adhoc.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_adhoc.c @@ -285,7 +285,6 @@ doprint(struct ieee80211vap *vap, int subtype) static int adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -412,9 +411,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", @@ -660,7 +657,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static int @@ -823,80 +819,44 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, is11bclient(rates, xrates) ? IEEE80211_SEND_LEGACY_11B : 0); break; - case IEEE80211_FC0_SUBTYPE_ACTION: { - const struct ieee80211_action *ia; - - if (vap->iv_state != IEEE80211_S_RUN) { + case IEEE80211_FC0_SUBTYPE_ACTION: + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (ni == vap->iv_bss) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "unknown node"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "wrong state %s", ieee80211_state_name[vap->iv_state]); vap->iv_stats.is_rx_mgtdiscard++; - return; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); } - /* - * action frame format: - * [1] category - * [1] action - * [tlv] parameters - */ - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action), return); - ia = (const struct ieee80211_action *) frm; - - vap->iv_stats.is_rx_action++; - IEEE80211_NODE_STAT(ni, rx_action); - - /* verify frame payloads but defer processing */ - /* XXX maybe push this to method */ - switch (ia->ia_category) { - case IEEE80211_ACTION_CAT_BA: - switch (ia->ia_action) { - case IEEE80211_ACTION_BA_ADDBA_REQUEST: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ba_addbarequest), - return); - break; - case IEEE80211_ACTION_BA_ADDBA_RESPONSE: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ba_addbaresponse), - return); - break; - case IEEE80211_ACTION_BA_DELBA: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ba_delba), - return); - break; - } - break; - case IEEE80211_ACTION_CAT_HT: - switch (ia->ia_action) { - case IEEE80211_ACTION_HT_TXCHWIDTH: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ht_txchwidth), - return); - break; - } - break; - } - ic->ic_recv_action(ni, wh, frm, efrm); break; - } - case IEEE80211_FC0_SUBTYPE_AUTH: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: - case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ATIM: case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, - wh, NULL, "%s", "not handled"); + wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; - return; + break; default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } @@ -910,6 +870,7 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_frame *wh; /* * Process management frames when scanning; useful for doing @@ -917,11 +878,42 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, */ if (ic->ic_flags & IEEE80211_F_SCAN) adhoc_recv_mgmt(ni, m0, subtype, rssi, nf); - else - vap->iv_stats.is_rx_mgtdiscard++; + else { + wh = mtod(m0, struct ieee80211_frame *); + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + case IEEE80211_FC0_SUBTYPE_BEACON: + case IEEE80211_FC0_SUBTYPE_ATIM: + case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ACTION: + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); + vap->iv_stats.is_rx_mgtdiscard++; + break; + default: + IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, + wh, "mgt", "subtype 0x%x not handled", subtype); + vap->iv_stats.is_rx_badsubtype++; + break; + } + } } static void -adhoc_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype) +adhoc_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; + } } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ageq.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ageq.c index 21745c8661..018ddc2711 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ageq.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ageq.c @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$"); void ieee80211_ageq_init(struct ieee80211_ageq *aq, int maxlen, const char *name) { - memset(aq, 0, sizeof(aq)); + memset(aq, 0, sizeof(*aq)); aq->aq_maxlen = maxlen; IEEE80211_AGEQ_INIT(aq, name); /* OS-dependent setup */ } @@ -154,7 +154,7 @@ ieee80211_ageq_drain_node(struct ieee80211_ageq *aq, * deltas (in seconds) relative to the head so we can check * and/or adjust only the head of the list. If a frame's age * exceeds the time quanta then remove it. The list of removed - * frames is is returned to the caller joined by m_nextpkt. + * frames is returned to the caller joined by m_nextpkt. */ struct mbuf * ieee80211_ageq_age(struct ieee80211_ageq *aq, int quanta) diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_alq.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_alq.c new file mode 100644 index 0000000000..0d06d4b9ef --- /dev/null +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_alq.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2011 Adrian Chadd, Xenion Lty Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifdef __FreeBSD__ +__FBSDID("$FreeBSD$"); +#endif + +/* + * net80211 fast-logging support, primarily for debugging. + * + * This implements a single debugging queue which includes + * per-device enumeration where needed. + */ + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct alq *ieee80211_alq; +static int ieee80211_alq_lost; +static int ieee80211_alq_logged; +static char ieee80211_alq_logfile[MAXPATHLEN] = "/tmp/net80211.log"; +static unsigned int ieee80211_alq_qsize = 64*1024; + +static int +ieee80211_alq_setlogging(int enable) +{ + int error; + + if (enable) { + if (ieee80211_alq) + alq_close(ieee80211_alq); + + error = alq_open(&ieee80211_alq, + ieee80211_alq_logfile, + curthread->td_ucred, + ALQ_DEFAULT_CMODE, + sizeof (struct ieee80211_alq_rec), + ieee80211_alq_qsize); + ieee80211_alq_lost = 0; + ieee80211_alq_logged = 0; + printf("net80211: logging to %s enabled; struct size %d bytes\n", + ieee80211_alq_logfile, sizeof(struct ieee80211_alq_rec)); + } else { + if (ieee80211_alq) + alq_close(ieee80211_alq); + ieee80211_alq = NULL; + printf("net80211: logging disabled\n"); + error = 0; + } + return (error); +} + +static int +sysctl_ieee80211_alq_log(SYSCTL_HANDLER_ARGS) +{ + int error, enable; + + enable = (ieee80211_alq != NULL); + error = sysctl_handle_int(oidp, &enable, 0, req); + if (error || !req->newptr) + return (error); + else + return (ieee80211_alq_setlogging(enable)); +} + +SYSCTL_PROC(_net_wlan, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW, + 0, 0, sysctl_ieee80211_alq_log, "I", "Enable net80211 alq logging"); +SYSCTL_INT(_net_wlan, OID_AUTO, alq_size, CTLFLAG_RW, + &ieee80211_alq_qsize, 0, "In-memory log size (#records)"); +SYSCTL_INT(_net_wlan, OID_AUTO, alq_lost, CTLFLAG_RW, + &ieee80211_alq_lost, 0, "Debugging operations not logged"); +SYSCTL_INT(_net_wlan, OID_AUTO, alq_logged, CTLFLAG_RW, + &ieee80211_alq_logged, 0, "Debugging operations logged"); + +static struct ale * +ieee80211_alq_get(void) +{ + struct ale *ale; + + ale = alq_get(ieee80211_alq, ALQ_NOWAIT); + if (!ale) + ieee80211_alq_lost++; + else + ieee80211_alq_logged++; + return ale; +} + +void +ieee80211_alq_log(struct ieee80211vap *vap, uint8_t op, u_char *p, int l) +{ + struct ale *ale; + struct ieee80211_alq_rec *r; + + if (ieee80211_alq == NULL) + return; + + ale = ieee80211_alq_get(); + if (! ale) + return; + + r = (struct ieee80211_alq_rec *) ale->ae_data; + r->r_timestamp = htonl(ticks); + r->r_version = 1; + r->r_wlan = htons(vap->iv_ifp->if_dunit); + r->r_op = op; + memcpy(&r->r_payload, p, MIN(l, sizeof(r->r_payload))); + alq_post(ieee80211_alq, ale); +} diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_alq.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_alq.h new file mode 100644 index 0000000000..648eba2ba0 --- /dev/null +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_alq.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2011 Adrian Chadd, Xenion Lty Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef __IEEE80211_ALQ_H__ +#define __IEEE80211_ALQ_H__ + +#define IEEE80211_ALQ_PAYLOAD_SIZE 24 + +/* + * timestamp + * wlan interface + * operation + * sub-operation + * rest of structure - operation specific + */ +struct ieee80211_alq_rec { + uint32_t r_timestamp; /* XXX may wrap! */ + uint16_t r_wlan; /* wlan interface number */ + uint8_t r_version; /* version */ + uint8_t r_op; /* top-level operation id */ + u_char r_payload[IEEE80211_ALQ_PAYLOAD_SIZE]; + /* operation-specific payload */ +}; + +/* General logging function */ +extern void ieee80211_alq_log(struct ieee80211vap *vap, uint8_t op, u_char *p, int l); + +#endif /* __IEEE80211_ALQ_H__ */ diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c index 7902545c28..73dd901a35 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c @@ -308,10 +308,10 @@ amrr_sysctlattach(struct ieee80211vap *vap, "amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, vap, 0, amrr_sysctl_interval, "I", "amrr operation interval (ms)"); /* XXX bounds check values */ - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "amrr_max_sucess_threshold", CTLFLAG_RW, &amrr->amrr_max_success_threshold, 0, ""); - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "amrr_min_sucess_threshold", CTLFLAG_RW, &amrr->amrr_min_success_threshold, 0, ""); } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto.h index 5a429fa5b5..8294546c68 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto.h @@ -78,6 +78,7 @@ struct ieee80211_key { #define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */ #define IEEE80211_KEY_RECV 0x0002 /* key used for recv */ #define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */ +#define IEEE80211_KEY_NOREPLAY 0x0008 /* ignore replay failures */ #define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */ #define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */ #define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */ @@ -98,7 +99,8 @@ struct ieee80211_key { uint8_t wk_macaddr[IEEE80211_ADDR_LEN]; }; #define IEEE80211_KEY_COMMON /* common flags passed in by apps */\ - (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP) + (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP | \ + IEEE80211_KEY_NOREPLAY) #define IEEE80211_KEY_DEVICE /* flags owned by device driver */\ (IEEE80211_KEY_DEVKEY|IEEE80211_KEY_CIPHER0|IEEE80211_KEY_CIPHER1) diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_ccmp.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_ccmp.c index 79df266cef..cb9ed0af01 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_ccmp.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_ccmp.c @@ -226,7 +226,8 @@ ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) } tid = ieee80211_gettid(wh); pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); - if (pn <= k->wk_keyrsc[tid]) { + if (pn <= k->wk_keyrsc[tid] && + (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { /* * Replay violation. */ diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_tkip.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_tkip.c index 6e1fda1fc9..05d9c74bdf 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_tkip.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_crypto_tkip.c @@ -281,7 +281,8 @@ tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) tid = ieee80211_gettid(wh); ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]); - if (ctx->rx_rsc <= k->wk_keyrsc[tid]) { + if (ctx->rx_rsc <= k->wk_keyrsc[tid] && + (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { /* * Replay violation; notify upper layer. */ diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_dfs.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_dfs.c index 72a21abc78..4ea1ac0ecb 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_dfs.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_dfs.c @@ -318,6 +318,8 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch * on the NOL to expire. */ /*XXX*/ + if_printf(ic->ic_ifp, "%s: No free channels; waiting for entry " + "on NOL to expire\n", __func__); } } else { /* diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_hostap.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_hostap.c index 63bcd3c9a1..e190450037 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_hostap.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_hostap.c @@ -472,7 +472,6 @@ doprint(struct ieee80211vap *vap, int subtype) static int hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -572,9 +571,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", @@ -914,7 +911,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static void @@ -2194,18 +2190,38 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, } case IEEE80211_FC0_SUBTYPE_ACTION: - if (vap->iv_state == IEEE80211_S_RUN) { - if (ieee80211_parse_action(ni, m0) == 0) - ic->ic_recv_action(ni, wh, frm, efrm); - } else + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (ni == vap->iv_bss) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "unknown node"); vap->iv_stats.is_rx_mgtdiscard++; + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); + } break; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_ATIM: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); + vap->iv_stats.is_rx_mgtdiscard++; + break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c index c823fa7a6b..aef705957b 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c @@ -54,31 +54,86 @@ __FBSDID("$FreeBSD$"); #define MS(_v, _f) (((_v) & _f) >> _f##_S) #define SM(_v, _f) (((_v) << _f##_S) & _f) -const struct ieee80211_mcs_rates ieee80211_htrates[16] = { - { 13, 14, 27, 30 }, /* MCS 0 */ - { 26, 29, 54, 60 }, /* MCS 1 */ - { 39, 43, 81, 90 }, /* MCS 2 */ - { 52, 58, 108, 120 }, /* MCS 3 */ - { 78, 87, 162, 180 }, /* MCS 4 */ - { 104, 116, 216, 240 }, /* MCS 5 */ - { 117, 130, 243, 270 }, /* MCS 6 */ - { 130, 144, 270, 300 }, /* MCS 7 */ - { 26, 29, 54, 60 }, /* MCS 8 */ - { 52, 58, 108, 120 }, /* MCS 9 */ - { 78, 87, 162, 180 }, /* MCS 10 */ - { 104, 116, 216, 240 }, /* MCS 11 */ - { 156, 173, 324, 360 }, /* MCS 12 */ - { 208, 231, 432, 480 }, /* MCS 13 */ - { 234, 260, 486, 540 }, /* MCS 14 */ - { 260, 289, 540, 600 } /* MCS 15 */ +const struct ieee80211_mcs_rates ieee80211_htrates[IEEE80211_HTRATE_MAXSIZE] = { + { 13, 14, 27, 30 }, /* MCS 0 */ + { 26, 29, 54, 60 }, /* MCS 1 */ + { 39, 43, 81, 90 }, /* MCS 2 */ + { 52, 58, 108, 120 }, /* MCS 3 */ + { 78, 87, 162, 180 }, /* MCS 4 */ + { 104, 116, 216, 240 }, /* MCS 5 */ + { 117, 130, 243, 270 }, /* MCS 6 */ + { 130, 144, 270, 300 }, /* MCS 7 */ + { 26, 29, 54, 60 }, /* MCS 8 */ + { 52, 58, 108, 120 }, /* MCS 9 */ + { 78, 87, 162, 180 }, /* MCS 10 */ + { 104, 116, 216, 240 }, /* MCS 11 */ + { 156, 173, 324, 360 }, /* MCS 12 */ + { 208, 231, 432, 480 }, /* MCS 13 */ + { 234, 260, 486, 540 }, /* MCS 14 */ + { 260, 289, 540, 600 }, /* MCS 15 */ + { 39, 43, 81, 90 }, /* MCS 16 */ + { 78, 87, 162, 180 }, /* MCS 17 */ + { 117, 130, 243, 270 }, /* MCS 18 */ + { 156, 173, 324, 360 }, /* MCS 19 */ + { 234, 260, 486, 540 }, /* MCS 20 */ + { 312, 347, 648, 720 }, /* MCS 21 */ + { 351, 390, 729, 810 }, /* MCS 22 */ + { 390, 433, 810, 900 }, /* MCS 23 */ + { 52, 58, 108, 120 }, /* MCS 24 */ + { 104, 116, 216, 240 }, /* MCS 25 */ + { 156, 173, 324, 360 }, /* MCS 26 */ + { 208, 231, 432, 480 }, /* MCS 27 */ + { 312, 347, 648, 720 }, /* MCS 28 */ + { 416, 462, 864, 960 }, /* MCS 29 */ + { 468, 520, 972, 1080 }, /* MCS 30 */ + { 520, 578, 1080, 1200 }, /* MCS 31 */ + { 0, 0, 12, 13 }, /* MCS 32 */ + { 78, 87, 162, 180 }, /* MCS 33 */ + { 104, 116, 216, 240 }, /* MCS 34 */ + { 130, 144, 270, 300 }, /* MCS 35 */ + { 117, 130, 243, 270 }, /* MCS 36 */ + { 156, 173, 324, 360 }, /* MCS 37 */ + { 195, 217, 405, 450 }, /* MCS 38 */ + { 104, 116, 216, 240 }, /* MCS 39 */ + { 130, 144, 270, 300 }, /* MCS 40 */ + { 130, 144, 270, 300 }, /* MCS 41 */ + { 156, 173, 324, 360 }, /* MCS 42 */ + { 182, 202, 378, 420 }, /* MCS 43 */ + { 182, 202, 378, 420 }, /* MCS 44 */ + { 208, 231, 432, 480 }, /* MCS 45 */ + { 156, 173, 324, 360 }, /* MCS 46 */ + { 195, 217, 405, 450 }, /* MCS 47 */ + { 195, 217, 405, 450 }, /* MCS 48 */ + { 234, 260, 486, 540 }, /* MCS 49 */ + { 273, 303, 567, 630 }, /* MCS 50 */ + { 273, 303, 567, 630 }, /* MCS 51 */ + { 312, 347, 648, 720 }, /* MCS 52 */ + { 130, 144, 270, 300 }, /* MCS 53 */ + { 156, 173, 324, 360 }, /* MCS 54 */ + { 182, 202, 378, 420 }, /* MCS 55 */ + { 156, 173, 324, 360 }, /* MCS 56 */ + { 182, 202, 378, 420 }, /* MCS 57 */ + { 208, 231, 432, 480 }, /* MCS 58 */ + { 234, 260, 486, 540 }, /* MCS 59 */ + { 208, 231, 432, 480 }, /* MCS 60 */ + { 234, 260, 486, 540 }, /* MCS 61 */ + { 260, 289, 540, 600 }, /* MCS 62 */ + { 260, 289, 540, 600 }, /* MCS 63 */ + { 286, 318, 594, 660 }, /* MCS 64 */ + { 195, 217, 405, 450 }, /* MCS 65 */ + { 234, 260, 486, 540 }, /* MCS 66 */ + { 273, 303, 567, 630 }, /* MCS 67 */ + { 234, 260, 486, 540 }, /* MCS 68 */ + { 273, 303, 567, 630 }, /* MCS 69 */ + { 312, 347, 648, 720 }, /* MCS 70 */ + { 351, 390, 729, 810 }, /* MCS 71 */ + { 312, 347, 648, 720 }, /* MCS 72 */ + { 351, 390, 729, 810 }, /* MCS 73 */ + { 390, 433, 810, 900 }, /* MCS 74 */ + { 390, 433, 810, 900 }, /* MCS 75 */ + { 429, 477, 891, 990 }, /* MCS 76 */ }; -static const struct ieee80211_htrateset ieee80211_rateset_11n = - { 16, { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15 } - }; - #ifdef IEEE80211_AMPDU_AGE static int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */ SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW, @@ -162,6 +217,9 @@ static int ieee80211_addba_response(struct ieee80211_node *ni, int code, int baparamset, int batimeout); static void ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap); +static void null_addba_response_timeout(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap); + static void ieee80211_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status); static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap); @@ -179,6 +237,7 @@ ieee80211_ht_attach(struct ieee80211com *ic) ic->ic_ampdu_enable = ieee80211_ampdu_enable; ic->ic_addba_request = ieee80211_addba_request; ic->ic_addba_response = ieee80211_addba_response; + ic->ic_addba_response_timeout = null_addba_response_timeout; ic->ic_addba_stop = ieee80211_addba_stop; ic->ic_bar_response = ieee80211_bar_response; ic->ic_ampdu_rx_start = ampdu_rx_start; @@ -247,40 +306,149 @@ ieee80211_ht_vdetach(struct ieee80211vap *vap) { } +static int +ht_getrate(struct ieee80211com *ic, int index, int mode, int ratetype) +{ + int mword, rate; + + mword = ieee80211_rate2media(ic, index | IEEE80211_RATE_MCS, mode); + if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS) + return (0); + switch (ratetype) { + case 0: + rate = ieee80211_htrates[index].ht20_rate_800ns; + break; + case 1: + rate = ieee80211_htrates[index].ht20_rate_400ns; + break; + case 2: + rate = ieee80211_htrates[index].ht40_rate_800ns; + break; + default: + rate = ieee80211_htrates[index].ht40_rate_400ns; + break; + } + return (rate); +} + +static struct printranges { + int minmcs; + int maxmcs; + int txstream; + int ratetype; + int htcapflags; +} ranges[] = { + { 0, 7, 1, 0, 0 }, + { 8, 15, 2, 0, 0 }, + { 16, 23, 3, 0, 0 }, + { 24, 31, 4, 0, 0 }, + { 32, 0, 1, 2, IEEE80211_HTC_TXMCS32 }, + { 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL }, + { 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL }, + { 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL }, + { 0, 0, 0, 0, 0 }, +}; + static void -ht_announce(struct ieee80211com *ic, int mode, - const struct ieee80211_htrateset *rs) +ht_rateprint(struct ieee80211com *ic, int mode, int ratetype) { struct ifnet *ifp = ic->ic_ifp; - int i, rate, mword; + int minrate, maxrate; + struct printranges *range; - if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]); - for (i = 0; i < rs->rs_nrates; i++) { - mword = ieee80211_rate2media(ic, - rs->rs_rates[i] | IEEE80211_RATE_MCS, mode); - if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS) + for (range = ranges; range->txstream != 0; range++) { + if (ic->ic_txstream < range->txstream) continue; - rate = ieee80211_htrates[rs->rs_rates[i]].ht40_rate_400ns; - printf("%s%d%sMbps", (i != 0 ? " " : ""), - rate / 2, ((rate & 0x1) != 0 ? ".5" : "")); + if (range->htcapflags && + (ic->ic_htcaps & range->htcapflags) == 0) + continue; + if (ratetype < range->ratetype) + continue; + minrate = ht_getrate(ic, range->minmcs, mode, ratetype); + maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype); + if (range->maxmcs) { + if_printf(ifp, "MCS %d-%d: %d%sMbps - %d%sMbps\n", + range->minmcs, range->maxmcs, + minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""), + maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : "")); + } else { + if_printf(ifp, "MCS %d: %d%sMbps\n", range->minmcs, + minrate/2, ((minrate & 0x1) != 0 ? ".5" : "")); + } + } +} + +static void +ht_announce(struct ieee80211com *ic, int mode) +{ + struct ifnet *ifp = ic->ic_ifp; + const char *modestr = ieee80211_phymode_name[mode]; + + if_printf(ifp, "%s MCS 20MHz\n", modestr); + ht_rateprint(ic, mode, 0); + if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) { + if_printf(ifp, "%s MCS 20MHz SGI\n", modestr); + ht_rateprint(ic, mode, 1); + } + if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) { + if_printf(ifp, "%s MCS 40MHz:\n", modestr); + ht_rateprint(ic, mode, 2); + } + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) { + if_printf(ifp, "%s MCS 40MHz SGI:\n", modestr); + ht_rateprint(ic, mode, 3); } - printf("\n"); } void ieee80211_ht_announce(struct ieee80211com *ic) { + struct ifnet *ifp = ic->ic_ifp; + + if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || + isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) + if_printf(ifp, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream); if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA)) - ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n); + ht_announce(ic, IEEE80211_MODE_11NA); if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) - ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n); + ht_announce(ic, IEEE80211_MODE_11NG); } +static struct ieee80211_htrateset htrateset; + const struct ieee80211_htrateset * ieee80211_get_suphtrates(struct ieee80211com *ic, - const struct ieee80211_channel *c) + const struct ieee80211_channel *c) { - return &ieee80211_rateset_11n; +#define ADDRATE(x) do { \ + htrateset.rs_rates[htrateset.rs_nrates] = x; \ + htrateset.rs_nrates++; \ +} while (0) + int i; + + memset(&htrateset, 0, sizeof(struct ieee80211_htrateset)); + for (i = 0; i < ic->ic_txstream * 8; i++) + ADDRATE(i); + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTC_TXMCS32)) + ADDRATE(i); + if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { + if (ic->ic_txstream >= 2) { + for (i = 33; i <= 38; i++) + ADDRATE(i); + } + if (ic->ic_txstream >= 3) { + for (i = 39; i <= 52; i++) + ADDRATE(i); + } + if (ic->ic_txstream == 4) { + for (i = 53; i <= 76; i++) + ADDRATE(i); + } + } + return &htrateset; +#undef ADDRATE } /* @@ -396,6 +564,7 @@ ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap, static void ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap) { + ampdu_rx_purge(rap); rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND); } @@ -656,7 +825,7 @@ again: if (off < rap->rxa_wnd) { /* * Common case (hopefully): in the BA window. - * Sec 9.10.7.6 a) (D2.04 p.118 line 47) + * Sec 9.10.7.6.2 a) (p.137) */ #ifdef IEEE80211_AMPDU_AGE /* @@ -721,7 +890,7 @@ again: /* * Outside the BA window, but within range; * flush the reorder q and move the window. - * Sec 9.10.7.6 b) (D2.04 p.118 line 60) + * Sec 9.10.7.6.2 b) (p.138) */ IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni, "move BA win <%u:%u> (%u frames) rxseq %u tid %u", @@ -745,7 +914,7 @@ again: } else { /* * Outside the BA window and out of range; toss. - * Sec 9.10.7.6 c) (D2.04 p.119 line 16) + * Sec 9.10.7.6.2 c) (p.138) */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr, @@ -809,7 +978,7 @@ ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0) if (off < IEEE80211_SEQ_BA_RANGE) { /* * Flush the reorder q up to rxseq and move the window. - * Sec 9.10.7.6 a) (D2.04 p.119 line 22) + * Sec 9.10.7.6.3 a) (p.138) */ IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni, "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u", @@ -830,7 +999,7 @@ ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0) } else { /* * Out of range; toss. - * Sec 9.10.7.6 b) (D2.04 p.119 line 41) + * Sec 9.10.7.6.3 b) (p.138) */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr, @@ -1398,7 +1567,7 @@ ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie) htcap_update_shortgi(ni); /* NB: honor operating mode constraint */ - /* XXX 40 MHZ intolerant */ + /* XXX 40 MHz intolerant */ htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ? IEEE80211_CHAN_HT20 : 0; if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) && @@ -1417,10 +1586,22 @@ ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie) int ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags) { + struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; const struct ieee80211_ie_htcap *htcap; struct ieee80211_htrateset *rs; - int i; + int i, maxequalmcs, maxunequalmcs; + + maxequalmcs = ic->ic_txstream * 8 - 1; + if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { + if (ic->ic_txstream >= 2) + maxunequalmcs = 38; + if (ic->ic_txstream >= 3) + maxunequalmcs = 52; + if (ic->ic_txstream >= 4) + maxunequalmcs = 76; + } else + maxunequalmcs = 0; rs = &ni->ni_htrates; memset(rs, 0, sizeof(*rs)); @@ -1439,6 +1620,13 @@ ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags) vap->iv_stats.is_rx_rstoobig++; break; } + if (i <= 31 && i > maxequalmcs) + continue; + if (i == 32 && + (ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0) + continue; + if (i > 32 && i > maxunequalmcs) + continue; rs->rs_rates[rs->rs_nrates++] = i; } } @@ -1507,14 +1695,23 @@ ampdu_tx_stop(struct ieee80211_tx_ampdu *tap) tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK); } +/* + * ADDBA response timeout. + * + * If software aggregation and per-TID queue management was done here, + * that queue would be unpaused after the ADDBA timeout occurs. + */ static void addba_timeout(void *arg) { struct ieee80211_tx_ampdu *tap = arg; + struct ieee80211_node *ni = tap->txa_ni; + struct ieee80211com *ic = ni->ni_ic; /* XXX ? */ tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND; tap->txa_attempts++; + ic->ic_addba_response_timeout(ni, tap); } static void @@ -1537,6 +1734,12 @@ addba_stop_timeout(struct ieee80211_tx_ampdu *tap) } } +static void +null_addba_response_timeout(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap) +{ +} + /* * Default method for requesting A-MPDU tx aggregation. * We setup the specified state block and start a timer @@ -1621,7 +1824,7 @@ ht_recv_action_ba_addba_request(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap; uint8_t dialogtoken; uint16_t baparamset, batimeout, baseqctl; - uint16_t args[4]; + uint16_t args[5]; int tid; dialogtoken = frm[2]; @@ -1671,6 +1874,7 @@ ht_recv_action_ba_addba_request(struct ieee80211_node *ni, | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ) ; args[3] = 0; + args[4] = 0; ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA, IEEE80211_ACTION_BA_ADDBA_RESPONSE, args); return 0; @@ -1874,7 +2078,7 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { struct ieee80211com *ic = ni->ni_ic; - uint16_t args[4]; + uint16_t args[5]; int tid, dialogtoken; static int tokens = 0; /* XXX */ @@ -1891,13 +2095,14 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, tap->txa_start = ni->ni_txseqs[tid]; args[0] = dialogtoken; - args[1] = IEEE80211_BAPS_POLICY_IMMEDIATE + args[1] = 0; /* NB: status code not used */ + args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE | SM(tid, IEEE80211_BAPS_TID) | SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ) ; - args[2] = 0; /* batimeout */ + args[3] = 0; /* batimeout */ /* NB: do first so there's no race against reply */ - if (!ic->ic_addba_request(ni, tap, dialogtoken, args[1], args[2])) { + if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) { /* unable to setup state, don't make request */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, "%s: could not setup BA stream for AC %d", @@ -1911,7 +2116,7 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, } tokens = dialogtoken; /* allocate token */ /* NB: after calling ic_addba_request so driver can set txa_start */ - args[3] = SM(tap->txa_start, IEEE80211_BASEQ_START) + args[4] = SM(tap->txa_start, IEEE80211_BASEQ_START) | SM(0, IEEE80211_BASEQ_FRAG) ; return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA, @@ -2002,7 +2207,7 @@ bar_tx_complete(struct ieee80211_node *ni, void *arg, int status) callout_pending(&tap->txa_timer)) { struct ieee80211com *ic = ni->ni_ic; - if (status) /* ACK'd */ + if (status == 0) /* ACK'd */ bar_stop_timer(tap); ic->ic_bar_response(ni, tap, status); /* NB: just let timer expire so we pace requests */ @@ -2014,7 +2219,7 @@ ieee80211_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status) { - if (status != 0) { /* got ACK */ + if (status == 0) { /* got ACK */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u", tap->txa_start, @@ -2104,11 +2309,15 @@ ieee80211_send_bar(struct ieee80211_node *ni, ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)", tid, barctl, seq, tap->txa_attempts); + /* + * ic_raw_xmit will free the node reference + * regardless of queue/TX success or failure. + */ ret = ic->ic_raw_xmit(ni, m, NULL); if (ret != 0) { /* xmit failed, clear state flag */ tap->txa_flags &= ~IEEE80211_AGGR_BARPEND; - goto bad; + return ret; } /* XXX hack against tx complete happening before timer is started */ if (tap->txa_flags & IEEE80211_AGGR_BARPEND) @@ -2157,12 +2366,12 @@ ht_send_action_ba_addba(struct ieee80211_node *ni, uint8_t *frm; IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni, - "send ADDBA %s: dialogtoken %d " + "send ADDBA %s: dialogtoken %d status %d " "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x", (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ? "request" : "response", - args[0], args[1], MS(args[1], IEEE80211_BAPS_TID), - args[2], args[3]); + args[0], args[1], args[2], MS(args[2], IEEE80211_BAPS_TID), + args[3], args[4]); IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, @@ -2179,10 +2388,12 @@ ht_send_action_ba_addba(struct ieee80211_node *ni, *frm++ = category; *frm++ = action; *frm++ = args[0]; /* dialog token */ - ADDSHORT(frm, args[1]); /* baparamset */ - ADDSHORT(frm, args[2]); /* batimeout */ + if (action == IEEE80211_ACTION_BA_ADDBA_RESPONSE) + ADDSHORT(frm, args[1]); /* status code */ + ADDSHORT(frm, args[2]); /* baparamset */ + ADDSHORT(frm, args[3]); /* batimeout */ if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) - ADDSHORT(frm, args[3]); /* baseqctl */ + ADDSHORT(frm, args[4]); /* baseqctl */ m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); return ht_action_output(ni, m); } else { @@ -2276,21 +2487,49 @@ ht_send_action_ht_txchwidth(struct ieee80211_node *ni, #undef ADDSHORT /* - * Construct the MCS bit mask for inclusion - * in an HT information element. + * Construct the MCS bit mask for inclusion in an HT capabilities + * information element. */ -static void -ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs) +static void +ieee80211_set_mcsset(struct ieee80211com *ic, uint8_t *frm) { int i; + uint8_t txparams; - for (i = 0; i < rs->rs_nrates; i++) { - int r = rs->rs_rates[i] & IEEE80211_RATE_VAL; - if (r < IEEE80211_HTRATE_MAXSIZE) { /* XXX? */ - /* NB: this assumes a particular implementation */ - setbit(frm, r); + KASSERT((ic->ic_rxstream > 0 && ic->ic_rxstream <= 4), + ("ic_rxstream %d out of range", ic->ic_rxstream)); + KASSERT((ic->ic_txstream > 0 && ic->ic_txstream <= 4), + ("ic_txstream %d out of range", ic->ic_txstream)); + + for (i = 0; i < ic->ic_rxstream * 8; i++) + setbit(frm, i); + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTC_RXMCS32)) + setbit(frm, 32); + if (ic->ic_htcaps & IEEE80211_HTC_RXUNEQUAL) { + if (ic->ic_rxstream >= 2) { + for (i = 33; i <= 38; i++) + setbit(frm, i); + } + if (ic->ic_rxstream >= 3) { + for (i = 39; i <= 52; i++) + setbit(frm, i); + } + if (ic->ic_txstream >= 4) { + for (i = 53; i <= 76; i++) + setbit(frm, i); } } + + if (ic->ic_rxstream != ic->ic_txstream) { + txparams = 0x1; /* TX MCS set defined */ + txparams |= 0x2; /* TX RX MCS not equal */ + txparams |= (ic->ic_txstream - 1) << 2; /* num TX streams */ + if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) + txparams |= 0x16; /* TX unequal modulation sup */ + } else + txparams = 0; + frm[12] = txparams; } /* @@ -2304,8 +2543,9 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni) frm[1] = (v) >> 8; \ frm += 2; \ } while (0) + struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; - uint16_t caps; + uint16_t caps, extcaps; int rxmax, density; /* HT capabilities */ @@ -2327,6 +2567,17 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni) /* use advertised setting (XXX locally constraint) */ rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU); density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); + + /* + * NB: Hardware might support HT40 on some but not all + * channels. We can't determine this earlier because only + * after association the channel is upgraded to HT based + * on the negotiated capabilities. + */ + if (ni->ni_chan != IEEE80211_CHAN_ANYC && + findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40U) == NULL && + findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40D) == NULL) + caps &= ~IEEE80211_HTCAP_CHWIDTH40; } else { /* override 20/40 use based on current channel */ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) @@ -2356,15 +2607,24 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni) /* supported MCS set */ /* - * XXX it would better to get the rate set from ni_htrates - * so we can restrict it but for sta mode ni_htrates isn't - * setup when we're called to form an AssocReq frame so for - * now we're restricted to the default HT rate set. + * XXX: For sta mode the rate set should be restricted based + * on the AP's capabilities, but ni_htrates isn't setup when + * we're called to form an AssocReq frame so for now we're + * restricted to the device capabilities. */ - ieee80211_set_htrates(frm, &ieee80211_rateset_11n); + ieee80211_set_mcsset(ni->ni_ic, frm); + + frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) - + __offsetof(struct ieee80211_ie_htcap, hc_mcsset); + + /* HT extended capabilities */ + extcaps = vap->iv_htextcaps & 0xffff; + + ADDSHORT(frm, extcaps); frm += sizeof(struct ieee80211_ie_htcap) - - __offsetof(struct ieee80211_ie_htcap, hc_mcsset); + __offsetof(struct ieee80211_ie_htcap, hc_txbf); + return frm; #undef ADDSHORT } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h index 4d81893918..d345fe9fb3 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h @@ -144,7 +144,8 @@ struct ieee80211_rx_ampdu { int rxa_age; /* age of oldest frame in window */ int rxa_nframes; /* frames since ADDBA */ struct mbuf *rxa_m[IEEE80211_AGGR_BAWMAX]; - uint64_t rxa_pad[4]; + void *rxa_private; + uint64_t rxa_pad[3]; }; void ieee80211_ht_attach(struct ieee80211com *); @@ -160,7 +161,7 @@ struct ieee80211_mcs_rates { uint16_t ht40_rate_800ns; uint16_t ht40_rate_400ns; }; -extern const struct ieee80211_mcs_rates ieee80211_htrates[16]; +extern const struct ieee80211_mcs_rates ieee80211_htrates[]; const struct ieee80211_htrateset *ieee80211_get_suphtrates( struct ieee80211com *, const struct ieee80211_channel *); diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.c index 28a58fe06b..a18da4afe2 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.c @@ -57,8 +57,53 @@ __FBSDID("$FreeBSD$"); #include #endif +static void +ieee80211_process_mimo(struct ieee80211_node *ni, struct ieee80211_rx_stats *rx) +{ + int i; + + /* Verify the required MIMO bits are set */ + if ((rx->r_flags & (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) != + (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) + return; + + /* XXX This assumes the MIMO radios have both ctl and ext chains */ + for (i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) { + IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ctl[i], rx->c_rssi_ctl[i]); + IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ext[i], rx->c_rssi_ext[i]); + } + + /* XXX This also assumes the MIMO radios have both ctl and ext chains */ + for(i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) { + ni->ni_mimo_noise_ctl[i] = rx->c_nf_ctl[i]; + ni->ni_mimo_noise_ext[i] = rx->c_nf_ext[i]; + } + ni->ni_mimo_chains = rx->c_chain; +} + +int +ieee80211_input_mimo(struct ieee80211_node *ni, struct mbuf *m, + struct ieee80211_rx_stats *rx) +{ + /* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */ + ieee80211_process_mimo(ni, rx); + return ieee80211_input(ni, m, rx->rssi, rx->nf); +} + int ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf) +{ + struct ieee80211_rx_stats rx; + + rx.r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI; + rx.nf = nf; + rx.rssi = rssi; + return ieee80211_input_mimo_all(ic, m, &rx); +} + +int +ieee80211_input_mimo_all(struct ieee80211com *ic, struct mbuf *m, + struct ieee80211_rx_stats *rx) { struct ieee80211vap *vap; int type = -1; @@ -96,7 +141,7 @@ ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf) m = NULL; } ni = ieee80211_ref_node(vap->iv_bss); - type = ieee80211_input(ni, mcopy, rssi, nf); + type = ieee80211_input_mimo(ni, mcopy, rx); ieee80211_free_node(ni); } if (m != NULL) /* no vaps, reclaim mbuf */ @@ -677,7 +722,6 @@ ieee80211_parse_action(struct ieee80211_node *ni, struct mbuf *m) IEEE80211_NODE_STAT(ni, rx_action); /* verify frame payloads but defer processing */ - /* XXX maybe push this to method */ switch (ia->ia_category) { case IEEE80211_ACTION_CAT_BA: switch (ia->ia_action) { diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.h index 921d07c238..c5638a9579 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_input.h @@ -142,6 +142,104 @@ ishtinfooui(const uint8_t *frm) return frm[1] > 3 && LE_READ_4(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI); } +#include /* For le16toh() */ + +/* + * Check the current frame sequence number against the current TID + * state and return whether it's in sequence or should be dropped. + * + * Since out of order packet and duplicate packet eliminations should + * be done by the AMPDU RX code, this routine blindly accepts all + * frames from a HT station w/ a TID that is currently doing AMPDU-RX. + * HT stations without WME or where the TID is not doing AMPDU-RX + * are checked like non-HT stations. + * + * The routine only eliminates packets whose sequence/fragment + * match or are less than the last seen sequence/fragment number + * AND are retransmits It doesn't try to eliminate out of order packets. + * + * Since all frames after sequence number 4095 will be less than 4095 + * (as the seqnum wraps), handle that special case so packets aren't + * incorrectly dropped - ie, if the next packet is sequence number 0 + * but a retransmit since the initial packet didn't make it. + */ +static __inline int +ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh) +{ +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_EQ(a,b) ((int)((a)-(b)) == 0) +#define HAS_SEQ(type) ((type & 0x4) == 0) +#define SEQNO(a) ((a) >> IEEE80211_SEQ_SEQ_SHIFT) +#define FRAGNO(a) ((a) & IEEE80211_SEQ_FRAG_MASK) + uint16_t rxseq; + uint8_t type; + uint8_t tid; + struct ieee80211_rx_ampdu *rap; + + rxseq = le16toh(*(uint16_t *)wh->i_seq); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + /* Types with no sequence number are always treated valid */ + if (! HAS_SEQ(type)) + return 1; + + tid = ieee80211_gettid(wh); + + /* + * Only do the HT AMPDU check for WME stations; non-WME HT stations + * shouldn't exist outside of debugging. We should at least + * handle that. + */ + if (tid < WME_NUM_TID) { + rap = &ni->ni_rx_ampdu[tid]; + /* HT nodes currently doing RX AMPDU are always valid */ + if ((ni->ni_flags & IEEE80211_NODE_HT) && + (rap->rxa_flags & IEEE80211_AGGR_RUNNING)) + return 1; + } + + /* + * Otherwise, retries for packets below or equal to the last + * seen sequence number should be dropped. + */ + + /* + * Treat frame seqnum 4095 as special due to boundary + * wrapping conditions. + */ + if (SEQNO(ni->ni_rxseqs[tid]) == 4095) { + /* + * Drop retransmits on seqnum 4095/current fragment for itself. + */ + if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) && + (wh->i_fc[1] & IEEE80211_FC1_RETRY)) + return 0; + /* + * Treat any subsequent frame as fine if the last seen frame + * is 4095 and it's not a retransmit for the same sequence + * number. However, this doesn't capture incorrectly ordered + * fragments w/ sequence number 4095. It shouldn't be seen + * in practice, but see the comment above for further info. + */ + return 1; + } + + /* + * At this point we assume that retransmitted seq/frag numbers below + * the current can simply be eliminated. + */ + if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && + SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) + return 0; + + return 1; +#undef SEQ_LEQ +#undef SEQ_EQ +#undef HAS_SEQ +#undef SEQNO +#undef FRAGNO +} + void ieee80211_deliver_data(struct ieee80211vap *, struct ieee80211_node *, struct mbuf *); struct mbuf *ieee80211_defrag(struct ieee80211_node *, diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c index fb1a2427e1..15c6c17a7f 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c @@ -70,6 +70,8 @@ __FBSDID("$FreeBSD$"); static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; static struct ieee80211_channel *findchannel(struct ieee80211com *, int ieee, int mode); +static int ieee80211_scanreq(struct ieee80211vap *, + struct ieee80211_scan_req *); static __noinline int ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq) @@ -141,7 +143,7 @@ static __noinline int ieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; - int space; + uint32_t space; space = __offsetof(struct ieee80211req_chaninfo, ic_chans[ic->ic_nchans]); @@ -205,7 +207,7 @@ ieee80211_ioctl_getstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; uint8_t macaddr[IEEE80211_ADDR_LEN]; - const int off = __offsetof(struct ieee80211req_sta_stats, is_stats); + const size_t off = __offsetof(struct ieee80211req_sta_stats, is_stats); int error; if (ireq->i_len < off) @@ -325,7 +327,7 @@ ieee80211_ioctl_getscanresults(struct ieee80211vap *vap, if (req.space > ireq->i_len) req.space = ireq->i_len; if (req.space > 0) { - size_t space; + uint32_t space; void *p; space = req.space; @@ -464,7 +466,7 @@ get_sta_info(void *arg, struct ieee80211_node *ni) static __noinline int getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq, - struct ieee80211_node *ni, int off) + struct ieee80211_node *ni, size_t off) { struct ieee80211com *ic = vap->iv_ic; struct stainforeq req; @@ -509,7 +511,7 @@ static __noinline int ieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq) { uint8_t macaddr[IEEE80211_ADDR_LEN]; - const int off = __offsetof(struct ieee80211req_sta_req, info); + const size_t off = __offsetof(struct ieee80211req_sta_req, info); struct ieee80211_node *ni; int error; @@ -1479,14 +1481,15 @@ mlmelookup(void *arg, const struct ieee80211_scan_entry *se) } static __noinline int -setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], - int ssid_len, const uint8_t ssid[IEEE80211_NWID_LEN]) +setmlme_assoc_sta(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len, + const uint8_t ssid[IEEE80211_NWID_LEN]) { struct scanlookup lookup; - /* XXX ibss/ahdemo */ - if (vap->iv_opmode != IEEE80211_M_STA) - return EINVAL; + KASSERT(vap->iv_opmode == IEEE80211_M_STA, + ("expected opmode STA not %s", + ieee80211_opmode_name[vap->iv_opmode])); /* NB: this is racey if roaming is !manual */ lookup.se = NULL; @@ -1502,6 +1505,37 @@ setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], return 0; } +static __noinline int +setmlme_assoc_adhoc(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len, + const uint8_t ssid[IEEE80211_NWID_LEN]) +{ + struct ieee80211_scan_req sr; + + KASSERT(vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_AHDEMO, + ("expected opmode IBSS or AHDEMO not %s", + ieee80211_opmode_name[vap->iv_opmode])); + + if (ssid_len == 0) + return EINVAL; + + /* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */ + memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN); + vap->iv_des_ssid[0].len = ssid_len; + memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len); + vap->iv_des_nssid = 1; + + memset(&sr, 0, sizeof(sr)); + sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE; + sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; + memcpy(sr.sr_ssid[0].ssid, ssid, ssid_len); + sr.sr_ssid[0].len = ssid_len; + sr.sr_nssid = 1; + + return ieee80211_scanreq(vap, &sr); +} + static __noinline int ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq) { @@ -1513,9 +1547,13 @@ ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq) error = copyin(ireq->i_data, &mlme, sizeof(mlme)); if (error) return error; - if (mlme.im_op == IEEE80211_MLME_ASSOC) - return setmlme_assoc(vap, mlme.im_macaddr, + if (vap->iv_opmode == IEEE80211_M_STA && + mlme.im_op == IEEE80211_MLME_ASSOC) + return setmlme_assoc_sta(vap, mlme.im_macaddr, vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid); + else if (mlme.im_op == IEEE80211_MLME_ASSOC) + return setmlme_assoc_adhoc(vap, mlme.im_macaddr, + mlme.im_ssid_len, mlme.im_ssid); else return setmlme_common(vap, mlme.im_op, mlme.im_macaddr, mlme.im_reason); @@ -2344,8 +2382,8 @@ ieee80211_ioctl_chanswitch(struct ieee80211vap *vap, struct ieee80211req *ireq) return error; } -static __noinline int -ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) +static int +ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr) { #define IEEE80211_IOC_SCAN_FLAGS \ (IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ACTIVE | \ @@ -2354,48 +2392,38 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) IEEE80211_IOC_SCAN_NOJOIN | IEEE80211_IOC_SCAN_FLUSH | \ IEEE80211_IOC_SCAN_CHECK) struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_req sr; /* XXX off stack? */ int error, i; - /* NB: parent must be running */ - if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - return ENXIO; - - if (ireq->i_len != sizeof(sr)) - return EINVAL; - error = copyin(ireq->i_data, &sr, sizeof(sr)); - if (error != 0) - return error; /* convert duration */ - if (sr.sr_duration == IEEE80211_IOC_SCAN_FOREVER) - sr.sr_duration = IEEE80211_SCAN_FOREVER; + if (sr->sr_duration == IEEE80211_IOC_SCAN_FOREVER) + sr->sr_duration = IEEE80211_SCAN_FOREVER; else { - if (sr.sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN || - sr.sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX) + if (sr->sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN || + sr->sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX) return EINVAL; - sr.sr_duration = msecs_to_ticks(sr.sr_duration); - if (sr.sr_duration < 1) - sr.sr_duration = 1; + sr->sr_duration = msecs_to_ticks(sr->sr_duration); + if (sr->sr_duration < 1) + sr->sr_duration = 1; } /* convert min/max channel dwell */ - if (sr.sr_mindwell != 0) { - sr.sr_mindwell = msecs_to_ticks(sr.sr_mindwell); - if (sr.sr_mindwell < 1) - sr.sr_mindwell = 1; + if (sr->sr_mindwell != 0) { + sr->sr_mindwell = msecs_to_ticks(sr->sr_mindwell); + if (sr->sr_mindwell < 1) + sr->sr_mindwell = 1; } - if (sr.sr_maxdwell != 0) { - sr.sr_maxdwell = msecs_to_ticks(sr.sr_maxdwell); - if (sr.sr_maxdwell < 1) - sr.sr_maxdwell = 1; + if (sr->sr_maxdwell != 0) { + sr->sr_maxdwell = msecs_to_ticks(sr->sr_maxdwell); + if (sr->sr_maxdwell < 1) + sr->sr_maxdwell = 1; } /* NB: silently reduce ssid count to what is supported */ - if (sr.sr_nssid > IEEE80211_SCAN_MAX_SSID) - sr.sr_nssid = IEEE80211_SCAN_MAX_SSID; - for (i = 0; i < sr.sr_nssid; i++) - if (sr.sr_ssid[i].len > IEEE80211_NWID_LEN) + if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID) + sr->sr_nssid = IEEE80211_SCAN_MAX_SSID; + for (i = 0; i < sr->sr_nssid; i++) + if (sr->sr_ssid[i].len > IEEE80211_NWID_LEN) return EINVAL; /* cleanse flags just in case, could reject if invalid flags */ - sr.sr_flags &= IEEE80211_IOC_SCAN_FLAGS; + sr->sr_flags &= IEEE80211_IOC_SCAN_FLAGS; /* * Add an implicit NOPICK if the vap is not marked UP. This * allows applications to scan without joining a bss (or picking @@ -2403,13 +2431,13 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) * roaming mode--you just need to mark the parent device UP. */ if ((vap->iv_ifp->if_flags & IFF_UP) == 0) - sr.sr_flags |= IEEE80211_IOC_SCAN_NOPICK; + sr->sr_flags |= IEEE80211_IOC_SCAN_NOPICK; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: flags 0x%x%s duration 0x%x mindwell %u maxdwell %u nssid %d\n", - __func__, sr.sr_flags, + __func__, sr->sr_flags, (vap->iv_ifp->if_flags & IFF_UP) == 0 ? " (!IFF_UP)" : "", - sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, sr.sr_nssid); + sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, sr->sr_nssid); /* * If we are in INIT state then the driver has never had a chance * to setup hardware state to do a scan; we must use the state @@ -2424,13 +2452,13 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) IEEE80211_LOCK(ic); if (vap->iv_state == IEEE80211_S_INIT) { /* NB: clobbers previous settings */ - vap->iv_scanreq_flags = sr.sr_flags; - vap->iv_scanreq_duration = sr.sr_duration; - vap->iv_scanreq_nssid = sr.sr_nssid; - for (i = 0; i < sr.sr_nssid; i++) { - vap->iv_scanreq_ssid[i].len = sr.sr_ssid[i].len; - memcpy(vap->iv_scanreq_ssid[i].ssid, sr.sr_ssid[i].ssid, - sr.sr_ssid[i].len); + vap->iv_scanreq_flags = sr->sr_flags; + vap->iv_scanreq_duration = sr->sr_duration; + vap->iv_scanreq_nssid = sr->sr_nssid; + for (i = 0; i < sr->sr_nssid; i++) { + vap->iv_scanreq_ssid[i].len = sr->sr_ssid[i].len; + memcpy(vap->iv_scanreq_ssid[i].ssid, + sr->sr_ssid[i].ssid, sr->sr_ssid[i].len); } vap->iv_flags_ext |= IEEE80211_FEXT_SCANREQ; IEEE80211_UNLOCK(ic); @@ -2438,25 +2466,45 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) } else { vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; IEEE80211_UNLOCK(ic); - /* XXX neeed error return codes */ - if (sr.sr_flags & IEEE80211_IOC_SCAN_CHECK) { - (void) ieee80211_check_scan(vap, sr.sr_flags, - sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, - sr.sr_nssid, + if (sr->sr_flags & IEEE80211_IOC_SCAN_CHECK) { + error = ieee80211_check_scan(vap, sr->sr_flags, + sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, + sr->sr_nssid, /* NB: cheat, we assume structures are compatible */ - (const struct ieee80211_scan_ssid *) &sr.sr_ssid[0]); + (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]); } else { - (void) ieee80211_start_scan(vap, sr.sr_flags, - sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, - sr.sr_nssid, + error = ieee80211_start_scan(vap, sr->sr_flags, + sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, + sr->sr_nssid, /* NB: cheat, we assume structures are compatible */ - (const struct ieee80211_scan_ssid *) &sr.sr_ssid[0]); + (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]); } + if (error == 0) + return EINPROGRESS; } - return error; + return 0; #undef IEEE80211_IOC_SCAN_FLAGS } +static __noinline int +ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_req sr; /* XXX off stack? */ + int error; + + /* NB: parent must be running */ + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return ENXIO; + + if (ireq->i_len != sizeof(sr)) + return EINVAL; + error = copyin(ireq->i_data, &sr, sizeof(sr)); + if (error != 0) + return error; + return ieee80211_scanreq(vap, &sr); +} + static __noinline int ieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq) { diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.h index b4dc8675a1..f1a1dcd69a 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.h @@ -582,7 +582,7 @@ struct ieee80211req { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ uint16_t i_type; /* req type */ int16_t i_val; /* Index or simple value */ - int16_t i_len; /* Index or simple value */ + uint16_t i_len; /* Index or simple value */ void *i_data; /* Extra data */ }; #define SIOCS80211 _IOW('i', 234, struct ieee80211req) @@ -798,7 +798,7 @@ struct ieee80211req_scan_result { #endif int8_t isr_noise; int8_t isr_rssi; - uint8_t isr_intval; /* beacon interval */ + uint16_t isr_intval; /* beacon interval */ uint8_t isr_capinfo; /* capabilities */ uint8_t isr_erp; /* ERP element */ uint8_t isr_bssid[IEEE80211_ADDR_LEN]; diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.c index d42d55db72..571a733539 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.c @@ -82,6 +82,7 @@ static void mesh_forward(struct ieee80211vap *, struct mbuf *, static int mesh_input(struct ieee80211_node *, struct mbuf *, int, int); static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, int, int); +static void mesh_recv_ctl(struct ieee80211_node *, struct mbuf *, int); static void mesh_peer_timeout_setup(struct ieee80211_node *); static void mesh_peer_timeout_backoff(struct ieee80211_node *); static void mesh_peer_timeout_cb(void *); @@ -520,6 +521,7 @@ mesh_vattach(struct ieee80211vap *vap) vap->iv_input = mesh_input; vap->iv_opdetach = mesh_vdetach; vap->iv_recv_mgmt = mesh_recv_mgmt; + vap->iv_recv_ctl = mesh_recv_ctl; ms = malloc(sizeof(struct ieee80211_mesh_state), M_80211_VAP, M_NOWAIT | M_ZERO); if (ms == NULL) { @@ -1038,7 +1040,6 @@ mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh, static int mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -1092,9 +1093,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr1, "duplicate", @@ -1461,18 +1460,19 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, meshid = frm; break; } - frm += frm[2] + 2; + frm += frm[1] + 2; } IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, return); IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return); if (xrates != NULL) IEEE80211_VERIFY_ELEMENT(xrates, IEEE80211_RATE_MAXSIZE - rates[1], return); - if (meshid != NULL) + if (meshid != NULL) { IEEE80211_VERIFY_ELEMENT(meshid, IEEE80211_MESHID_LEN, return); - /* NB: meshid, not ssid */ - IEEE80211_VERIFY_SSID(vap->iv_bss, meshid, return); + /* NB: meshid, not ssid */ + IEEE80211_VERIFY_SSID(vap->iv_bss, meshid, return); + } /* XXX find a better class or define it's own */ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2, @@ -1486,46 +1486,42 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, ieee80211_send_proberesp(vap, wh->i_addr2, 0); break; } + case IEEE80211_FC0_SUBTYPE_ACTION: - if (vap->iv_state != IEEE80211_S_RUN) { - vap->iv_stats.is_rx_mgtdiscard++; - break; - } - /* - * We received an action for an unknown neighbor. - * XXX: wait for it to beacon or create ieee80211_node? - */ + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: if (ni == vap->iv_bss) { - IEEE80211_DISCARD(vap, IEEE80211_MSG_MESH, + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "unknown node"); vap->iv_stats.is_rx_mgtdiscard++; - break; - } - /* - * Discard if not for us. - */ - if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { - IEEE80211_DISCARD(vap, IEEE80211_MSG_MESH, - wh, NULL, "%s", "not for me"); + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); vap->iv_stats.is_rx_mgtdiscard++; - break; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); } - /* XXX parse_action is a bit useless now */ - if (ieee80211_parse_action(ni, m0) == 0) - ic->ic_recv_action(ni, wh, frm, efrm); break; - case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: - case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ATIM: case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; - return; + break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "mgt", "subtype 0x%x not handled", subtype); @@ -1534,6 +1530,17 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, } } +static void +mesh_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) +{ + + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; + } +} + /* * Parse meshpeering action ie's for open+confirm frames; the * important bits are returned in the supplied structure. @@ -2283,6 +2290,7 @@ mesh_verify_meshconf(struct ieee80211vap *vap, const uint8_t *ie) const struct ieee80211_meshconf_ie *meshconf = (const struct ieee80211_meshconf_ie *) ie; const struct ieee80211_mesh_state *ms = vap->iv_mesh; + uint16_t cap; if (meshconf == NULL) return 1; @@ -2316,8 +2324,10 @@ mesh_verify_meshconf(struct ieee80211vap *vap, const uint8_t *ie) meshconf->conf_pselid); return 1; } + /* NB: conf_cap is only read correctly here */ + cap = LE_READ_2(&meshconf->conf_cap); /* Not accepting peers */ - if (!(meshconf->conf_cap & IEEE80211_MESHCONF_CAP_AP)) { + if (!(cap & IEEE80211_MESHCONF_CAP_AP)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH, "not accepting peers: 0x%x\n", meshconf->conf_cap); return 1; @@ -2381,6 +2391,7 @@ uint8_t * ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap) { const struct ieee80211_mesh_state *ms = vap->iv_mesh; + uint16_t caps; KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap")); @@ -2396,11 +2407,12 @@ ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap) if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) *frm |= IEEE80211_MESHCONF_FORM_MP; frm += 1; + caps = 0; if (ms->ms_flags & IEEE80211_MESHFLAGS_AP) - *frm |= IEEE80211_MESHCONF_CAP_AP; + caps |= IEEE80211_MESHCONF_CAP_AP; if (ms->ms_flags & IEEE80211_MESHFLAGS_FWD) - *frm |= IEEE80211_MESHCONF_CAP_FWRD; - frm += 1; + caps |= IEEE80211_MESHCONF_CAP_FWRD; + ADDSHORT(frm, caps); return frm; } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.h index 5a9d148977..a748be32f8 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_mesh.h @@ -49,7 +49,7 @@ struct ieee80211_meshconf_ie { uint8_t conf_syncid; /* Sync. Protocol ID */ uint8_t conf_authid; /* Auth. Protocol ID */ uint8_t conf_form; /* Formation Information */ - uint8_t conf_cap; + uint16_t conf_cap; } __packed; /* Hybrid Wireless Mesh Protocol */ @@ -72,7 +72,8 @@ struct ieee80211_meshconf_ie { #define IEEE80211_MESHCONF_CAP_FWRD 0x08 /* forwarding enabled */ #define IEEE80211_MESHCONF_CAP_BTR 0x10 /* Beacon Timing Report Enab */ #define IEEE80211_MESHCONF_CAP_TBTTA 0x20 /* TBTT Adj. Enabled */ -#define IEEE80211_MESHCONF_CAP_PSL 0x40 /* Power Save Level */ +#define IEEE80211_MESHCONF_CAP_TBTT 0x40 /* TBTT Adjusting */ +#define IEEE80211_MESHCONF_CAP_PSL 0x80 /* Power Save Level */ /* Mesh Identifier */ struct ieee80211_meshid_ie { diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.c index 514e666529..1cbff9618b 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.c @@ -282,10 +282,7 @@ ieee80211_node_set_chan(struct ieee80211_node *ni, mode = ieee80211_chan2mode(chan); if (IEEE80211_IS_CHAN_HT(chan)) { /* - * XXX Gotta be careful here; the rate set returned by - * ieee80211_get_suprates is actually any HT rate - * set so blindly copying it will be bad. We must - * install the legacy rate est in ni_rates and the + * We must install the legacy rate est in ni_rates and the * HT rate set in ni_htrates. */ ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); @@ -1085,7 +1082,26 @@ static void node_getmimoinfo(const struct ieee80211_node *ni, struct ieee80211_mimo_info *info) { - /* XXX zero data? */ + int i; + uint32_t avgrssi; + int32_t rssi; + + bzero(info, sizeof(*info)); + + for (i = 0; i < ni->ni_mimo_chains; i++) { + avgrssi = ni->ni_mimo_rssi_ctl[i]; + if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) { + info->rssi[i] = 0; + } else { + rssi = IEEE80211_RSSI_GET(avgrssi); + info->rssi[i] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; + } + info->noise[i] = ni->ni_mimo_noise_ctl[i]; + } + + /* XXX ext radios? */ + + /* XXX EVM? */ } struct ieee80211_node * diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.h index 8fae8d6104..68167a0e05 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_node.h @@ -166,6 +166,13 @@ struct ieee80211_node { uint32_t ni_avgrssi; /* recv ssi state */ int8_t ni_noise; /* noise floor */ + /* mimo statistics */ + uint32_t ni_mimo_rssi_ctl[IEEE80211_MAX_CHAINS]; + uint32_t ni_mimo_rssi_ext[IEEE80211_MAX_CHAINS]; + uint8_t ni_mimo_noise_ctl[IEEE80211_MAX_CHAINS]; + uint8_t ni_mimo_noise_ext[IEEE80211_MAX_CHAINS]; + uint8_t ni_mimo_chains; + /* header */ uint8_t ni_macaddr[IEEE80211_ADDR_LEN]; uint8_t ni_bssid[IEEE80211_ADDR_LEN]; diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_output.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_output.c index 874ceb8bb8..bcd3c2bdac 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_output.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_output.c @@ -57,8 +57,11 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef INET +#if defined(INET) || defined(INET6) #include +#endif + +#ifdef INET #include #include #include @@ -67,6 +70,8 @@ __FBSDID("$FreeBSD$"); #include #endif +#include + #define ETHER_HEADER_COPY(dst, src) \ memcpy(dst, src, sizeof(struct ether_header)) @@ -396,14 +401,101 @@ ieee80211_output(struct ifnet *ifp, struct mbuf *m, senderr(ENETDOWN); } vap = ifp->if_softc; + /* + * Hand to the 802.3 code if not tagged as + * a raw 802.11 frame. + */ + if (dst->sa_family != AF_IEEE80211) + return vap->iv_output(ifp, m, dst, ro); +#ifdef MAC + error = mac_ifnet_check_transmit(ifp, m); + if (error) + senderr(error); +#endif + if (ifp->if_flags & IFF_MONITOR) + senderr(ENETDOWN); + if (!IFNET_IS_UP_RUNNING(ifp)) + senderr(ENETDOWN); + if (vap->iv_state == IEEE80211_S_CAC) { + IEEE80211_DPRINTF(vap, + IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, + "block %s frame in CAC state\n", "raw data"); + vap->iv_stats.is_tx_badstate++; + senderr(EIO); /* XXX */ + } else if (vap->iv_state == IEEE80211_S_SCAN) + senderr(EIO); + /* XXX bypass bridge, pfil, carp, etc. */ - return vap->iv_output(ifp, m, dst, ro); + if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) + senderr(EIO); /* XXX */ + wh = mtod(m, struct ieee80211_frame *); + if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != + IEEE80211_FC0_VERSION_0) + senderr(EIO); /* XXX */ + /* locate destination node */ + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + case IEEE80211_FC1_DIR_FROMDS: + ni = ieee80211_find_txnode(vap, wh->i_addr1); + break; + case IEEE80211_FC1_DIR_TODS: + case IEEE80211_FC1_DIR_DSTODS: + if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) + senderr(EIO); /* XXX */ + ni = ieee80211_find_txnode(vap, wh->i_addr3); + break; + default: + senderr(EIO); /* XXX */ + } + if (ni == NULL) { + /* + * Permit packets w/ bpf params through regardless + * (see below about sa_len). + */ + if (dst->sa_len == 0) + senderr(EHOSTUNREACH); + ni = ieee80211_ref_node(vap->iv_bss); + } + + /* + * Sanitize mbuf for net80211 flags leaked from above. + * + * NB: This must be done before ieee80211_classify as + * it marks EAPOL in frames with M_EAPOL. + */ + m->m_flags &= ~M_80211_TX; + + /* calculate priority so drivers can find the tx queue */ + /* XXX assumes an 802.3 frame */ + if (ieee80211_classify(ni, m)) + senderr(EIO); /* XXX */ + + ifp->if_opackets++; + IEEE80211_NODE_STAT(ni, tx_data); + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_NODE_STAT(ni, tx_mcast); + m->m_flags |= M_MCAST; + } else + IEEE80211_NODE_STAT(ni, tx_ucast); + /* NB: ieee80211_encap does not include 802.11 header */ + IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); + + /* + * NB: DLT_IEEE802_11_RADIO identifies the parameters are + * present by setting the sa_len field of the sockaddr (yes, + * this is a hack). + * NB: we assume sa_data is suitably aligned to cast. + */ + return vap->iv_ic->ic_raw_xmit(ni, m, + (const struct ieee80211_bpf_params *)(dst->sa_len ? + dst->sa_data : NULL)); bad: if (m != NULL) m_freem(m); + if (ni != NULL) + ieee80211_free_node(ni); ifp->if_oerrors++; - return error; #undef senderr } @@ -424,6 +516,7 @@ ieee80211_send_setup( { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_tx_ampdu *tap; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); ieee80211_seq seqno; @@ -491,9 +584,15 @@ ieee80211_send_setup( } *(uint16_t *)&wh->i_dur[0] = 0; - seqno = ni->ni_txseqs[tid]++; - *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); - M_SEQNO_SET(m, seqno); + tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)]; + if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) + m->m_flags |= M_AMPDU_MPDU; + else { + seqno = ni->ni_txseqs[tid]++; + *(uint16_t *)&wh->i_seq[0] = + htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + M_SEQNO_SET(m, seqno); + } if (IEEE80211_IS_MULTICAST(wh->i_addr1)) m->m_flags |= M_MCAST; @@ -2693,6 +2792,8 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct ieee80211com *ic = ni->ni_ic; int len_changed = 0; uint16_t capinfo; + struct ieee80211_frame *wh; + ieee80211_seq seqno; IEEE80211_LOCK(ic); /* @@ -2724,6 +2825,12 @@ ieee80211_beacon_update(struct ieee80211_node *ni, return 1; /* just assume length changed */ } + wh = mtod(m, struct ieee80211_frame *); + seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; + *(uint16_t *)&wh->i_seq[0] = + htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + M_SEQNO_SET(m, seqno); + /* XXX faster to recalculate entirely or just changes? */ capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); *bo->bo_caps = htole16(capinfo); @@ -2834,13 +2941,13 @@ ieee80211_beacon_update(struct ieee80211_node *ni, bo->bo_tim_trailer += adjust; bo->bo_erp += adjust; bo->bo_htinfo += adjust; -#ifdef IEEE80211_SUPERG_SUPPORT +#ifdef IEEE80211_SUPPORT_SUPERG bo->bo_ath += adjust; #endif -#ifdef IEEE80211_TDMA_SUPPORT +#ifdef IEEE80211_SUPPORT_TDMA bo->bo_tdma += adjust; #endif -#ifdef IEEE80211_MESH_SUPPORT +#ifdef IEEE80211_SUPPORT_MESH bo->bo_meshconf += adjust; #endif bo->bo_appie += adjust; @@ -2888,13 +2995,13 @@ ieee80211_beacon_update(struct ieee80211_node *ni, bo->bo_erp += sizeof(*csa); bo->bo_htinfo += sizeof(*csa); bo->bo_wme += sizeof(*csa); -#ifdef IEEE80211_SUPERG_SUPPORT +#ifdef IEEE80211_SUPPORT_SUPERG bo->bo_ath += sizeof(*csa); #endif -#ifdef IEEE80211_TDMA_SUPPORT +#ifdef IEEE80211_SUPPORT_TDMA bo->bo_tdma += sizeof(*csa); #endif -#ifdef IEEE80211_MESH_SUPPORT +#ifdef IEEE80211_SUPPORT_MESH bo->bo_meshconf += sizeof(*csa); #endif bo->bo_appie += sizeof(*csa); diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_power.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_power.c index 89f93cf0ca..2b68f9022f 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_power.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_power.c @@ -100,7 +100,7 @@ ieee80211_power_vdetach(struct ieee80211vap *vap) void ieee80211_psq_init(struct ieee80211_psq *psq, const char *name) { - memset(psq, 0, sizeof(psq)); + memset(psq, 0, sizeof(*psq)); psq->psq_maxlen = IEEE80211_PS_MAX_QUEUE; IEEE80211_PSQ_INIT(psq, name); /* OS-dependent setup */ } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.c index fa6b1684fe..f44c594111 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.c @@ -64,7 +64,7 @@ const char *ieee80211_mgt_subtype_name[] = { "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", "probe_req", "probe_resp", "reserved#6", "reserved#7", "beacon", "atim", "disassoc", "auth", - "deauth", "action", "reserved#14", "reserved#15" + "deauth", "action", "action_noack", "reserved#15" }; const char *ieee80211_ctl_subtype_name[] = { "reserved#0", "reserved#1", "reserved#2", "reserved#3", @@ -207,6 +207,21 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) const struct ieee80211_rateset *rs = &ic->ic_sup_rates[i]; vap->iv_txparms[i].ucastrate = IEEE80211_FIXED_RATE_NONE; + + /* + * Setting the management rate to MCS 0 assumes that the + * BSS Basic rate set is empty and the BSS Basic MCS set + * is not. + * + * Since we're not checking this, default to the lowest + * defined rate for this mode. + * + * At least one 11n AP (DLINK DIR-825) is reported to drop + * some MCS management traffic (eg BA response frames.) + * + * See also: 9.6.0 of the 802.11n-2009 specification. + */ +#ifdef NOTYET if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) { vap->iv_txparms[i].mgmtrate = 0 | IEEE80211_RATE_MCS; vap->iv_txparms[i].mcastrate = 0 | IEEE80211_RATE_MCS; @@ -216,6 +231,9 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; } +#endif + vap->iv_txparms[i].mgmtrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; + vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT; } vap->iv_roaming = IEEE80211_ROAMING_AUTO; @@ -877,6 +895,15 @@ ieee80211_wme_initparams_locked(struct ieee80211vap *vap) if ((ic->ic_caps & IEEE80211_C_WME) == 0 || ic->ic_nrunning > 1) return; + /* + * Clear the wme cap_info field so a qoscount from a previous + * vap doesn't confuse later code which only parses the beacon + * field and updates hardware when said field changes. + * Otherwise the hardware is programmed with defaults, not what + * the beacon actually announces. + */ + wme->wme_wmeChanParams.cap_info = 0; + /* * Select mode; we can be called early in which case we * always use auto mode. We know we'll be called when @@ -1474,6 +1501,11 @@ ieee80211_csa_startswitch(struct ieee80211com *ic, ieee80211_notify_csa(ic, c, mode, count); } +/* + * Complete the channel switch by transitioning all CSA VAPs to RUN. + * This is called by both the completion and cancellation functions + * so each VAP is placed back in the RUN state and can thus transmit. + */ static void csa_completeswitch(struct ieee80211com *ic) { @@ -1491,15 +1523,27 @@ csa_completeswitch(struct ieee80211com *ic) * Complete an 802.11h channel switch started by ieee80211_csa_startswitch. * We clear state and move all vap's in CSA state to RUN state * so they can again transmit. + * + * Although this may not be completely correct, update the BSS channel + * for each VAP to the newly configured channel. The setcurchan sets + * the current operating channel for the interface (so the radio does + * switch over) but the VAP BSS isn't updated, leading to incorrectly + * reported information via ioctl. */ void ieee80211_csa_completeswitch(struct ieee80211com *ic) { + struct ieee80211vap *vap; + IEEE80211_LOCK_ASSERT(ic); KASSERT(ic->ic_flags & IEEE80211_F_CSAPENDING, ("csa not pending")); ieee80211_setcurchan(ic, ic->ic_csa_newchan); + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_state == IEEE80211_S_CSA) + vap->iv_bss->ni_chan = ic->ic_curchan; + csa_completeswitch(ic); } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.h index 56544f98d5..2b325576ef 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_proto.h @@ -63,9 +63,36 @@ void ieee80211_syncflag(struct ieee80211vap *, int flag); void ieee80211_syncflag_ht(struct ieee80211vap *, int flag); void ieee80211_syncflag_ext(struct ieee80211vap *, int flag); +#define IEEE80211_R_NF 0x0000001 /* global NF value valid */ +#define IEEE80211_R_RSSI 0x0000002 /* global RSSI value valid */ +#define IEEE80211_R_C_CHAIN 0x0000004 /* RX chain count valid */ +#define IEEE80211_R_C_NF 0x0000008 /* per-chain NF value valid */ +#define IEEE80211_R_C_RSSI 0x0000010 /* per-chain RSSI value valid */ +#define IEEE80211_R_C_EVM 0x0000020 /* per-chain EVM valid */ +#define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */ + +struct ieee80211_rx_stats { + uint32_t r_flags; /* IEEE80211_R_* flags */ + uint8_t c_chain; /* number of RX chains involved */ + int16_t c_nf_ctl[IEEE80211_MAX_CHAINS]; /* per-chain NF */ + int16_t c_nf_ext[IEEE80211_MAX_CHAINS]; /* per-chain NF */ + int16_t c_rssi_ctl[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ + int16_t c_rssi_ext[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ + uint8_t nf; /* global NF */ + uint8_t rssi; /* global RSSI */ + uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS]; + /* per-chain, per-pilot EVM values */ +}; + #define ieee80211_input(ni, m, rssi, nf) \ ((ni)->ni_vap->iv_input(ni, m, rssi, nf)) int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int); + +int ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *, + struct ieee80211_rx_stats *); +int ieee80211_input_mimo_all(struct ieee80211com *, struct mbuf *, + struct ieee80211_rx_stats *); + struct ieee80211_bpf_params; int ieee80211_mgmt_output(struct ieee80211_node *, struct mbuf *, int, struct ieee80211_bpf_params *); diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan.c index db2802a399..68a0ea4542 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan.c @@ -424,6 +424,8 @@ start_scan_locked(const struct ieee80211_scanner *scan, vap->iv_stats.is_scan_passive++; if (flags & IEEE80211_SCAN_FLUSH) ss->ss_ops->scan_flush(ss); + if (flags & IEEE80211_SCAN_BGSCAN) + ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; /* NB: flush frames rx'd before 1st channel change */ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; @@ -440,12 +442,13 @@ start_scan_locked(const struct ieee80211_scanner *scan, ic->ic_flags |= IEEE80211_F_SCAN; ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); } + return 1; } else { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: %s scan already in progress\n", __func__, ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"); } - return (ic->ic_flags & IEEE80211_F_SCAN); + return 0; } /* diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan_sta.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan_sta.c index 3c1ed811d6..11bd3f56c0 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan_sta.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_scan_sta.c @@ -238,6 +238,7 @@ sta_add(struct ieee80211_scan_state *ss, const uint8_t *macaddr = wh->i_addr2; struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_channel *c; struct sta_entry *se; struct ieee80211_scan_entry *ise; int hash; @@ -300,7 +301,6 @@ found: * association on the wrong channel. */ if (sp->status & IEEE80211_BPARSE_OFFCHAN) { - struct ieee80211_channel *c; /* * Off-channel, locate the home/bss channel for the sta * using the value broadcast in the DSPARMS ie. We know @@ -317,6 +317,14 @@ found: } } else ise->se_chan = ic->ic_curchan; + if (IEEE80211_IS_CHAN_HT(ise->se_chan) && sp->htcap == NULL) { + /* Demote legacy networks to a non-HT channel. */ + c = ieee80211_find_channel(ic, ise->se_chan->ic_freq, + ise->se_chan->ic_flags & ~IEEE80211_CHAN_HT); + KASSERT(c != NULL, + ("no legacy channel %u", ise->se_chan->ic_ieee)); + ise->se_chan = c; + } ise->se_fhdwell = sp->fhdwell; ise->se_fhindex = sp->fhindex; ise->se_erp = sp->erp; @@ -756,26 +764,38 @@ maxrate(const struct ieee80211_scan_entry *se) { const struct ieee80211_ie_htcap *htcap = (const struct ieee80211_ie_htcap *) se->se_ies.htcap_ie; - int rmax, r, i; + int rmax, r, i, txstream; uint16_t caps; + uint8_t txparams; rmax = 0; if (htcap != NULL) { /* * HT station; inspect supported MCS and then adjust - * rate by channel width. Could also include short GI - * in this if we want to be extra accurate. + * rate by channel width. */ - /* XXX assumes MCS15 is max */ - for (i = 15; i >= 0 && isclr(htcap->hc_mcsset, i); i--) - ; + txparams = htcap->hc_mcsset[12]; + if (txparams & 0x3) { + /* + * TX MCS parameters defined and not equal to RX, + * extract the number of spartial streams and + * map it to the highest MCS rate. + */ + txstream = ((txparams & 0xc) >> 2) + 1; + i = txstream * 8 - 1; + } else + for (i = 31; i >= 0 && isclr(htcap->hc_mcsset, i); i--); if (i >= 0) { caps = LE_READ_2(&htcap->hc_cap); - /* XXX short/long GI */ - if (caps & IEEE80211_HTCAP_CHWIDTH40) + if ((caps & IEEE80211_HTCAP_CHWIDTH40) && + (caps & IEEE80211_HTCAP_SHORTGI40)) rmax = ieee80211_htrates[i].ht40_rate_400ns; - else + else if (caps & IEEE80211_HTCAP_CHWIDTH40) rmax = ieee80211_htrates[i].ht40_rate_800ns; + else if (caps & IEEE80211_HTCAP_SHORTGI20) + rmax = ieee80211_htrates[i].ht20_rate_400ns; + else + rmax = ieee80211_htrates[i].ht20_rate_800ns; } } for (i = 0; i < se->se_rates[1]; i++) { diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_sta.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_sta.c index f377d86e6d..5444459a15 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_sta.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_sta.c @@ -434,7 +434,7 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) goto invalid; break; case IEEE80211_S_SLEEP: - ieee80211_sta_pwrsave(vap, 0); + ieee80211_sta_pwrsave(vap, 1); break; default: invalid: @@ -512,7 +512,6 @@ doprint(struct ieee80211vap *vap, int subtype) static int sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -591,9 +590,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", @@ -910,7 +907,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static void @@ -1544,7 +1540,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, htcap = frm; } else if (ishtinfooui(frm)) { if (htinfo == NULL) - htcap = frm; + htinfo = frm; } } /* XXX Atheros OUI support */ @@ -1718,21 +1714,35 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, } case IEEE80211_FC0_SUBTYPE_ACTION: - if (vap->iv_state == IEEE80211_S_RUN) { - if (ieee80211_parse_action(ni, m0) == 0) - ic->ic_recv_action(ni, wh, frm, efrm); - } else + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); + } break; - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + case IEEE80211_FC0_SUBTYPE_ATIM: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; - return; + break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } @@ -1741,6 +1751,11 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, } static void -sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype) +sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; + } } diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h index 6848e0524b..93db5b313e 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h @@ -140,6 +140,7 @@ struct ieee80211com { uint32_t ic_flags_ven; /* vendor state flags */ uint32_t ic_caps; /* capabilities */ uint32_t ic_htcaps; /* HT capabilities */ + uint32_t ic_htextcaps; /* HT extended capabilities */ uint32_t ic_cryptocaps; /* crypto capabilities */ uint8_t ic_modecaps[2]; /* set of mode capabilities */ uint8_t ic_promisc; /* vap's needing promisc mode */ @@ -192,8 +193,8 @@ struct ieee80211com { struct ieee80211_dfs_state ic_dfs; /* DFS state */ struct ieee80211_scan_state *ic_scan; /* scan state */ - long long ic_lastdata; /* time of last data frame */ - long long ic_lastscan; /* time last scan completed */ + int ic_lastdata; /* time of last data frame */ + int ic_lastscan; /* time last scan completed */ /* NB: this is the union of all vap stations/neighbors */ int ic_max_keyix; /* max h/w key index */ @@ -213,8 +214,10 @@ struct ieee80211com { uint16_t ic_ht40_sta_assoc;/* HT40 stations associated */ uint8_t ic_curhtprotmode;/* HTINFO bss state */ enum ieee80211_protmode ic_htprotmode; /* HT protection mode */ - long long ic_lastnonerp; /* last time non-ERP sta noted*/ - long long ic_lastnonht; /* last time non-HT sta noted */ + int ic_lastnonerp; /* last time non-ERP sta noted*/ + int ic_lastnonht; /* last time non-HT sta noted */ + uint8_t ic_rxstream; /* # RX streams */ + uint8_t ic_txstream; /* # TX streams */ /* optional state for Atheros SuperG protocol extensions */ struct ieee80211_superg *ic_superg; @@ -307,6 +310,8 @@ struct ieee80211com { int status, int baparamset, int batimeout); void (*ic_addba_stop)(struct ieee80211_node *, struct ieee80211_tx_ampdu *); + void (*ic_addba_response_timeout)(struct ieee80211_node *, + struct ieee80211_tx_ampdu *); /* BAR response received */ void (*ic_bar_response)(struct ieee80211_node *, struct ieee80211_tx_ampdu *, int status); @@ -316,7 +321,7 @@ struct ieee80211com { int batimeout, int baseqctl); void (*ic_ampdu_rx_stop)(struct ieee80211_node *, struct ieee80211_rx_ampdu *); - uint64_t ic_spare[8]; + uint64_t ic_spare[7]; }; struct ieee80211_aclator; @@ -343,6 +348,7 @@ struct ieee80211vap { uint32_t iv_flags_ven; /* vendor state flags */ uint32_t iv_caps; /* capabilities */ uint32_t iv_htcaps; /* HT capabilities */ + uint32_t iv_htextcaps; /* HT extended capabilities */ enum ieee80211_opmode iv_opmode; /* operation mode */ enum ieee80211_state iv_state; /* state machine state */ enum ieee80211_state iv_nstate; /* pending state */ @@ -576,7 +582,7 @@ struct ieee80211vap { #define IEEE80211_FHT_BITS \ "\20\1NONHT_PR" \ - "\23GF\24HT\25AMDPU_TX\26AMPDU_TX" \ + "\23GF\24HT\25AMPDU_TX\26AMPDU_TX" \ "\27AMSDU_TX\30AMSDU_RX\31USEHT40\32PUREN\33SHORTGI20\34SHORTGI40" \ "\35HTCOMPAT\36RIFS\37STBC_TX\40STBC_RX" @@ -635,6 +641,10 @@ struct ieee80211vap { #define IEEE80211_HTC_HT 0x00040000 /* CAPABILITY: HT operation */ #define IEEE80211_HTC_SMPS 0x00080000 /* CAPABILITY: MIMO power save*/ #define IEEE80211_HTC_RIFS 0x00100000 /* CAPABILITY: RIFS support */ +#define IEEE80211_HTC_RXUNEQUAL 0x00200000 /* CAPABILITY: RX unequal MCS */ +#define IEEE80211_HTC_RXMCS32 0x00400000 /* CAPABILITY: MCS32 support */ +#define IEEE80211_HTC_TXUNEQUAL 0x00800000 /* CAPABILITY: TX unequal MCS */ +#define IEEE80211_HTC_TXMCS32 0x01000000 /* CAPABILITY: MCS32 suport */ #define IEEE80211_C_HTCAP_BITS \ "\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \ diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_wds.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_wds.c index 15518d8181..ed82fac1c0 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_wds.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_wds.c @@ -406,7 +406,6 @@ wds_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) static int wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -454,6 +453,9 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) */ wh = mtod(m, struct ieee80211_frame *); + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) + ni->ni_inact = ni->ni_inact_reload; + if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, @@ -492,9 +494,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr1, "duplicate", @@ -536,8 +536,6 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) vap->iv_stats.is_rx_wrongdir++;/*XXX*/ goto out; } - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) - ni->ni_inact = ni->ni_inact_reload; /* * Handle A-MPDU re-ordering. If the frame is to be * processed directly then ieee80211_ampdu_reorder @@ -740,7 +738,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static void @@ -756,31 +753,47 @@ wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, frm = (u_int8_t *)&wh[1]; efrm = mtod(m0, u_int8_t *) + m0->m_len; switch (subtype) { - case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ACTION: + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (ni == vap->iv_bss) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "unknown node"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1)) { + /* NB: not interested in multicast frames. */ + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); + } + break; + + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: case IEEE80211_FC0_SUBTYPE_PROBE_RESP: case IEEE80211_FC0_SUBTYPE_BEACON: - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: - case IEEE80211_FC0_SUBTYPE_AUTH: - case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: - case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_ATIM: case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; break; - case IEEE80211_FC0_SUBTYPE_ACTION: - if (vap->iv_state != IEEE80211_S_RUN || - IEEE80211_IS_MULTICAST(wh->i_addr1)) { - vap->iv_stats.is_rx_mgtdiscard++; - break; - } - ni->ni_inact = ni->ni_inact_reload; - if (ieee80211_parse_action(ni, m0) == 0) - ic->ic_recv_action(ni, wh, frm, efrm); - break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; }