Beispiel #1
0
/*
 * Process an RX descriptor, and return the status to the caller.
 * Copy some hardware specific items into the software portion
 * of the descriptor.
 *
 * NB: the caller is responsible for validating the memory contents
 *     of the descriptor (e.g. flushing any cached copy).
 */
HAL_STATUS
ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
    uint32_t pa, struct ath_desc *nds, uint64_t tsf,
    struct ath_rx_status *rs)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	if ((ads->ds_rxstatus8 & AR_RxDone) == 0)
		return HAL_EINPROGRESS;

	rs->rs_status = 0;
	rs->rs_flags = 0;

	rs->rs_datalen = ads->ds_rxstatus1 & AR_DataLen;
	rs->rs_tstamp =  ads->AR_RcvTimestamp;

	/* XXX what about KeyCacheMiss? */

	rs->rs_rssi = MS(ads->ds_rxstatus4, AR_RxRSSICombined);
	rs->rs_rssi_ctl[0] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt00);
	rs->rs_rssi_ctl[1] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt01);
	rs->rs_rssi_ctl[2] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt02);
	rs->rs_rssi_ext[0] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt10);
	rs->rs_rssi_ext[1] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt11);
	rs->rs_rssi_ext[2] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt12);

	if (ads->ds_rxstatus8 & AR_RxKeyIdxValid)
		rs->rs_keyix = MS(ads->ds_rxstatus8, AR_KeyIdx);
	else
		rs->rs_keyix = HAL_RXKEYIX_INVALID;

	/* NB: caller expected to do rate table mapping */
	rs->rs_rate = RXSTATUS_RATE(ah, ads);
	rs->rs_more = (ads->ds_rxstatus1 & AR_RxMore) ? 1 : 0;

	rs->rs_isaggr = (ads->ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
	rs->rs_moreaggr = (ads->ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
	rs->rs_antenna = MS(ads->ds_rxstatus3, AR_RxAntenna);

	if (ads->ds_rxstatus3 & AR_GI)
		rs->rs_flags |= HAL_RX_GI;
	if (ads->ds_rxstatus3 & AR_2040)
		rs->rs_flags |= HAL_RX_2040;

	/*
	 * Only the AR9280 and later chips support STBC RX, so
	 * ensure we only set this bit for those chips.
	 */
	if (AR_SREV_MERLIN_10_OR_LATER(ah)
	    && ads->ds_rxstatus3 & AR_STBCFrame)
		rs->rs_flags |= HAL_RX_STBC;

	if (ads->ds_rxstatus8 & AR_PreDelimCRCErr)
		rs->rs_flags |= HAL_RX_DELIM_CRC_PRE;
	if (ads->ds_rxstatus8 & AR_PostDelimCRCErr)
		rs->rs_flags |= HAL_RX_DELIM_CRC_POST;
	if (ads->ds_rxstatus8 & AR_DecryptBusyErr)
		rs->rs_flags |= HAL_RX_DECRYPT_BUSY;
	if (ads->ds_rxstatus8 & AR_HiRxChain)
		rs->rs_flags |= HAL_RX_HI_RX_CHAIN;

	if ((ads->ds_rxstatus8 & AR_RxFrameOK) == 0) {
		/*
		 * These four bits should not be set together.  The
		 * 5416 spec states a Michael error can only occur if
		 * DecryptCRCErr not set (and TKIP is used).  Experience
		 * indicates however that you can also get Michael errors
		 * when a CRC error is detected, but these are specious.
		 * Consequently we filter them out here so we don't
		 * confuse and/or complicate drivers.
		 */

		/*
		 * The AR5416 sometimes sets both AR_CRCErr and AR_PHYErr
		 * when reporting radar pulses.  In this instance
		 * set HAL_RXERR_PHY as well as HAL_RXERR_CRC and
		 * let the driver layer figure out what to do.
		 *
		 * See PR kern/169362.
		 */
		if (ads->ds_rxstatus8 & AR_PHYErr) {
			u_int phyerr;

			/*
			 * Packets with OFDM_RESTART on post delimiter are CRC OK and
			 * usable and MAC ACKs them.
			 * To avoid packet from being lost, we remove the PHY Err flag
			 * so that driver layer does not drop them.
			 */
			phyerr = MS(ads->ds_rxstatus8, AR_PHYErrCode);

			if ((phyerr == HAL_PHYERR_OFDM_RESTART) &&
			    (ads->ds_rxstatus8 & AR_PostDelimCRCErr)) {
				ath_hal_printf(ah,
				    "%s: OFDM_RESTART on post-delim CRC error\n",
				    __func__);
				rs->rs_phyerr = 0;
			} else {
				rs->rs_status |= HAL_RXERR_PHY;
				rs->rs_phyerr = phyerr;
			}
		}
		if (ads->ds_rxstatus8 & AR_CRCErr)
			rs->rs_status |= HAL_RXERR_CRC;
		else if (ads->ds_rxstatus8 & AR_DecryptCRCErr)
			rs->rs_status |= HAL_RXERR_DECRYPT;
		else if (ads->ds_rxstatus8 & AR_MichaelErr)
			rs->rs_status |= HAL_RXERR_MIC;
	}

	return HAL_OK;
}
Beispiel #2
0
/*
 * Process an RX descriptor, and return the status to the caller.
 * Copy some hardware specific items into an rx status struct.
 */
static HAL_STATUS
ar5416ProcRxDescBase(struct ath_hal *ah, struct ath_desc *ds,
    struct ath_rx_status *rx_stats)
{
    struct ar5416_desc ads;
    struct ar5416_desc *adsp = AR5416DESC(ds);

    if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) {
        rx_stats->rs_status = HAL_RXERR_INCOMP;
        return HAL_EINPROGRESS;
    }

    /*
     * Now we need to get the stats from the descriptor. Since desc are
     * uncached, lets make a copy of the stats first. Note that, since we
     * touch most of the rx stats, a memcpy would always be more efficient
     *
     * Next we fill in all values in a caller passed stack variable.
     * This reduces the number of uncached accesses.
     * Do this copy here, after the check so that when the checks fail, we
     * dont end up copying the entire stats uselessly.
     */
    ads.u.rx = adsp->u.rx;

    rx_stats->rs_status = 0;
    rx_stats->rs_flags =  0;

    rx_stats->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
    rx_stats->rs_tstamp =  ads.AR_RcvTimestamp;

    /* If post delim CRC error happens,  */
    if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
        rx_stats->rs_rssi      = HAL_RSSI_BAD;
        rx_stats->rs_rssi_ctl0 = HAL_RSSI_BAD;
        rx_stats->rs_rssi_ctl1 = HAL_RSSI_BAD;
        rx_stats->rs_rssi_ctl2 = HAL_RSSI_BAD;
        rx_stats->rs_rssi_ext0 = HAL_RSSI_BAD;
        rx_stats->rs_rssi_ext1 = HAL_RSSI_BAD;
        rx_stats->rs_rssi_ext2 = HAL_RSSI_BAD;
    } else {
        rx_stats->rs_rssi      = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
        rx_stats->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
        rx_stats->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
        rx_stats->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
        rx_stats->rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
        rx_stats->rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
        rx_stats->rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
    }
    rx_stats->evm0 = adsp->ds_rxstatus5;
    rx_stats->evm1 = adsp->ds_rxstatus6;
    rx_stats->evm2 = adsp->ds_rxstatus7;
    /* XXX what about KeyCacheMiss? */
    if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) {
        rx_stats->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
    } else {
        rx_stats->rs_keyix = HAL_RXKEYIX_INVALID;
    }
    /* NB: caller expected to do rate table mapping */
    rx_stats->rs_rate = RXSTATUS_RATE(ah, (&ads));
    rx_stats->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;

    rx_stats->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
    rx_stats->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
    rx_stats->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
    rx_stats->rs_flags  = (ads.ds_rxstatus3 & AR_GI) ? HAL_RX_GI : 0;
    rx_stats->rs_flags  |= (ads.ds_rxstatus3 & AR_2040) ? HAL_RX_2040 : 0;

    if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) {
        rx_stats->rs_flags |= HAL_RX_DELIM_CRC_PRE;
    }
    if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
        rx_stats->rs_flags |= HAL_RX_DELIM_CRC_POST;
    }
    if (ads.ds_rxstatus8 & AR_DecryptBusyErr) {
        rx_stats->rs_flags |= HAL_RX_DECRYPT_BUSY;
    }
    if (ads.ds_rxstatus8 & AR_HiRxChain) {
        rx_stats->rs_flags |= HAL_RX_HI_RX_CHAIN;
    }
    if (ads.ds_rxstatus8 & AR_KeyMiss) {
        rx_stats->rs_status |= HAL_RXERR_KEYMISS;
    }

    if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
        /*
         * These four bits should not be set together.  The
         * 5416 spec states a Michael error can only occur if
         * DecryptCRCErr not set (and TKIP is used).  Experience
         * indicates however that you can also get Michael errors
         * when a CRC error is detected, but these are specious.
         * Consequently we filter them out here so we don't
         * confuse and/or complicate drivers.
         */
        if (ads.ds_rxstatus8 & AR_CRCErr) {
            rx_stats->rs_status |= HAL_RXERR_CRC;
        } else if (ads.ds_rxstatus8 & AR_PHYErr) {
            u_int phyerr;

            rx_stats->rs_status |= HAL_RXERR_PHY;
            phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
            rx_stats->rs_phyerr = phyerr;
        } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
            rx_stats->rs_status |= HAL_RXERR_DECRYPT;
        else if (ads.ds_rxstatus8 & AR_MichaelErr)
            rx_stats->rs_status |= HAL_RXERR_MIC;
    }
