[PATCH] Add IEEE80211_TX_CTL_REQ_TX_STATUS support

Kalle Valo kvalo at qca.qualcomm.com
Wed Jun 5 02:16:02 EDT 2013


Pontus Fuchs <pontus.fuchs at gmail.com> writes:

> As there seems to be no packet id in the status indication message
> from the FW, I stop the queues in order to have only one frame with
> IEEE80211_TX_CTL_REQ_TX_STATUS submitted to the FW.
>
> Signed-off-by: Pontus Fuchs <pontus.fuchs at gmail.com>
> ---

[...]

> +void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status)
> +{
> +	struct ieee80211_tx_info *info;
> +	struct sk_buff *skb;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&wcn->dxe_lock, flags);
> +	skb = wcn->tx_ack_skb;
> +	wcn->tx_ack_skb = NULL;
> +	spin_unlock_irqrestore(&wcn->dxe_lock, flags);
> +
> +	if (!skb) {
> +		wcn36xx_error("Spurious TX complete indication");
> +		return;

wcn36xx_warn() is more approriate here.

> +	}
> +
> +	info = IEEE80211_SKB_CB(skb);
> +	if (status == 1) {
> +		wcn36xx_dbg(WCN36XX_DBG_DXE, "Got positive ack status");
> +		info->flags |= IEEE80211_TX_STAT_ACK;
> +	} else
> +		wcn36xx_dbg(WCN36XX_DBG_DXE, "Got negative ack status");

You can avoid the else branch with this:

wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx status %d", status);

if (status == 1)
        info->flags |= IEEE80211_TX_STAT_ACK;

> @@ -478,14 +507,33 @@ int wcn36xx_dxe_tx(struct wcn36xx *wcn,
>  		   struct sk_buff *skb,
>  		   u8 broadcast,
>  		   bool is_high,
> -		   u32 header_len)
> +		   u32 header_len, bool tx_ack)
>  {
>  	struct wcn36xx_dxe_ctl *ctl = NULL;
>  	struct wcn36xx_dxe_desc *desc = NULL;
>  	struct wcn36xx_dxe_ch *ch = NULL;
> +	unsigned long flags;
>  
>  	ch = is_high ? &wcn->dxe_tx_h_ch : &wcn->dxe_tx_l_ch;
>  
> +	if (tx_ack) {
> +		wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested");
> +		spin_lock_irqsave(&wcn->dxe_lock, flags);
> +		if (wcn->tx_ack_skb) {
> +			spin_unlock_irqrestore(&wcn->dxe_lock, flags);
> +			wcn36xx_error("tx_ack_skb already set");
> +			return -EINVAL;

wcn36xx_warn() is better here. And I don't see skb freed when this
happens.

> @@ -682,6 +729,13 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn)
>  {
>  	free_irq(wcn->tx_irq, wcn);
>  	free_irq(wcn->rx_irq, wcn);
> +
> +	if (wcn->tx_ack_skb) {
> +		ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
> +		ieee80211_wake_queues(wcn->hw);
> +		wcn->tx_ack_skb = NULL;
> +	}

Calling wake_queues() from deinit() looks bad. Is that really the
intention?

> +static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len)
> +{
> +	struct tx_compl_ind_msg *rsp = (struct tx_compl_ind_msg *)buf;
> +
> +	if (len != sizeof(*rsp)) {
> +		wcn36xx_error("Bad TX complete indication");
> +		return -EIO;
> +	}

Again wcn36xx_warn() is better.

> +
> +	wcn36xx_dxe_tx_ack_ind(wcn, rsp->status);
> +	return 0;

Style: having an empty line before the return makes the code more
readable.

> --- a/wcn36xx.h
> +++ b/wcn36xx.h
> @@ -20,6 +20,7 @@
>  #include <linux/completion.h>
>  #include <linux/printk.h>
>  #include <linux/firmware.h>
> +#include <linux/spinlock.h>
>  #include <linux/workqueue.h>
>  #include <mach/msm_smd.h>
>  #include <net/mac80211.h>
> @@ -149,9 +150,14 @@ struct wcn36xx {
>  	struct wcn36xx_dxe_ch	dxe_rx_l_ch;	/* RX low */
>  	struct wcn36xx_dxe_ch	dxe_rx_h_ch;	/* RX high */
>  
> +	/* DXE lock */
> +	spinlock_t	dxe_lock;
> +
>  	/* Memory pools */
>  	struct wcn36xx_dxe_mem_pool mgmt_mem_pool;
>  	struct wcn36xx_dxe_mem_pool data_mem_pool;
> +
> +	struct sk_buff		*tx_ack_skb;

It would be good to document that tx_ack_skb is serialised with dxe_lock.

-- 
Kalle Valo



More information about the wcn36xx mailing list