X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;ds=sidebyside;f=carlfw%2Fsrc%2Fwlantx.c;h=a8d09522d3619c2d7934d79d74be3dd01414a17c;hb=001384147050b9cd9daadb4d3115cc0f13f5b319;hp=9f2f51b07ba54794010b3ce1a5a7654a6402a041;hpb=11c1064a307a661df20e237e3623e1b5d88641fa;p=carl9170fw.git diff --git a/carlfw/src/wlantx.c b/carlfw/src/wlantx.c index 9f2f51b..a8d0952 100644 --- a/carlfw/src/wlantx.c +++ b/carlfw/src/wlantx.c @@ -19,8 +19,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * with this program; If not, see . */ #include "carl9170.h" @@ -33,15 +32,35 @@ #include "linux/ieee80211.h" #include "wol.h" -static void wlan_txunstuck(unsigned int queue) +static void wlan_txunstuck(unsigned int qidx) { - set_wlan_txq_dma_addr(queue, ((uint32_t) fw.wlan.tx_queue[queue].head) | 1); + struct dma_queue *queue = &fw.wlan.tx_queue[qidx]; + struct dma_desc *iter; + + /* + * walk up to the last descriptor which hasn't been + * processed by the hardware before it bailed out + * due to a TX error. + * Note: if there was no more "pending" frame + * in the queue, it iter will be on the + * queue->terminator (which is fine) + */ + __for_each_desc_bits(iter, queue, AR9170_OWN_BITS_SW); + + set_wlan_txq_dma_addr(qidx, ((uint32_t) iter) | 1); + wlan_trigger(BIT(qidx)); } #ifdef CONFIG_CARL9170FW_DMA_QUEUE_BUMP -static void wlan_txupdate(unsigned int queue) +static void wlan_txupdate(unsigned int qidx) { - set_wlan_txq_dma_addr(queue, ((uint32_t) fw.wlan.tx_queue[queue].head)); + struct dma_queue *queue = &fw.wlan.tx_queue[qidx]; + struct dma_desc *iter; + /* comment in wlan_txunstuck applies here too. */ + __for_each_desc_bits(iter, queue, AR9170_OWN_BITS_SW); + + set_wlan_txq_dma_addr(qidx, ((uint32_t) iter)); + wlan_trigger(BIT(qidx)); } void wlan_dma_bump(unsigned int qidx) @@ -241,7 +260,7 @@ static void __wlan_tx(struct dma_desc *desc) if (unlikely(super->s.fill_in_tsf)) { struct ieee80211_mgmt *mgmt = (void *) &super->f.data.i3e; - uint32_t *tsf = (uint32_t *) &mgmt->u.probe_resp.timestamp; + uint32_t tmptsf[2]; /* * Truth be told: this is a hack. @@ -253,14 +272,15 @@ static void __wlan_tx(struct dma_desc *desc) * (even, if it's got an accurate atomic clock source). */ - read_tsf(tsf); + read_tsf(tmptsf); + memcpy(&mgmt->u.probe_resp.timestamp, tmptsf, sizeof(tmptsf)); } wlan_tx_ampdu(super); -#ifdef CONFIG_CARL9170FW_DEBUG +#if (defined CONFIG_CARL9170FW_DEBUG) && (defined CONFIG_CARL9170FW_RADIO_FUNCTIONS) BUG_ON(fw.phy.psm.state != CARL9170_PSM_WAKE); -#endif /* CONFIG_CARL9170FW_DEBUG */ +#endif /* CONFIG_CARL9170FW_DEBUG && CONFIG_CARL9170FW_RADIO_FUNCTIONS */ /* insert desc into the right queue */ dma_put(&fw.wlan.tx_queue[super->s.queue], desc); @@ -367,7 +387,7 @@ static bool wlan_tx_status(struct dma_queue *queue, wlan_txunstuck(qidx); /* abort cycle - this is necessary due to HW design */ - return false; + goto out; } else { /* (HT-) BlockACK failure */ @@ -383,7 +403,7 @@ static bool wlan_tx_status(struct dma_queue *queue, BUG_ON(dma_unlink_head(queue) != desc); #endif /* CONFIG_CARL9170FW_DEBUG */ dma_put(&fw.wlan.tx_retry, desc); - return true; + goto out; } } else { /* out of frame attempts - discard frame */ @@ -415,7 +435,7 @@ static bool wlan_tx_status(struct dma_queue *queue, if (fw.wlan.fw_desc_callback) fw.wlan.fw_desc_callback(super, success); - return true; + goto out; } if (unlikely(super->s.cab)) @@ -430,7 +450,12 @@ static bool wlan_tx_status(struct dma_queue *queue, /* recycle freed descriptors */ dma_reclaim(&fw.pta.down_queue, desc); down_trigger(); - return true; +out: + /* + * if we encounter a frame which run out of (normal) + * tx retries we have to stop too. + */ + return !txfail; } void handle_wlan_tx_completion(void)