#if ATH_SUPPORT_CFEND
    /* count number of good subframes */
    if (((rx_stats->rs_status & HAL_RXERR_CRC) == 0) &&
        ((rx_stats->rs_status & HAL_RXERR_PHY) == 0) && (rx_stats->rs_isaggr)){
                if (!(rx_stats->rs_moreaggr))
                    ah->ah_rxNumCurAggrGood=0;
                else
                    ah->ah_rxNumCurAggrGood++;
    }
    /* make sure we reset good subframe count when we recieve non-aggr*/
    if (!rx_stats->rs_isaggr) {
        ah->ah_rxNumCurAggrGood=0;
    }
#endif
    return HAL_OK;
}
Beispiel #3
0
void ar5416FillRadiotapHdr(struct ath_hal *ah,
                           struct ah_rx_radiotap_header *rh,                           
                           struct ah_ppi_data *ppi,
                           struct ath_desc *ds,
                           void *buf_addr)
{
    struct ath_rx_status *rx_stats = &ds->ds_rxstat;
    struct ar5416_desc *adsp = AR5416DESC(ds);
    int i, j;

    if (rh != NULL) {
        OS_MEMZERO(rh, sizeof(struct ah_rx_radiotap_header));

        rh->tsf = ar5416GetTsf64(ah); /* AR5416 specific */

        rh->wr_rate = RXSTATUS_RATE(ah, adsp);
        rh->wr_chan_freq = (AH_PRIVATE(ah)->ah_curchan) ?
    		AH_PRIVATE(ah)->ah_curchan->channel : 0;
        rh->wr_antsignal = MS(adsp->ds_rxstatus4, AR_RxRSSICombined);

        // Fill out extended channel info.
        rh->wr_xchannel.freq = rh->wr_chan_freq;
        rh->wr_xchannel.flags = AH_PRIVATE(ah)->ah_curchan->channelFlags;
        rh->wr_xchannel.maxpower = AH_PRIVATE(ah)->ah_curchan->maxRegTxPower;
        rh->wr_xchannel.chan = ath_hal_mhz2ieee(ah, rh->wr_chan_freq, rh->wr_xchannel.flags);

        /* Radiotap Rx flags */
        if (AH5416(ah)->ah_getPlcpHdr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PLCP;
        }
        if (adsp->ds_rxstatus8 & AR_CRCErr) {
            /* for now, set both values */
            rh->wr_flags |= AH_RADIOTAP_F_BADFCS;
            rh->wr_rx_flags |= AH_RADIOTAP_F_RX_BADFCS;
        }
        if (adsp->ds_rxstatus3 & AR_GI) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_HALFGI;
            rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_SHORT_GI;
        }
        if (adsp->ds_rxstatus3 & AR_2040 ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40;
            rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_40MHZ;
        }
        if (adsp->ds_rxstatus3 & AR_Parallel40 ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40P;
        }
        if (adsp->ds_rxstatus8 & AR_RxAggr ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_AGGR;
        }
        if (adsp->ds_rxstatus8 & AR_RxFirstAggr ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_FIRSTAGGR;
        }
        if (adsp->ds_rxstatus8 & AR_RxMoreAggr ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MOREAGGR;
        }
        if (adsp->ds_rxstatus1 & AR_RxMore ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MORE;
        }
        if (adsp->ds_rxstatus8 & AR_PreDelimCRCErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PREDELIM_CRCERR;
        }
        if (adsp->ds_rxstatus8 & AR_PostDelimCRCErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_POSTDELIM_CRCERR;
        }
        if (adsp->ds_rxstatus8 & AR_DecryptCRCErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_DECRYPTCRCERR;
        }
        if (adsp->ds_rxstatus3 & AR_STBC ) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_STBC;
        }
        if (adsp->ds_rxstatus8 & AR_PHYErr) {
            rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PHYERR;
            rh->ath_ext.phyerr_code = rx_stats->rs_phyerr;
        }

        /* add the extension part */
        rh->vendor_ext.oui[0] = (ATH_OUI & 0xff);
        rh->vendor_ext.oui[1] = ((ATH_OUI >> 8) & 0xff);
        rh->vendor_ext.oui[2] = ((ATH_OUI >> 16) & 0xff);
        rh->vendor_ext.skip_length = sizeof(struct ah_rx_vendor_radiotap_header);
        /* sub_namespace - simply set to 0 since we don't use multiple namespaces */
        rh->vendor_ext.sub_namespace = 0;

        rh->ath_ext.version = AH_RADIOTAP_VERSION;

        rh->ath_ext.ch_info.num_chains =
            owl_get_ntxchains(AH5416(ah)->ah_rxchainmask);

        /*
         * Two-pass strategy to fill in RSSI and EVM:
         * First pass: copy the info from each chain from the
         * descriptor into the corresponding index of the
         * radiotap header's ch_info array.
         * Second pass: use the rxchainmask to determine
         * which chains are valid.  Shift ch_info array
         * elements down to fill in indices that were off
         * in the rxchainmask.
         */
        rh->ath_ext.ch_info.rssi_ctl[0] = rx_stats->rs_rssi_ctl0;
        rh->ath_ext.ch_info.rssi_ext[0] = rx_stats->rs_rssi_ext0;
        rh->ath_ext.ch_info.evm[0] = rx_stats->evm0;

        rh->ath_ext.ch_info.rssi_ctl[1] = rx_stats->rs_rssi_ctl1;
        rh->ath_ext.ch_info.rssi_ext[1] = rx_stats->rs_rssi_ext1;
        rh->ath_ext.ch_info.evm[1] = rx_stats->evm1;

        rh->ath_ext.ch_info.rssi_ctl[2] = rx_stats->rs_rssi_ctl2;
        rh->ath_ext.ch_info.rssi_ext[2] = rx_stats->rs_rssi_ext2;
        rh->ath_ext.ch_info.evm[2] = rx_stats->evm2;

        for (i = 0, j = 0; i < RADIOTAP_MAX_CHAINS ; i++ ) {
            if (AH5416(ah)->ah_rxchainmask & (0x1 << i)) {
                /*
                 * This chain is enabled.  Does its data need
                 * to be shifted down into a lower array index?
                 */
                if (i != j) {
                    rh->ath_ext.ch_info.rssi_ctl[j] =
                        rh->ath_ext.ch_info.rssi_ctl[i];
                    rh->ath_ext.ch_info.rssi_ext[j] =
                        rh->ath_ext.ch_info.rssi_ext[i];
                    /*
                     * EVM fields only need to be shifted if PCU_SEL_EVM bit is set.
                     * Otherwise EVM fields hold the value of PLCP headers which
                     * are not related to chainmask.
                     */
                    if (!(AH5416(ah)->ah_getPlcpHdr)) {
                        rh->ath_ext.ch_info.evm[j] = rh->ath_ext.ch_info.evm[i];
                    }
                }
                j++;
            }
        }
        rh->ath_ext.n_delims = MS(adsp->ds_rxstatus1, AR_NumDelim);
    }
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
			struct ath_rx_status *rs, u64 tsf)
{
	struct ar5416_desc ads;
	struct ar5416_desc *adsp = AR5416DESC(ds);
	u32 phyerr;

	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
		return -EINPROGRESS;

