@ -209,11 +209,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
int error = 0 , i ;
u32 size ;
common - > rx_bufsize = roundup ( IEEE80211_MAX_MPDU_LEN +
ah - > caps . rx_status_len ,
min ( common - > cachelsz , ( u16 ) 64 ) ) ;
ath9k_hw_set_rx_bufsize ( ah , common - > rx_bufsize -
ah - > caps . rx_status_len ) ;
@ -300,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
sc - > sc_flags & = ~ SC_OP_RXFLUSH ;
spin_lock_init ( & sc - > rx . rxbuflock ) ;
common - > rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
sc - > sc_ah - > caps . rx_status_len ;
if ( sc - > sc_ah - > caps . hw_caps & ATH9K_HW_CAP_EDMA ) {
return ath_rx_edma_init ( sc , nbufs ) ;
} else {
common - > rx_bufsize = roundup ( IEEE80211_MAX_MPDU_LEN ,
min ( common - > cachelsz , ( u16 ) 64 ) ) ;
ath_dbg ( common , ATH_DBG_CONFIG , " cachelsz %u rxbufsize %u \n " ,
common - > cachelsz , common - > rx_bufsize ) ;
@ -815,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_common *common,
if ( rx_stats - > rs_datalen > ( common - > rx_bufsize - rx_status_len ) )
return false ;
/*
* rs_more indicates chained descriptors which can be used
* to link buffers together for a sort of scatter - gather
* operation .
* reject the frame , we don ' t support scatter - gather yet and
* the frame is probably corrupt anyway
*/
/* Only use error bits from the last fragment */
if ( rx_stats - > rs_more )
return fals e;
return true ;
/*
* The rx_stats - > rs_status will not be set until the end of the
@ -981,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
if ( ! ath9k_rx_accept ( common , hdr , rx_status , rx_stats , decrypt_error ) )
return - EINVAL ;
/* Only use status info from the last fragment */
if ( rx_stats - > rs_more )
return 0 ;
ath9k_process_rssi ( common , hw , hdr , rx_stats ) ;
if ( ath9k_process_rate ( common , hw , rx_stats , rx_status ) )
@ -1582,7 +1575,7 @@ div_comb_done:
int ath_rx_tasklet ( struct ath_softc * sc , int flush , bool hp )
{
struct ath_buf * bf ;
struct sk_buff * skb = NULL , * requeue_skb ;
struct sk_buff * skb = NULL , * requeue_skb , * hdr_skb ;
struct ieee80211_rx_status * rxs ;
struct ath_hw * ah = sc - > sc_ah ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
@ -1633,8 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if ( ! skb )
continue ;
hdr = ( struct ieee80211_hdr * ) ( skb - > data + rx_status_len ) ;
rxs = IEEE80211_SKB_RXCB ( skb ) ;
/*
* Take frame header from the first fragment and RX status from
* the last one .
*/
if ( sc - > rx . frag )
hdr_skb = sc - > rx . frag ;
else
hdr_skb = skb ;
hdr = ( struct ieee80211_hdr * ) ( hdr_skb - > data + rx_status_len ) ;
rxs = IEEE80211_SKB_RXCB ( hdr_skb ) ;
ath_debug_stat_rx ( sc , & rs ) ;
@ -1643,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
* chain it back at the queue without processing it .
*/
if ( flush )
goto requeue ;
goto requeue_drop_frag ;
retval = ath9k_rx_skb_preprocess ( common , hw , hdr , & rs ,
rxs , & decrypt_error ) ;
if ( retval )
goto requeue ;
goto requeue_drop_frag ;
rxs - > mactime = ( tsf & ~ 0xffffffffULL ) | rs . rs_tstamp ;
if ( rs . rs_tstamp > tsf_lower & &
@ -1668,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
* skb and put it at the tail of the sc - > rx . rxbuf list for
* processing . */
if ( ! requeue_skb )
goto requeue ;
goto requeue_drop_frag ;
/* Unmap the frame */
dma_unmap_single ( sc - > dev , bf - > bf_buf_addr ,
@ -1679,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if ( ah - > caps . rx_status_len )
skb_pull ( skb , ah - > caps . rx_status_len ) ;
ath9k_rx_skb_postprocess ( common , skb , & rs ,
rxs , decrypt_error ) ;
if ( ! rs . rs_more )
ath9k_rx_skb_postprocess ( common , hdr_skb , & rs ,
rxs , decrypt_error ) ;
/* We will now give hardware our shiny new allocated skb */
bf - > bf_mpdu = requeue_skb ;
@ -1697,6 +1700,38 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
break ;
}
if ( rs . rs_more ) {
/*
* rs_more indicates chained descriptors which can be
* used to link buffers together for a sort of
* scatter - gather operation .
*/
if ( sc - > rx . frag ) {
/* too many fragments - cannot handle frame */
dev_kfree_skb_any ( sc - > rx . frag ) ;
dev_kfree_skb_any ( skb ) ;
skb = NULL ;
}
sc - > rx . frag = skb ;
goto requeue ;
}
if ( sc - > rx . frag ) {
int space = skb - > len - skb_tailroom ( hdr_skb ) ;
sc - > rx . frag = NULL ;
if ( pskb_expand_head ( hdr_skb , 0 , space , GFP_ATOMIC ) < 0 ) {
dev_kfree_skb ( skb ) ;
goto requeue_drop_frag ;
}
skb_copy_from_linear_data ( skb , skb_put ( hdr_skb , skb - > len ) ,
skb - > len ) ;
dev_kfree_skb_any ( skb ) ;
skb = hdr_skb ;
}
/*
* change the default rx antenna if rx diversity chooses the
* other antenna 3 times in a row .
@ -1722,6 +1757,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
ieee80211_rx ( hw , skb ) ;
requeue_drop_frag :
if ( sc - > rx . frag ) {
dev_kfree_skb_any ( sc - > rx . frag ) ;
sc - > rx . frag = NULL ;
}
requeue :
if ( edma ) {
list_add_tail ( & bf - > list , & sc - > rx . rxbuf ) ;