Date: Wed, 20 Feb 2008 13:02:31 GMT From: Sepherosa Ziehau <sephe@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 135785 for review Message-ID: <200802201302.m1KD2VrK043767@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=135785 Change 135785 by sephe@sephe_zealot:sam_wifi on 2008/02/20 13:01:38 Add raw_xmit support. Submitted by: sam Affected files ... .. //depot/projects/wifi/sys/dev/bwi/if_bwi.c#23 edit Differences ... ==== //depot/projects/wifi/sys/dev/bwi/if_bwi.c#23 (text+ko) ==== @@ -97,6 +97,8 @@ static int bwi_ioctl(struct ifnet *, u_long, caddr_t); 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_scan_start(struct ieee80211com *); static void bwi_set_channel(struct ieee80211com *); @@ -123,6 +125,9 @@ static int bwi_newbuf(struct bwi_softc *, int, int); static int bwi_encap(struct bwi_softc *, int, struct mbuf *, struct ieee80211_node *); +static int bwi_encap_raw(struct bwi_softc *, int, struct mbuf *, + struct ieee80211_node *, + const struct ieee80211_bpf_params *); static void bwi_init_rxdesc_ring32(struct bwi_softc *, uint32_t, bus_addr_t, int, int); @@ -541,6 +546,7 @@ ic->ic_set_channel = bwi_set_channel; ic->ic_node_alloc = bwi_node_alloc; ic->ic_newassoc = bwi_newassoc; + ic->ic_raw_xmit = bwi_raw_xmit; /* complete initialization */ ieee80211_media_init(ic, bwi_media_change, ieee80211_media_status); ieee80211_amrr_init(&sc->sc_amrr, ic, @@ -1442,6 +1448,55 @@ ifp->if_timer = 5; } +static int +bwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct bwi_softc *sc = ifp->if_softc; + /* XXX wme? */ + struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; + int idx, error; + + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ieee80211_free_node(ni); + m_freem(m); + return ENETDOWN; + } + + BWI_LOCK(sc); + idx = tbd->tbd_idx; + KASSERT(tbd->tbd_buf[idx].tb_mbuf == NULL, ("slot %d not empty", idx)); + if (params == NULL) { + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + */ + error = bwi_encap(sc, idx, m, ni); + } else { + /* + * Caller supplied explicit parameters to use in + * sending the frame. + */ + error = bwi_encap_raw(sc, idx, m, ni, params); + } + if (error == 0) { + ifp->if_opackets++; + 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; + } else { + /* NB: m is reclaimed on encap failure */ + ieee80211_free_node(ni); + ifp->if_oerrors++; + } + BWI_UNLOCK(sc); + return error; +} + static void bwi_watchdog(struct ifnet *ifp) { @@ -3166,6 +3221,162 @@ return error; } +static int +bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, + struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; + struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; + struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; + struct bwi_mac *mac; + struct bwi_txbuf_hdr *hdr; + struct ieee80211_frame *wh; + uint8_t rate, rate_fb; + uint32_t mac_ctrl; + uint16_t phy_ctrl; + bus_addr_t paddr; + int ismcast, pkt_len, error; + + KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, + ("current regwin type %d", sc->sc_cur_regwin->rw_type)); + mac = (struct bwi_mac *)sc->sc_cur_regwin; + + wh = mtod(m, struct ieee80211_frame *); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + /* Get 802.11 frame len before prepending TX header */ + pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN; + + /* + * Find TX rate + */ + bzero(tb->tb_rate_idx, sizeof(tb->tb_rate_idx)); + rate = params->ibp_rate0; + rate_fb = (params->ibp_try1 != 0) ? + params->ibp_rate1 : params->ibp_rate0; + tb->tb_rate_idx[0] = rate; + tb->tb_rate_idx[1] = rate_fb; + sc->sc_tx_rate = rate; + + /* + * TX radio tap + */ + if (bpf_peers_present(sc->sc_drvbpf)) { + sc->sc_tx_th.wt_flags = 0; + /* XXX IEEE80211_BPF_CRYPTO */ + if (wh->i_fc[1] & IEEE80211_FC1_WEP) + sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; + if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) + sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + sc->sc_tx_th.wt_rate = rate; + + bpf_mtap2(sc->sc_drvbpf, &sc->sc_tx_th, sc->sc_tx_th_len, m); + } + + /* + * Setup the embedded TX header + */ + M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); + if (m == NULL) { + if_printf(ic->ic_ifp, "prepend TX header failed\n"); + return ENOBUFS; + } + hdr = mtod(m, struct bwi_txbuf_hdr *); + + bzero(hdr, sizeof(*hdr)); + + bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); + bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); + + mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG; + if (!ismcast && (params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { + uint16_t dur; + uint8_t ack_rate; + + /* XXX rate_fb? */ + ack_rate = ieee80211_ack_rate(ni, rate_fb); + dur = ieee80211_txtime(ni, + sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN, + ack_rate, 0); + + hdr->txh_fb_duration = htole16(dur); + mac_ctrl |= BWI_TXH_MAC_C_ACK; + } + + hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | + __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK); + + bwi_plcp_header(hdr->txh_plcp, pkt_len, rate); + bwi_plcp_header(hdr->txh_fb_plcp, pkt_len, rate_fb); + + phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, + BWI_TXH_PHY_C_ANTMODE_MASK); + if (ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) { + phy_ctrl |= BWI_TXH_PHY_C_OFDM; + mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; + } else if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) + phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE; + + hdr->txh_mac_ctrl = htole32(mac_ctrl); + hdr->txh_phy_ctrl = htole16(phy_ctrl); + + /* Catch any further usage */ + hdr = NULL; + wh = NULL; + + /* DMA load */ + error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, + bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); + if (error != 0) { + struct mbuf *m_new; + + if (error != EFBIG) { + if_printf(ic->ic_ifp, + "%s: can't load TX buffer (1) %d\n", + __func__, error); + goto back; + } + m_new = m_defrag(m, M_DONTWAIT); + if (m_new == NULL) { + if_printf(ic->ic_ifp, "%s: can't defrag TX buffer\n", + __func__); + error = ENOBUFS; + goto back; + } + m = m_new; + error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, + bwi_dma_buf_addr, &paddr, + BUS_DMA_NOWAIT); + if (error) { + if_printf(ic->ic_ifp, + "%s: can't load TX buffer (2) %d\n", + __func__, error); + goto back; + } + } + + bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); + + tb->tb_mbuf = m; + tb->tb_ni = ni; + + DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n", + idx, pkt_len, m->m_pkthdr.len); + + /* Setup TX descriptor */ + sc->sc_setup_txdesc(sc, rd, idx, paddr, m->m_pkthdr.len); + bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap, + BUS_DMASYNC_PREWRITE); + + /* Kick start */ + sc->sc_start_tx(sc, rd->rdata_txrx_ctrl, idx); +back: + if (error) + m_freem(m); + return error; +} + static void bwi_start_tx32(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802201302.m1KD2VrK043767>