	ads.u.rx = adsp->u.rx;

	rs->rs_status = 0;
	rs->rs_flags = 0;

	rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
	rs->rs_tstamp = ads.AR_RcvTimestamp;

	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
		rs->rs_rssi = ATH9K_RSSI_BAD;
		rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
		rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
		rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
		rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
		rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
		rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
	} else {
		rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
		rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
						AR_RxRSSIAnt00);
		rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
						AR_RxRSSIAnt01);
		rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
						AR_RxRSSIAnt02);
		rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
						AR_RxRSSIAnt10);
		rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
						AR_RxRSSIAnt11);
		rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
						AR_RxRSSIAnt12);
	}
	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
		rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
	else
		rs->rs_keyix = ATH9K_RXKEYIX_INVALID;

	rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
	rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;

	rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
	rs->rs_moreaggr =
		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
	rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
	rs->rs_flags =
		(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
	rs->rs_flags |=
		(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;

	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
		rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
		rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
		rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;

	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
		/*
		 * Treat these errors as mutually exclusive to avoid spurious
		 * extra error reports from the hardware. If a CRC error is
		 * reported, then decryption and MIC errors are irrelevant,
		 * the frame is going to be dropped either way
		 */
		if (ads.ds_rxstatus8 & AR_CRCErr)
			rs->rs_status |= ATH9K_RXERR_CRC;
		else if (ads.ds_rxstatus8 & AR_PHYErr) {
			rs->rs_status |= ATH9K_RXERR_PHY;
			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
			rs->rs_phyerr = phyerr;
		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
			rs->rs_status |= ATH9K_RXERR_DECRYPT;
		else if (ads.ds_rxstatus8 & AR_MichaelErr)
			rs->rs_status |= ATH9K_RXERR_MIC;

		if (ads.ds_rxstatus8 & AR_KeyMiss)
			rs->rs_status |= ATH9K_RXERR_DECRYPT;
	}

	return 0;
}
Beispiel #5
0
/*
 * Process an RX descriptor, and return the status to the caller.
 * Copy some hardware specific items into the software portion
 * of the descriptor.
 *
 * NB: the caller is responsible for validating the memory contents
 *     of the descriptor (e.g. flushing any cached copy).
 */
HAL_STATUS
ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
    uint32_t pa, struct ath_desc *nds, uint64_t tsf,
    struct ath_rx_status *rs)
{
	struct ar5416_desc *ads = AR5416DESC(ds);
	struct ar5416_desc *ands = AR5416DESC(nds);

