Search Linux Wireless

Re: [PATCH v2] ath6kl: Add support for uAPSD

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Thirumalai,

On 01/12/2012 02:51 PM, Thirumalai Pachamuthu wrote:
> * A new APSD power save queue is added in the station structure.
> * When a station has APSD capability and goes to power save, the frame
>   designated to the station will be buffered in APSD queue.
> * When the host receives a frame which the firmware marked as trigger,
>   host delivers the buffered frame from the APSD power save queue.
>   Number of frames to deliver is decided by MAX SP length.
> * When a station moves from sleep to awake state, all frames buffered
>   in APSD power save queue are sent to the firmware.
> * When a station is disconnected, all frames bufferes in APSD power save
>   queue are dropped.
> * When the host queues the first frame to the APSD queue or removes the
>   last frame from the APSD queue, it is indicated to the firmware using
>   WMI_AP_APSD_BUFFERED_TRAFFIC_CMD.
> 
> Signed-off-by: Thirumalai Pachamuthu <tpachamu@xxxxxxxxxxxxxxxx>

Thanks, I applied your patch with these changes below. Please check that
I didn't break anything.

> +static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,
> +				struct ath6kl_vif *vif,
> +				struct sk_buff *skb,
> +				u32 *flags)
> +{
> +	struct ath6kl *ar = vif->ar;
> +	bool is_apsdq_empty = false;
> +	struct ethhdr *datap = (struct ethhdr *) skb->data;
> +	u8 up = 0;

This is initilised in an else branch I added below.

> +	u8 traffic_class;
> +	u16 ether_type;
> +	u8 *ip_hdr;
> +	struct ath6kl_llc_snap_hdr *llc_hdr;

I combined the same type variable declarations here.

> +
> +	if (conn->sta_flags & STA_PS_APSD_TRIGGER) {
> +		/*
> +		 * This tx is because of a uAPSD trigger, determine
> +		 * more and EOSP bit. Set EOSP if queue is empty
> +		 * or sufficient frames are delivered for this trigger.
> +		 */
> +		spin_lock_bh(&conn->psq_lock);
> +		if (!skb_queue_empty(&conn->apsdq))
> +			*flags |= WMI_DATA_HDR_FLAGS_MORE;
> +		else if (conn->sta_flags & STA_PS_APSD_EOSP)
> +			*flags |= WMI_DATA_HDR_FLAGS_EOSP;
> +		*flags |= WMI_DATA_HDR_FLAGS_UAPSD;
> +		spin_unlock_bh(&conn->psq_lock);
> +		return false;
> +	} else if (!conn->apsd_info)
> +		return false;
> +
> +	if (test_bit(WMM_ENABLED, &vif->flags)) {
> +		ether_type = be16_to_cpu(datap->h_proto);
> +		if (is_ethertype(ether_type)) {
> +			/* packet is in DIX format  */
> +			ip_hdr = (u8 *)(datap + 1);
> +		} else {
> +			/* packet is in 802.3 format */
> +			llc_hdr = (struct ath6kl_llc_snap_hdr *)
> +							(datap + 1);
> +			ether_type = be16_to_cpu(llc_hdr->eth_type);
> +			ip_hdr = (u8 *)(llc_hdr + 1);
> +		}
> +
> +		if (ether_type == IP_ETHERTYPE)
> +			up = ath6kl_wmi_determine_user_priority(
> +							ip_hdr, 0);
> +	}

I added the else branch here.

> +static bool ath6kl_process_psq(struct ath6kl_sta *conn,
> +				struct ath6kl_vif *vif,
> +				struct sk_buff *skb,
> +				u32 *flags)
> +{
> +	bool is_psq_empty = false;
> +	struct ath6kl *ar = vif->ar;
> +
> +	if (conn->sta_flags & STA_PS_POLLED) {
> +		spin_lock_bh(&conn->psq_lock);
> +		if (!skb_queue_empty(&conn->psq))
> +			*flags |= WMI_DATA_HDR_FLAGS_MORE;
> +		spin_unlock_bh(&conn->psq_lock);
> +		return false;
> +	} else {
> +		/* Queue the frames if the STA is sleeping */

The else block is not needed as there's a return in the if block above.
So the code below can be taken out of the else block.

> +static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,
> +						 struct ath6kl_sta *conn)
> +{
> +	struct ath6kl *ar = vif->ar;
> +	bool is_apsdq_empty;
> +	bool is_apsdq_empty_at_start;
> +	u32 num_frames_to_deliver;
> +	struct sk_buff *skb = NULL;
> +	u32 flags;

Combined variable declarations.

>  				spin_lock_bh(&conn->psq_lock);
> -				while ((skbuff = skb_dequeue(&conn->psq))
> -				       != NULL) {
> +				while ((skbuff = skb_dequeue(&conn->psq))) {
> +					spin_unlock_bh(&conn->psq_lock);
> +					ath6kl_data_tx(skbuff, vif->ndev);
> +					spin_lock_bh(&conn->psq_lock);
> +					skbuff = skb_dequeue(&conn->psq);
> +				}

This was buggy now. After the first skb you will take two skbs in one round.

> +
> +				is_apsdq_empty = skb_queue_empty(&conn->apsdq);
> +				while ((skbuff = skb_dequeue(&conn->apsdq))) {
>  					spin_unlock_bh(&conn->psq_lock);
>  					ath6kl_data_tx(skbuff, vif->ndev);
>  					spin_lock_bh(&conn->psq_lock);
> +					skbuff = skb_dequeue(&conn->apsdq);
>  				}

And this had the same bug.

Kalle
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux