示例#1
0
static int
ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
{
	struct ath_hal *ah = sc->sc_ah;
	int error;
	struct mbuf *m;
	struct ath_desc *ds;

	m = bf->bf_m;
	if (m == NULL) {
		/*
		 * NB: by assigning a page to the rx dma buffer we
		 * implicitly satisfy the Atheros requirement that
		 * this buffer be cache-line-aligned and sized to be
		 * multiple of the cache line size.  Not doing this
		 * causes weird stuff to happen (for the 5210 at least).
		 */
		m = m_getcl(MB_WAIT, MT_DATA, M_PKTHDR);
		if (m == NULL) {
			DPRINTF(sc, ATH_DEBUG_ANY,
				"%s: no mbuf/cluster\n", __func__);
			sc->sc_stats.ast_rx_nombuf++;
			return ENOMEM;
		}
		m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;

		error = bus_dmamap_load_mbuf_segment(sc->sc_dmat,
					     bf->bf_dmamap, m,
					     bf->bf_segs, 1, &bf->bf_nseg,
					     BUS_DMA_NOWAIT);
		if (error != 0) {
			DPRINTF(sc, ATH_DEBUG_ANY,
			    "%s: bus_dmamap_load_mbuf_sg failed; error %d\n",
			    __func__, error);
			sc->sc_stats.ast_rx_busdma++;
			m_freem(m);
			return error;
		}
		KASSERT(bf->bf_nseg == 1,
			("multi-segment packet; nseg %u", bf->bf_nseg));
		bf->bf_m = m;
	}
	bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD);

	/*
	 * Setup descriptors.  For receive we always terminate
	 * the descriptor list with a self-linked entry so we'll
	 * not get overrun under high load (as can happen with a
	 * 5212 when ANI processing enables PHY error frames).
	 *
	 * To insure the last descriptor is self-linked we create
	 * each descriptor as self-linked and add it to the end.  As
	 * each additional descriptor is added the previous self-linked
	 * entry is ``fixed'' naturally.  This should be safe even
	 * if DMA is happening.  When processing RX interrupts we
	 * never remove/process the last, self-linked, entry on the
	 * descriptor list.  This insures the hardware always has
	 * someplace to write a new frame.
	 */
	/*
	 * 11N: we can no longer afford to self link the last descriptor.
	 * MAC acknowledges BA status as long as it copies frames to host
	 * buffer (or rx fifo). This can incorrectly acknowledge packets
	 * to a sender if last desc is self-linked.
	 */
	ds = bf->bf_desc;
	if (sc->sc_rxslink)
		ds->ds_link = bf->bf_daddr;	/* link to self */
	else
		ds->ds_link = 0;		/* terminate the list */
	ds->ds_data = bf->bf_segs[0].ds_addr;
	ath_hal_setuprxdesc(ah, ds
		, m->m_len		/* buffer size */
		, 0
	);

	if (sc->sc_rxlink != NULL)
		*sc->sc_rxlink = bf->bf_daddr;
	sc->sc_rxlink = &ds->ds_link;
	return 0;
}
/*
 * Allocate and setup an initial beacon frame.
 */
int
ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ath_vap *avp = ATH_VAP(vap);
	struct ath_buf *bf;
	struct mbuf *m;
	int error;

	bf = avp->av_bcbuf;
	DPRINTF(sc, ATH_DEBUG_NODE, "%s: bf_m=%p, bf_node=%p\n",
	    __func__, bf->bf_m, bf->bf_node);
	if (bf->bf_m != NULL) {
		bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
		m_freem(bf->bf_m);
		bf->bf_m = NULL;
	}
	if (bf->bf_node != NULL) {
		ieee80211_free_node(bf->bf_node);
		bf->bf_node = NULL;
	}

	/*
	 * NB: the beacon data buffer must be 32-bit aligned;
	 * we assume the mbuf routines will return us something
	 * with this alignment (perhaps should assert).
	 */
	m = ieee80211_beacon_alloc(ni, &avp->av_boff);
	if (m == NULL) {
		device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__);
		sc->sc_stats.ast_be_nombuf++;
		return ENOMEM;
	}
	error = bus_dmamap_load_mbuf_segment(sc->sc_dmat, bf->bf_dmamap, m,
				     bf->bf_segs, 1, &bf->bf_nseg,
				     BUS_DMA_NOWAIT);
	if (error != 0) {
		device_printf(sc->sc_dev,
		    "%s: cannot map mbuf, bus_dmamap_load_mbuf_sg returns %d\n",
		    __func__, error);
		m_freem(m);
		return error;
	}

	/*
	 * Calculate a TSF adjustment factor required for staggered
	 * beacons.  Note that we assume the format of the beacon
	 * frame leaves the tstamp field immediately following the
	 * header.
	 */
	if (sc->sc_stagbeacons && avp->av_bslot > 0) {
		uint64_t tsfadjust;
		struct ieee80211_frame *wh;

		/*
		 * The beacon interval is in TU's; the TSF is in usecs.
		 * We figure out how many TU's to add to align the timestamp
		 * then convert to TSF units and handle byte swapping before
		 * inserting it in the frame.  The hardware will then add this
		 * each time a beacon frame is sent.  Note that we align vap's
		 * 1..N and leave vap 0 untouched.  This means vap 0 has a
		 * timestamp in one beacon interval while the others get a
		 * timstamp aligned to the next interval.
		 */
		tsfadjust = ni->ni_intval *
		    (ATH_BCBUF - avp->av_bslot) / ATH_BCBUF;
		tsfadjust = htole64(tsfadjust << 10);	/* TU -> TSF */

		DPRINTF(sc, ATH_DEBUG_BEACON,
		    "%s: %s beacons bslot %d intval %u tsfadjust %llu\n",
		    __func__, sc->sc_stagbeacons ? "stagger" : "burst",
		    avp->av_bslot, ni->ni_intval,
		    (unsigned long long) le64toh(tsfadjust));

		wh = mtod(m, struct ieee80211_frame *);
		memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust));
	}