	if ((ads->ds_rxstatus8 & AR_RxDone) == 0)
		return HAL_EINPROGRESS;
	/*
	 * Given the use of a self-linked tail be very sure that the hw is
	 * done with this descriptor; the hw may have done this descriptor
	 * once and picked it up again...make sure the hw has moved on.
	 */
	if ((ands->ds_rxstatus8 & AR_RxDone) == 0
	    && OS_REG_READ(ah, AR_RXDP) == pa)
		return HAL_EINPROGRESS;

	rs->rs_status = 0;
	rs->rs_flags = 0;

	rs->rs_datalen = ads->ds_rxstatus1 & AR_DataLen;
	rs->rs_tstamp =  ads->AR_RcvTimestamp;

	/* XXX what about KeyCacheMiss? */

	rs->rs_rssi = MS(ads->ds_rxstatus4, AR_RxRSSICombined);
	rs->rs_rssi_ctl[0] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt00);
	rs->rs_rssi_ctl[1] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt01);
	rs->rs_rssi_ctl[2] = MS(ads->ds_rxstatus0, AR_RxRSSIAnt02);
	rs->rs_rssi_ext[0] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt10);
	rs->rs_rssi_ext[1] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt11);
	rs->rs_rssi_ext[2] = MS(ads->ds_rxstatus4, AR_RxRSSIAnt12);

	if (ads->ds_rxstatus8 & AR_RxKeyIdxValid)
		rs->rs_keyix = MS(ads->ds_rxstatus8, AR_KeyIdx);
	else
		rs->rs_keyix = HAL_RXKEYIX_INVALID;

	/* NB: caller expected to do rate table mapping */
	rs->rs_rate = RXSTATUS_RATE(ah, ads);
	rs->rs_more = (ads->ds_rxstatus1 & AR_RxMore) ? 1 : 0;

	rs->rs_isaggr = (ads->ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
	rs->rs_moreaggr = (ads->ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
	rs->rs_antenna = MS(ads->ds_rxstatus3, AR_RxAntenna);

	if (ads->ds_rxstatus3 & AR_GI)
		rs->rs_flags |= HAL_RX_GI;
	if (ads->ds_rxstatus3 & AR_2040)
		rs->rs_flags |= HAL_RX_2040;

	if (ads->ds_rxstatus8 & AR_PreDelimCRCErr)
		rs->rs_flags |= HAL_RX_DELIM_CRC_PRE;
	if (ads->ds_rxstatus8 & AR_PostDelimCRCErr)
		rs->rs_flags |= HAL_RX_DELIM_CRC_POST;
	if (ads->ds_rxstatus8 & AR_DecryptBusyErr)
		rs->rs_flags |= HAL_RX_DECRYPT_BUSY;
	if (ads->ds_rxstatus8 & AR_HiRxChain)
		rs->rs_flags |= HAL_RX_HI_RX_CHAIN;

	if ((ads->ds_rxstatus8 & AR_RxFrameOK) == 0) {
		/*
		 * These four bits should not be set together.  The
		 * 5416 spec states a Michael error can only occur if
		 * DecryptCRCErr not set (and TKIP is used).  Experience
		 * indicates however that you can also get Michael errors
		 * when a CRC error is detected, but these are specious.
		 * Consequently we filter them out here so we don't
		 * confuse and/or complicate drivers.
		 */
		if (ads->ds_rxstatus8 & AR_CRCErr)
			rs->rs_status |= HAL_RXERR_CRC;
		else if (ads->ds_rxstatus8 & AR_PHYErr) {
			u_int phyerr;

			rs->rs_status |= HAL_RXERR_PHY;
			phyerr = MS(ads->ds_rxstatus8, AR_PHYErrCode);
			rs->rs_phyerr = phyerr;
		} else if (ads->ds_rxstatus8 & AR_DecryptCRCErr)
			rs->rs_status |= HAL_RXERR_DECRYPT;
		else if (ads->ds_rxstatus8 & AR_MichaelErr)
			rs->rs_status |= HAL_RXERR_MIC;
	}

	return HAL_OK;
}
HAL_STATUS ar5416ProcRxDescFast_20(struct ath_hal *ah, struct ath_rx_desc *ds,
				   a_uint32_t pa, struct ath_desc *nds,
				   struct ath_rx_status *rx_stats)
{
	struct ar5416_desc ads;
	struct ar5416_desc *adsp = AR5416DESC(ds);
	struct ar5416_desc *ands = AR5416DESC(nds);

	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
		return HAL_EINPROGRESS;
	/*
	 * Given the use of a self-linked tail be very sure that the hw is
	 * done with this descriptor; the hw may have done this descriptor
	 * once and picked it up again...make sure the hw has moved on.
	 */
	if ((ands->ds_rxstatus8 & AR_RxDone) == 0
	    && OS_REG_READ(ah, AR_RXDP) == pa)
		return HAL_EINPROGRESS;

	/*
	 * Now we need to get the stats from the descriptor. Since desc are 
	 * uncached, lets make a copy of the stats first. Note that, since we
	 * touch most of the rx stats, a memcpy would always be more efficient
	 *
	 * Next we fill in all values in a caller passed stack variable.
	 * This reduces the number of uncached accesses.
	 * Do this copy here, after the check so that when the checks fail, we
	 * dont end up copying the entire stats uselessly.
	 */
	ads.u.rx = adsp->u.rx;

	rx_stats->rs_status = 0;
	rx_stats->rs_flags = 0;

	rx_stats->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
	rx_stats->rs_tstamp =  ads.AR_RcvTimestamp;

	/* XXX what about KeyCacheMiss? */
	rx_stats->rs_rssi_combined = 
		MS(ads.ds_rxstatus4, AR_RxRSSICombined);
	rx_stats->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
	rx_stats->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
	rx_stats->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
	rx_stats->rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
	rx_stats->rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
	rx_stats->rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
		rx_stats->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
	else
		rx_stats->rs_keyix = HAL_RXKEYIX_INVALID;
	/* NB: caller expected to do rate table mapping */
	rx_stats->rs_rate = RXSTATUS_RATE(ah, (&ads));
	rx_stats->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;

	rx_stats->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
	rx_stats->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
	rx_stats->rs_flags  |= (ads.ds_rxstatus3 & AR_GI) ? HAL_RX_GI : 0;
	rx_stats->rs_flags  |= (ads.ds_rxstatus3 & AR_2040) ? HAL_RX_2040 : 0;

	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
		rx_stats->rs_flags |= HAL_RX_DELIM_CRC_PRE;
	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
		rx_stats->rs_flags |= HAL_RX_DELIM_CRC_POST;
	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
		rx_stats->rs_flags |= HAL_RX_DECRYPT_BUSY;

	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
		/*
		 * These four bits should not be set together.  The
		 * 5416 spec states a Michael error can only occur if
		 * DecryptCRCErr not set (and TKIP is used).  Experience
		 * indicates however that you can also get Michael errors
		 * when a CRC error is detected, but these are specious.
		 * Consequently we filter them out here so we don't
		 * confuse and/or complicate drivers.
		 */
		if (ads.ds_rxstatus8 & AR_CRCErr)
			rx_stats->rs_status |= HAL_RXERR_CRC;
		else if (ads.ds_rxstatus8 & AR_PHYErr) {
			a_uint32_t phyerr;

			rx_stats->rs_status |= HAL_RXERR_PHY;
			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
			rx_stats->rs_phyerr = phyerr;
		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
			rx_stats->rs_status |= HAL_RXERR_DECRYPT;
		else if (ads.ds_rxstatus8 & AR_MichaelErr)
			rx_stats->rs_status |= HAL_RXERR_MIC;
	}
	rx_stats->evm0=ads.AR_RxEVM0;
	rx_stats->evm1=ads.AR_RxEVM1;
	rx_stats->evm2=ads.AR_RxEVM2;

	return HAL_OK;
}