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