diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 11:47:58 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 11:47:58 -0700 | 
| commit | 6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7 (patch) | |
| tree | 8f3892fc44f1e403675a6d7e88fda5c70e56ee4c /drivers/net/wireless/rt2x00/rt2x00dev.c | |
| parent | 5abd9ccced7a726c817dd6b5b96bc933859138d1 (diff) | |
| parent | 3ff1c25927e3af61c6bf0e4ed959504058ae4565 (diff) | |
| download | olio-linux-3.10-6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7.tar.xz olio-linux-3.10-6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1443 commits)
  phy/marvell: add 88ec048 support
  igb: Program MDICNFG register prior to PHY init
  e1000e: correct MAC-PHY interconnect register offset for 82579
  hso: Add new product ID
  can: Add driver for esd CAN-USB/2 device
  l2tp: fix export of header file for userspace
  can-raw: Fix skb_orphan_try handling
  Revert "net: remove zap_completion_queue"
  net: cleanup inclusion
  phy/marvell: add 88e1121 interface mode support
  u32: negative offset fix
  net: Fix a typo from "dev" to "ndev"
  igb: Use irq_synchronize per vector when using MSI-X
  ixgbevf: fix null pointer dereference due to filter being set for VLAN 0
  e1000e: Fix irq_synchronize in MSI-X case
  e1000e: register pm_qos request on hardware activation
  ip_fragment: fix subtracting PPPOE_SES_HLEN from mtu twice
  net: Add getsockopt support for TCP thin-streams
  cxgb4: update driver version
  cxgb4: add new PCI IDs
  ...
