PERFORCE change 135785 for review
Sepherosa Ziehau
sephe at FreeBSD.org
Wed Feb 20 13:02:32 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=135785
Change 135785 by sephe at 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)
{
More information about the p4-projects
mailing list