[rt2x00-users] [RFC] rt2x00: implement PS broadcast/multicast frame buffering

Gertjan van Wingerde gwingerde at gmail.com
Tue Jun 22 19:25:02 UTC 2010


On 06/21/10 18:42, Helmut Schaa wrote:
> In AP mode mac80211 will buffer multi- and broadcast frames for us. rt2x00
> should retrieve the buffered frames via ieee80211_get_buffered_bc after a
> beacon was sent out. Since we already have the beacondone callback that is
> called after each beacon we can simply set another flag to trigger the
> buffered frames to be sent out in rt2x00lib_intf_scheduled_iter.
> 
> Signed-off-by: Helmut Schaa <helmut.schaa at googlemail.com>
> ---
> 
> I'm not sure if it is enough to send the buffered frames from within the
> workqueue as 802.11 tells us:
> 
> "After a DTIM, the AP shall send out the buffered broadcast/multicast MSDUs
> using normal frame transmission rules, before transmitting any unicast frames."
> 
> But even in interrupt context I don't think we can ensure that no unicast
> frames are sent out before the buffered frames? Any ideas?
> 
> Could we put the buffered frames in a different queue? Maybe the mgmt queue?
> 
> However, this patch at least sends multicast and broadcast frames out after
> a DTIM beacon. That's better then not sening them out at all, right?
> 
> Helmut
> 
>  drivers/net/wireless/rt2x00/rt2400pci.c |    2 +-
>  drivers/net/wireless/rt2x00/rt2500pci.c |    2 +-
>  drivers/net/wireless/rt2x00/rt2800pci.c |    2 +-
>  drivers/net/wireless/rt2x00/rt2x00.h    |    4 +++-
>  drivers/net/wireless/rt2x00/rt2x00dev.c |   20 ++++++++++++++++++--
>  drivers/net/wireless/rt2x00/rt2x00mac.c |    2 +-
>  drivers/net/wireless/rt2x00/rt61pci.c   |    2 +-
>  7 files changed, 26 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
> index 1eb882e..ca80b60 100644
> --- a/drivers/net/wireless/rt2x00/rt2400pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2400pci.c
> @@ -1261,7 +1261,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
>  	 * 1 - Beacon timer expired interrupt.
>  	 */
>  	if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
> -		rt2x00lib_beacondone(rt2x00dev);
> +		rt2x00lib_beacondone(rt2x00dev, true);
>  
>  	/*
>  	 * 2 - Rx ring done interrupt.
> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
> index a29cb21..49ec41e 100644
> --- a/drivers/net/wireless/rt2x00/rt2500pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2500pci.c
> @@ -1397,7 +1397,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
>  	 * 1 - Beacon timer expired interrupt.
>  	 */
>  	if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
> -		rt2x00lib_beacondone(rt2x00dev);
> +		rt2x00lib_beacondone(rt2x00dev, true);
>  
>  	/*
>  	 * 2 - Rx ring done interrupt.
> diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
> index d51a080..a84e80b 100644
> --- a/drivers/net/wireless/rt2x00/rt2800pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2800pci.c
> @@ -945,7 +945,7 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
>  	 * Current beacon was sent out, fetch the next one
>  	 */
>  	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
> -		rt2x00lib_beacondone(rt2x00dev);
> +		rt2x00lib_beacondone(rt2x00dev, true);
>  
>  	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
>  		rt2800pci_wakeup(rt2x00dev);
> diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
> index e7acc6a..7523797 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00.h
> @@ -373,6 +373,7 @@ struct rt2x00_intf {
>  	 */
>  	unsigned int delayed_flags;
>  #define DELAYED_UPDATE_BEACON		0x00000001
> +#define DELAYED_SEND_BUFFERED_BC	0x00000002
>  
>  	/*
>  	 * Software sequence counter, this is only required
> @@ -1053,7 +1054,8 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
>  /*
>   * Interrupt context handlers.
>   */
> -void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
> +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev,
> +			  bool send_buffered_bc);
>  void rt2x00lib_txdone(struct queue_entry *entry,
>  		      struct txdone_entry_desc *txdesc);
>  void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
> diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
> index e684698..0456f8d 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00dev.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
> @@ -124,6 +124,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
>  {
>  	struct rt2x00_dev *rt2x00dev = data;
>  	struct rt2x00_intf *intf = vif_to_intf(vif);
> +	struct sk_buff *skb;
>  	int delayed_flags;
>  
>  	/*
> @@ -147,6 +148,18 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
>  	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
>  		return;
>  
> +	/*
> +	 * Send out buffered broad- and multicast frames when
> +	 * DELAYED_SEND_BUFFERED_BC is set.
> +	 */
> +	if (delayed_flags & DELAYED_SEND_BUFFERED_BC) {
> +		skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
> +		while (skb) {
> +			rt2x00mac_tx(rt2x00dev->hw, skb);
> +			skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
> +		}	
> +	}
> +
>  	if (delayed_flags & DELAYED_UPDATE_BEACON)
>  		rt2x00queue_update_beacon(rt2x00dev, vif, true);
>  }

Do we really need this additional flag?
I guess the flag is only disabled when beaconing is enabled. What are the chances
that then there are buffered bc/mc frames already. Wouldn't the while-loop be a
nop in that case?

Adding the boolean to the beacondone function and this flag seems like a lot of
overkill for a situation that might not happen in the first place.


> @@ -172,6 +185,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
>  				      struct ieee80211_vif *vif)
>  {
>  	struct rt2x00_intf *intf = vif_to_intf(vif);
> +	bool send_buffered_bc = *(bool *)data;
>  
>  	if (vif->type != NL80211_IFTYPE_AP &&
>  	    vif->type != NL80211_IFTYPE_ADHOC &&
> @@ -181,17 +195,19 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
>  
>  	spin_lock(&intf->lock);
>  	intf->delayed_flags |= DELAYED_UPDATE_BEACON;
> +	if (send_buffered_bc)
> +		intf->delayed_flags |= DELAYED_SEND_BUFFERED_BC;
>  	spin_unlock(&intf->lock);
>  }
>  
> -void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
> +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev, bool send_buffered_bc)
>  {
>  	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
>  		return;
>  
>  	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
>  						   rt2x00lib_beacondone_iter,
> -						   rt2x00dev);
> +						   &send_buffered_bc);
>  
>  	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
>  }
> diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
> index abbd857..7813f39 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00mac.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
> @@ -435,7 +435,7 @@ int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
>  {
>  	struct rt2x00_dev *rt2x00dev = hw->priv;
>  
> -	rt2x00lib_beacondone(rt2x00dev);
> +	rt2x00lib_beacondone(rt2x00dev, false);
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
> index ee7d434..25239ce 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.c
> +++ b/drivers/net/wireless/rt2x00/rt61pci.c
> @@ -2204,7 +2204,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
>  	 * 5 - Beacon done interrupt.
>  	 */
>  	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
> -		rt2x00lib_beacondone(rt2x00dev);
> +		rt2x00lib_beacondone(rt2x00dev, true);
>  
>  	return IRQ_HANDLED;
>  }




More information about the users mailing list