Manually fix up conflicts in:
 - drivers/net/e1000e/netdev.c: due to pm_qos registration
   infrastructure changes
 - drivers/net/phy/marvell.c: conflict between adding 88ec048 support
   and cleaning up the IDs
 - drivers/net/wireless/ipw2x00/ipw2100.c: trivial ipw2100_pm_qos_req
   conflict (registration change vs marking it static)
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 139 | 
1 files changed, 122 insertions, 17 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f20d3eeeea7..585e8166f22 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -70,6 +70,11 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)  	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);  	/* +	 * Start watchdog monitoring. +	 */ +	rt2x00link_start_watchdog(rt2x00dev); + +	/*  	 * Start the TX queues.  	 */  	ieee80211_wake_queues(rt2x00dev->hw); @@ -89,6 +94,11 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)  	rt2x00queue_stop_queues(rt2x00dev);  	/* +	 * Stop watchdog monitoring. +	 */ +	rt2x00link_stop_watchdog(rt2x00dev); + +	/*  	 * Disable RX.  	 */  	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); @@ -168,10 +178,32 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)  /*   * Interrupt context handlers.   */ -static void rt2x00lib_beacondone_iter(void *data, u8 *mac, -				      struct ieee80211_vif *vif) +static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac, +				     struct ieee80211_vif *vif)  { -	struct rt2x00_intf *intf = vif_to_intf(vif); +	struct rt2x00_dev *rt2x00dev = data; +	struct sk_buff *skb; + +	/* +	 * Only AP mode interfaces do broad- and multicast buffering +	 */ +	if (vif->type != NL80211_IFTYPE_AP) +		return; + +	/* +	 * Send out buffered broad- and multicast frames +	 */ +	skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); +	while (skb) { +		rt2x00mac_tx(rt2x00dev->hw, skb); +		skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); +	} +} + +static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac, +					struct ieee80211_vif *vif) +{ +	struct rt2x00_dev *rt2x00dev = data;  	if (vif->type != NL80211_IFTYPE_AP &&  	    vif->type != NL80211_IFTYPE_ADHOC && @@ -179,9 +211,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,  	    vif->type != NL80211_IFTYPE_WDS)  		return; -	spin_lock(&intf->lock); -	intf->delayed_flags |= DELAYED_UPDATE_BEACON; -	spin_unlock(&intf->lock); +	rt2x00queue_update_beacon(rt2x00dev, vif, true);  }  void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) @@ -189,14 +219,37 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)  	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))  		return; -	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, -						   rt2x00lib_beacondone_iter, -						   rt2x00dev); +	/* send buffered bc/mc frames out for every bssid */ +	ieee80211_iterate_active_interfaces(rt2x00dev->hw, +					    rt2x00lib_bc_buffer_iter, +					    rt2x00dev); +	/* +	 * Devices with pre tbtt interrupt don't need to update the beacon +	 * here as they will fetch the next beacon directly prior to +	 * transmission. +	 */ +	if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags)) +		return; -	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); +	/* fetch next beacon */ +	ieee80211_iterate_active_interfaces(rt2x00dev->hw, +					    rt2x00lib_beaconupdate_iter, +					    rt2x00dev);  }  EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); +void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) +{ +	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) +		return; + +	/* fetch next beacon */ +	ieee80211_iterate_active_interfaces(rt2x00dev->hw, +					    rt2x00lib_beaconupdate_iter, +					    rt2x00dev); +} +EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); +  void rt2x00lib_txdone(struct queue_entry *entry,  		      struct txdone_entry_desc *txdesc)  { @@ -216,6 +269,16 @@ void rt2x00lib_txdone(struct queue_entry *entry,  	rt2x00queue_unmap_skb(rt2x00dev, entry->skb);  	/* +	 * Remove the extra tx headroom from the skb. +	 */ +	skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom); + +	/* +	 * Signal that the TX descriptor is no longer in the skb. +	 */ +	skbdesc->flags &= ~SKBDESC_DESC_IN_SKB; + +	/*  	 * Remove L2 padding which was added during  	 */  	if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) @@ -224,7 +287,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,  	/*  	 * If the IV/EIV data was stripped from the frame before it was  	 * passed to the hardware, we should now reinsert it again because -	 * mac80211 will expect the the same data to be present it the +	 * mac80211 will expect the same data to be present it the  	 * frame as it was passed to us.  	 */  	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) @@ -241,8 +304,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,  	 */  	success =  	    test_bit(TXDONE_SUCCESS, &txdesc->flags) || -	    test_bit(TXDONE_UNKNOWN, &txdesc->flags) || -	    test_bit(TXDONE_FALLBACK, &txdesc->flags); +	    test_bit(TXDONE_UNKNOWN, &txdesc->flags);  	/*  	 * Update TX statistics. @@ -264,11 +326,22 @@ void rt2x00lib_txdone(struct queue_entry *entry,  	/*  	 * Frame was send with retries, hardware tried  	 * different rates to send out the frame, at each -	 * retry it lowered the rate 1 step. +	 * retry it lowered the rate 1 step except when the +	 * lowest rate was used.  	 */  	for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) {  		tx_info->status.rates[i].idx = rate_idx - i;  		tx_info->status.rates[i].flags = rate_flags; + +		if (rate_idx - i == 0) { +			/* +			 * The lowest rate (index 0) was used until the +			 * number of max retries was reached. +			 */ +			tx_info->status.rates[i].count = retry_rates - i; +			i++; +			break; +		}  		tx_info->status.rates[i].count = 1;  	}  	if (i < (IEEE80211_TX_MAX_RATES - 1)) @@ -281,6 +354,21 @@ void rt2x00lib_txdone(struct queue_entry *entry,  			rt2x00dev->low_level_stats.dot11ACKFailureCount++;  	} +	/* +	 * Every single frame has it's own tx status, hence report +	 * every frame as ampdu of size 1. +	 * +	 * TODO: if we can find out how many frames were aggregated +	 * by the hw we could provide the real ampdu_len to mac80211 +	 * which would allow the rc algorithm to better decide on +	 * which rates are suitable. +	 */ +	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { +		tx_info->flags |= IEEE80211_TX_STAT_AMPDU; +		tx_info->status.ampdu_len = 1; +		tx_info->status.ampdu_ack_len = success ? 1 : 0; +	} +  	if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {  		if (success)  			rt2x00dev->low_level_stats.dot11RTSSuccessCount++; @@ -295,9 +383,17 @@ void rt2x00lib_txdone(struct queue_entry *entry,  	 * send the status report back.  	 */  	if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) -		ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); +		/* +		 * Only PCI and SOC devices process the tx status in process +		 * context. Hence use ieee80211_tx_status for PCI and SOC +		 * devices and stick to ieee80211_tx_status_irqsafe for USB. +		 */ +		if (rt2x00_is_usb(rt2x00dev)) +			ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); +		else +			ieee80211_tx_status(rt2x00dev->hw, entry->skb);  	else -		dev_kfree_skb_irq(entry->skb); +		dev_kfree_skb_any(entry->skb);  	/*  	 * Make this entry available for reuse. @@ -444,7 +540,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,  	 */  	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);  	memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); -	ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); + +	/* +	 * Currently only PCI and SOC devices handle rx interrupts in process +	 * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni +	 * for PCI and SOC devices. +	 */ +	if (rt2x00_is_usb(rt2x00dev)) +		ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); +	else +		ieee80211_rx_ni(rt2x00dev->hw, entry->skb);  	/*  	 * Replace the skb with the freshly allocated one.  |