Please pull 'upstream' branch of rt2x00
Hi John,
Here is the latest rt2x00 update.
Lots of new features, optimizations and cleanups.
Ivo
---
The following changes since commit 30b5741a6880688c4540c8f80f90371f42b05a63:
Winkler, Tomas (1):
iwl3945: use iwl_rb_status
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/ivd/rt2x00.git/ upstream
Andrey Yurovsky (1):
rt2x00: Add mesh support
Ivo van Doorn (14):
rt2x00: Implement Powersaving
rt2x00: Move link tuning into seperate file
rt2x00: Reduce calls to bbp_read()
rt2x00: Restrict interface between rt2x00link and drivers
rt2x00: Add RFKILL support to rt2500usb and rt73usb
rt2x00: Rename CONFIG_CRYPTO_COPY_IV
rt2x00: Implement WDS support
rt2x00: Split EEPROM_NIC_TX_RX_FIXED
rt2x00: Move code into seperate functions
rt2x00: Remove ENTRY_TXD_OFDM_RATE
rt2x00: Allow drivers to pass the noise value during rxdone
rt2x00: Introduce RXDONE_SIGNAL_MASK mask
rt2x00: Fix segementation fault
rt2x00: Release rt2x00 2.3.0
drivers/net/wireless/rt2x00/Makefile | 1 + drivers/net/wireless/rt2x00/rt2400pci.c | 60 +++- drivers/net/wireless/rt2x00/rt2500pci.c | 88 ++++-- drivers/net/wireless/rt2x00/rt2500usb.c | 58 ++++- drivers/net/wireless/rt2x00/rt2500usb.h | 8 + drivers/net/wireless/rt2x00/rt2x00.h | 131 +++------ drivers/net/wireless/rt2x00/rt2x00config.c | 7 +- drivers/net/wireless/rt2x00/rt2x00crypto.c | 13 +- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 322 ++------------------ drivers/net/wireless/rt2x00/rt2x00lib.h | 87 +++++- drivers/net/wireless/rt2x00/rt2x00link.c | 461 ++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 42 ++- drivers/net/wireless/rt2x00/rt2x00queue.c | 193 ++++++------ drivers/net/wireless/rt2x00/rt2x00queue.h | 15 +- drivers/net/wireless/rt2x00/rt2x00reg.h | 10 + drivers/net/wireless/rt2x00/rt2x00usb.c | 6 +- drivers/net/wireless/rt2x00/rt61pci.c | 144 +++++---- drivers/net/wireless/rt2x00/rt61pci.h | 7 +- drivers/net/wireless/rt2x00/rt73usb.c | 134 ++++++--- drivers/net/wireless/rt2x00/rt73usb.h | 13 + 21 files changed, 1138 insertions(+), 666 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2x00link.c
PATCH 1/15 rt2x00: Implement Powersaving
Listen to IEEE80211_CONF_PS to determine if the device should drop into powersaving mode. This feature depends on the dynamic power save functionality in mac80211.
--- drivers/net/wireless/rt2x00/rt2400pci.c | 28 ++++++++++++++++ drivers/net/wireless/rt2x00/rt2500pci.c | 28 ++++++++++++++++ drivers/net/wireless/rt2x00/rt2500usb.c | 28 ++++++++++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 53 ++++++++++++++++++++++++++---- drivers/net/wireless/rt2x00/rt61pci.h | 4 ++ drivers/net/wireless/rt2x00/rt73usb.c | 40 +++++++++++++++++++++++ 6 files changed, 174 insertions(+), 7 deletions(-)
drivers/net/wireless/rt2x00/rt2400pci.c +28 -0
@@ -524,6 +524,32 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00pci_register_write (rt2x00dev,CSR12 , reg); } +static void rt2400pci_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00pci_register_read (rt2x00dev,CSR20 , ®); +rt2x00_set_field32 (®,CSR20_DELAY_AFTER_TBCN , + (libconf->conf->beacon_int -20 ) *16 ); +rt2x00_set_field32 (®,CSR20_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,0 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,1 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + } + + rt2x00dev->ops->lib->set_device_state (rt2x00dev, state); +} +static void rt2400pci_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)
@@ -537,6 +563,8 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,rt2400pci_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt2400pci_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt2400pci_config_ps (rt2x00dev, libconf); } static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
drivers/net/wireless/rt2x00/rt2500pci.c +28 -0
@@ -573,6 +573,32 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00pci_register_write (rt2x00dev,CSR12 , reg); } +static void rt2500pci_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00pci_register_read (rt2x00dev,CSR20 , ®); +rt2x00_set_field32 (®,CSR20_DELAY_AFTER_TBCN , + (libconf->conf->beacon_int -20 ) *16 ); +rt2x00_set_field32 (®,CSR20_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,0 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,1 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + } + + rt2x00dev->ops->lib->set_device_state (rt2x00dev, state); +} +static void rt2500pci_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)
@@ -588,6 +614,8 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,rt2500pci_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt2500pci_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt2500pci_config_ps (rt2x00dev, libconf); }/*
drivers/net/wireless/rt2x00/rt2500usb.c +28 -0
@@ -634,6 +634,32 @@ static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,rt2500usb_register_write (rt2x00dev,TXRX_CSR18 , reg); } +static void rt2500usb_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u16 reg; + +if (state ==STATE_SLEEP ) { +rt2500usb_register_read (rt2x00dev,MAC_CSR18 , ®); +rt2x00_set_field16 (®,MAC_CSR18_DELAY_AFTER_BEACON , + libconf->conf->beacon_int -20 ); +rt2x00_set_field16 (®,MAC_CSR18_BEACONS_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field16 (®,MAC_CSR18_AUTO_WAKE ,0 ); +rt2500usb_register_write (rt2x00dev,MAC_CSR18 , reg); + +rt2x00_set_field16 (®,MAC_CSR18_AUTO_WAKE ,1 ); +rt2500usb_register_write (rt2x00dev,MAC_CSR18 , reg); + } + + rt2x00dev->ops->lib->set_device_state (rt2x00dev, state); +} +static void rt2500usb_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)
@@ -647,6 +673,8 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, libconf->conf->power_level);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt2500usb_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt2500usb_config_ps (rt2x00dev, libconf); }/*
drivers/net/wireless/rt2x00/rt61pci.c +46 -7
77 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt61pci.h +4 -0
@@ -88,8 +88,10 @@/* * SOFT_RESET_CSR +* FORCE_CLOCK_ON: Host force MAC clock ON */ #define SOFT_RESET_CSR 0x0010 +#define SOFT_RESET_CSR_FORCE_CLOCK_ON FIELD32(0x00000002)/* * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register.
@@ -1054,8 +1056,10 @@ struct hw_pairwise_ta_entry {/* * IO_CNTL_CSR +* RF_PS: Set RF interface value to power save */ #define IO_CNTL_CSR 0x3498 +#define IO_CNTL_CSR_RF_PS FIELD32(0x00000004)/* * UART_INT_SOURCE_CSR
drivers/net/wireless/rt2x00/rt73usb.c +40 -0
@@ -844,6 +844,44 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00usb_register_write (rt2x00dev,TXRX_CSR9 , reg); } +static void rt73usb_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00usb_register_read (rt2x00dev,MAC_CSR11 , ®); +rt2x00_set_field32 (®,MAC_CSR11_DELAY_AFTER_TBCN , + libconf->conf->beacon_int -10 ); +rt2x00_set_field32 (®,MAC_CSR11_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); +rt2x00_set_field32 (®,MAC_CSR11_WAKEUP_LATENCY ,5 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,0 ); +rt2x00usb_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,1 ); +rt2x00usb_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00usb_vendor_request_sw (rt2x00dev,USB_DEVICE_MODE ,0 , +USB_MODE_SLEEP ,REGISTER_TIMEOUT ); + }else { +rt2x00usb_vendor_request_sw (rt2x00dev,USB_DEVICE_MODE ,0 , +USB_MODE_WAKEUP ,REGISTER_TIMEOUT ); + +rt2x00usb_register_read (rt2x00dev,MAC_CSR11 , ®); +rt2x00_set_field32 (®,MAC_CSR11_DELAY_AFTER_TBCN ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_TBCN_BEFORE_WAKEUP ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_WAKEUP_LATENCY ,0 ); +rt2x00usb_register_write (rt2x00dev,MAC_CSR11 , reg); + } +} +static void rt73usb_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)
@@ -861,6 +899,8 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev,rt73usb_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt73usb_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt73usb_config_ps (rt2x00dev, libconf); }/*
Signature · 1 line
1.5.6.1
PATCH 2/15 rt2x00: Move link tuning into seperate file
Move link and antenna tuning into a seperate file named rt2x00link.c, this makes the interface to the link tuner a lot cleaner.
--- drivers/net/wireless/rt2x00/Makefile | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 29 +-- drivers/net/wireless/rt2x00/rt2x00config.c | 5 +- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 303 +-------------------- drivers/net/wireless/rt2x00/rt2x00lib.h | 81 ++++++- drivers/net/wireless/rt2x00/rt2x00link.c | 402 ++++++++++++++++++++++++++++ 7 files changed, 494 insertions(+), 331 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rt2x00/Makefile +1 -0
@@ -2,6 +2,7 @@ rt2x00lib-y += rt2x00dev.o rt2x00lib-y += rt2x00mac.o rt2x00lib-y += rt2x00config.o rt2x00lib-y += rt2x00queue.o +rt2x00lib-y += rt2x00link.o rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
drivers/net/wireless/rt2x00/rt2x00.h +1 -28
@@ -212,7 +212,7 @@ struct link_qual {* (WEIGHT_TX * tx_percentage) + * (WEIGHT_RX * rx_percentage)) / 100 * -* This value should then be checked to not be greated then 100. +* This value should then be checked to not be greater then 100. */ int rx_percentage;int rx_success;
@@ -318,33 +318,6 @@ static inline int rt2x00_get_link_rssi(struct link *link)return DEFAULT_RSSI ; } -static inline int rt2x00_get_link_ant_rssi (struct link *link) -{ -if (link->ant.rssi_ant && link->qual.rx_success) -return link->ant.rssi_ant; -return DEFAULT_RSSI ; -} - -static inline void rt2x00_reset_link_ant_rssi (struct link *link) -{ - link->ant.rssi_ant =0 ; -} - -static inline int rt2x00_get_link_ant_rssi_history (struct link *link, -enum antenna ant) -{ -if (link->ant.rssi_history[ant -ANTENNA_A ]) -return link->ant.rssi_history[ant -ANTENNA_A ]; -return DEFAULT_RSSI ; -} - -static inline int rt2x00_update_ant_rssi (struct link *link,int rssi) -{ -int old_rssi = link->ant.rssi_history[link->ant.active.rx -ANTENNA_A ]; - link->ant.rssi_history[link->ant.active.rx -ANTENNA_A ] = rssi; -return old_rssi; -} -/* * Interface structure * Per interface configuration details, this structure
drivers/net/wireless/rt2x00/rt2x00config.c +2 -3
@@ -152,8 +152,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,*/ rt2x00dev->ops->lib->config_ant (rt2x00dev, ant); -rt2x00lib_reset_link_tuner (rt2x00dev); -rt2x00_reset_link_ant_rssi (&rt2x00dev->link); +rt2x00link_reset_tuner (rt2x00dev, true);memcpy (active, ant,sizeof (*ant));
@@ -191,7 +190,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,* which means we need to reset the link tuner. */ if (ieee80211_flags &IEEE80211_CONF_CHANGE_CHANNEL ) -rt2x00lib_reset_link_tuner (rt2x00dev); +rt2x00link_reset_tuner (rt2x00dev, false); rt2x00dev->curr_band = conf->channel->band; rt2x00dev->tx_power = conf->power_level;
drivers/net/wireless/rt2x00/rt2x00debug.c +3 -1
@@ -130,9 +130,11 @@ struct rt2x00debug_intf { };void rt2x00debug_update_crypto (struct rt2x00_dev *rt2x00dev, -enum cipher cipher,enum rx_crypto status) +struct rxdone_entry_desc *rxdesc) {struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; +enum cipher cipher = rxdesc->cipher; +enum rx_crypto status = rxdesc->cipher_status;if (cipher ==CIPHER_TKIP_NO_MIC ) cipher =CIPHER_TKIP ;
drivers/net/wireless/rt2x00/rt2x00dev.c +8 -295
349 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt2x00lib.h +77 -4
105 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt2x00link.c new file +402 -0
402 lines not on this page · raw message
Signature · 1 line
1.5.6.1
PATCH 3/15 rt2x00: Reduce calls to bbp_read()
The link_tuner() function will always call bbp_read() at the start of the function. Because this is an indirect register access has some costs attached to it (especially for USB hardware).
We already store the value read from the register into the vgc_level value inside the link structure. Instead of reading from the register we can read that field directly and base the tuner on that value.
This reduces the time the registers are locked with the csr_mutex and speeds up the link_tuner processing.
--- drivers/net/wireless/rt2x00/rt2400pci.c | 27 ++++++++-------- drivers/net/wireless/rt2x00/rt2500pci.c | 50 +++++++++++++++--------------- drivers/net/wireless/rt2x00/rt2x00.h | 9 ++++- drivers/net/wireless/rt2x00/rt61pci.c | 49 +++++++++++++---------------- drivers/net/wireless/rt2x00/rt73usb.c | 52 ++++++++++++++---------------- 5 files changed, 92 insertions(+), 95 deletions(-)
drivers/net/wireless/rt2x00/rt2400pci.c +14 -13
@@ -600,35 +600,36 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, qual->false_cca = bbp; } +static inline void rt2400pci_set_vgc (struct rt2x00_dev *rt2x00dev,u8 vgc_level) +{ +rt2400pci_bbp_write (rt2x00dev,13 , vgc_level); + rt2x00dev->link.vgc_level = vgc_level; + rt2x00dev->link.vgc_level_reg = vgc_level; +} +static void rt2400pci_reset_tuner (struct rt2x00_dev *rt2x00dev) { -rt2400pci_bbp_write (rt2x00dev,13 ,0x08 ); - rt2x00dev->link.vgc_level =0x08 ; +rt2400pci_set_vgc (rt2x00dev,0x08 ); }static void rt2400pci_link_tuner (struct rt2x00_dev *rt2x00dev) { -u8 reg; +struct link *link = &rt2x00dev->link;/* * The link tuner should not run longer then 60 seconds, * and should run once every 2 seconds. */ -if (rt2x00dev->link.count >60 || !(rt2x00dev->link.count &1 )) +if (link->count >60 || !(link->count &1 ))return ;/* * Base r13 link tuning on the false cca count. */ -rt2400pci_bbp_read (rt2x00dev,13 , ®); - -if (rt2x00dev->link.qual.false_cca >512 && reg <0x20 ) { -rt2400pci_bbp_write (rt2x00dev,13 , ++reg); - rt2x00dev->link.vgc_level = reg; - }else if (rt2x00dev->link.qual.false_cca <100 && reg >0x08 ) { -rt2400pci_bbp_write (rt2x00dev,13 , --reg); - rt2x00dev->link.vgc_level = reg; - } +if ((link->qual.false_cca >512 ) && (link->vgc_level <0x20 )) +rt2400pci_set_vgc (rt2x00dev, ++link->vgc_level); +else if ((link->qual.false_cca <100 ) && (link->vgc_level >0x08 )) +rt2400pci_set_vgc (rt2x00dev, --link->vgc_level); }/*
drivers/net/wireless/rt2x00/rt2500pci.c +25 -25
100 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt2x00.h +7 -2
@@ -286,9 +286,14 @@ struct link {struct link_ant ant;/* -* Active VGC level +* Active VGC level (for false cca tuning) */ -int vgc_level; +u8 vgc_level; + +/* +* VGC level as configured in register +*/ +u8 vgc_level_reg;/* * Work structure for scheduling periodic link tuning.
drivers/net/wireless/rt2x00/rt61pci.c +22 -27
100 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt73usb.c +24 -28
103 lines not on this page · raw message
Signature · 1 line
1.5.6.1
PATCH 4/15 rt2x00: Restrict interface between rt2x00link and drivers
Restrict drivers to only access link_qual structure during link tuning. The contents of these fields are for the drivers and all fields are allowed to be changed to values the driver considers correct.
This means that some fields need to be moved outside of this structure to restrict access only to rt2x00link itself. This allows some code to be moved outside of the rt2x00.h header and into rt2x00link.c.
--- drivers/net/wireless/rt2x00/rt2400pci.c | 27 +++--- drivers/net/wireless/rt2x00/rt2500pci.c | 50 +++++----- drivers/net/wireless/rt2x00/rt2500usb.c | 5 +- drivers/net/wireless/rt2x00/rt2x00.h | 99 +++++++------------- drivers/net/wireless/rt2x00/rt2x00link.c | 145 +++++++++++++++++++++--------- drivers/net/wireless/rt2x00/rt61pci.c | 49 +++++----- drivers/net/wireless/rt2x00/rt73usb.c | 57 ++++++------ 7 files changed, 233 insertions(+), 199 deletions(-)
drivers/net/wireless/rt2x00/rt2400pci.c +14 -13
@@ -600,36 +600,37 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, qual->false_cca = bbp; } -static inline void rt2400pci_set_vgc (struct rt2x00_dev *rt2x00dev,u8 vgc_level) +static inline void rt2400pci_set_vgc (struct rt2x00_dev *rt2x00dev, +struct link_qual *qual,u8 vgc_level) {rt2400pci_bbp_write (rt2x00dev,13 , vgc_level); - rt2x00dev->link.vgc_level = vgc_level; - rt2x00dev->link.vgc_level_reg = vgc_level; + qual->vgc_level = vgc_level; + qual->vgc_level_reg = vgc_level; } -static void rt2400pci_reset_tuner (struct rt2x00_dev *rt2x00dev) +static void rt2400pci_reset_tuner (struct rt2x00_dev *rt2x00dev, +struct link_qual *qual) { -rt2400pci_set_vgc (rt2x00dev,0x08 ); +rt2400pci_set_vgc (rt2x00dev, qual,0x08 ); } -static void rt2400pci_link_tuner (struct rt2x00_dev *rt2x00dev) +static void rt2400pci_link_tuner (struct rt2x00_dev *rt2x00dev, +struct link_qual *qual,const u32 count) { -struct link *link = &rt2x00dev->link; -/* * The link tuner should not run longer then 60 seconds, * and should run once every 2 seconds. */ -if (link->count >60 || !(link->count &1 )) +if (count >60 || !(count &1 ))return ;/* * Base r13 link tuning on the false cca count. */ -if ((link->qual.false_cca >512 ) && (link->vgc_level <0x20 )) -rt2400pci_set_vgc (rt2x00dev, ++link->vgc_level); -else if ((link->qual.false_cca <100 ) && (link->vgc_level >0x08 )) -rt2400pci_set_vgc (rt2x00dev, --link->vgc_level); +if ((qual->false_cca >512 ) && (qual->vgc_level <0x20 )) +rt2400pci_set_vgc (rt2x00dev, qual, ++qual->vgc_level); +else if ((qual->false_cca <100 ) && (qual->vgc_level >0x08 )) +rt2400pci_set_vgc (rt2x00dev, qual, --qual->vgc_level); }/*
drivers/net/wireless/rt2x00/rt2500pci.c +25 -25
101 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt2500usb.c +3 -2
@@ -698,7 +698,8 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev, qual->false_cca =rt2x00_get_field16 (reg,STA_CSR3_FALSE_CCA_ERROR ); } -static void rt2500usb_reset_tuner (struct rt2x00_dev *rt2x00dev) +static void rt2500usb_reset_tuner (struct rt2x00_dev *rt2x00dev, +struct link_qual *qual) {u16 eeprom;u16 value;
@@ -719,7 +720,7 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) value =rt2x00_get_field16 (eeprom,EEPROM_BBPTUNE_VGCUPPER );rt2500usb_bbp_write (rt2x00dev,17 , value); - rt2x00dev->link.vgc_level = value; + qual->vgc_level = value; }/*
drivers/net/wireless/rt2x00/rt2x00.h +35 -64
137 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt2x00link.c +102 -43
250 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt61pci.c +25 -24
103 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt73usb.c +29 -28
119 lines not on this page · raw message
Signature · 1 line
1.5.6.1
PATCH 5/15 rt2x00: Add mesh support
From: Andrey Yurovsky <[email protected]>
This adds initial support for Mesh Point mode. For this we tell mac80211 that we support NL80211_IFTYPE_MESH_POINT. We also need to send beacons. mac80211 will configure our RX filter accordingly.
--- drivers/net/wireless/rt2x00/rt2x00config.c | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 11 +++++++---- drivers/net/wireless/rt2x00/rt2x00mac.c | 1 + 3 files changed, 9 insertions(+), 4 deletions(-)
drivers/net/wireless/rt2x00/rt2x00config.c +1 -0
@@ -42,6 +42,7 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,switch (type) {case NL80211_IFTYPE_ADHOC :case NL80211_IFTYPE_AP : +case NL80211_IFTYPE_MESH_POINT : conf.sync =TSF_SYNC_BEACON ;break ;case NL80211_IFTYPE_STATION :
drivers/net/wireless/rt2x00/rt2x00dev.c +7 -4
@@ -190,7 +190,8 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,struct rt2x00_intf *intf =vif_to_intf (vif);if (vif->type !=NL80211_IFTYPE_AP && - vif->type !=NL80211_IFTYPE_ADHOC ) + vif->type !=NL80211_IFTYPE_ADHOC && + vif->type !=NL80211_IFTYPE_MESH_POINT )return ;/*
@@ -782,7 +783,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)if (rt2x00dev->ops->bcn->entry_num >0 ) rt2x00dev->hw->wiphy->interface_modes |=BIT (NL80211_IFTYPE_ADHOC ) | -BIT (NL80211_IFTYPE_AP ); +BIT (NL80211_IFTYPE_AP ) | +BIT (NL80211_IFTYPE_MESH_POINT );/* * Let the driver probe the device to detect the capabilities.
@@ -937,10 +939,11 @@ static void rt2x00lib_resume_intf(void *data, u8 *mac,/* -* Master or Ad-hoc mode require a new beacon update. +* AP, Ad-hoc, and Mesh Point mode require a new beacon update. */ if (vif->type ==NL80211_IFTYPE_AP || - vif->type ==NL80211_IFTYPE_ADHOC ) + vif->type ==NL80211_IFTYPE_ADHOC || + vif->type ==NL80211_IFTYPE_MESH_POINT ) intf->delayed_flags |=DELAYED_UPDATE_BEACON ;spin_unlock (&intf->lock);
drivers/net/wireless/rt2x00/rt2x00mac.c +1 -0
@@ -226,6 +226,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,break ;case NL80211_IFTYPE_STATION :case NL80211_IFTYPE_ADHOC : +case NL80211_IFTYPE_MESH_POINT :/* * We don't support mixed combinations of * sta and ap interfaces.
Signature · 1 line
1.5.6.1
PATCH 6/15 rt2x00: Add RFKILL support to rt2500usb and rt73usb
Some very rare Ralink USB hardware exists which features the RFKILL switch on the USB stick.
This patch adds the EEPROM check function to see if RFKILL is supported and the polling function to rt2500usb and rt73usb in order to support RFKILL for that hardware.
--- drivers/net/wireless/rt2x00/rt2500usb.c | 21 +++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2500usb.h | 8 ++++++++ drivers/net/wireless/rt2x00/rt73usb.c | 21 +++++++++++++++++++++ drivers/net/wireless/rt2x00/rt73usb.h | 13 +++++++++++++ 4 files changed, 63 insertions(+), 0 deletions(-)
drivers/net/wireless/rt2x00/rt2500usb.c +21 -0
@@ -280,6 +280,18 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { };#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +#ifdef CONFIG_RT2X00_LIB_RFKILL +static int rt2500usb_rfkill_poll (struct rt2x00_dev *rt2x00dev) +{ +u16 reg; + +rt2500usb_register_read (rt2x00dev,MAC_CSR19 , ®); +return rt2x00_get_field32 (reg,MAC_CSR19_BIT7 ); +} +#else +#define rt2500usb_rfkill_poll NULL +#endif /* CONFIG_RT2X00_LIB_RFKILL */ +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500usb_brightness_set (struct led_classdev *led_cdev,enum led_brightness brightness)
@@ -1606,6 +1618,14 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)#endif /* CONFIG_RT2X00_LIB_LEDS */ /* +* Detect if this device has an hardware controlled radio. +*/ +#ifdef CONFIG_RT2X00_LIB_RFKILL +if (rt2x00_get_field16 (eeprom,EEPROM_ANTENNA_HARDWARE_RADIO )) +__set_bit (CONFIG_SUPPORT_HW_BUTTON , &rt2x00dev->flags); +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + +/* * Check if the BBP tuning should be disabled. */ rt2x00_eeprom_read (rt2x00dev,EEPROM_NIC , &eeprom);
@@ -1911,6 +1931,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .uninitialize = rt2x00usb_uninitialize, .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt2500usb_set_device_state, + .rfkill_poll = rt2500usb_rfkill_poll, .link_stats = rt2500usb_link_stats, .reset_tuner = rt2500usb_reset_tuner, .link_tuner = rt2500usb_link_tuner,
drivers/net/wireless/rt2x00/rt2500usb.h +8 -0
@@ -189,6 +189,14 @@* MAC_CSR19: GPIO control register. */ #define MAC_CSR19 0x0426 +#define MAC_CSR19_BIT0 FIELD32(0x0001) +#define MAC_CSR19_BIT1 FIELD32(0x0002) +#define MAC_CSR19_BIT2 FIELD32(0x0004) +#define MAC_CSR19_BIT3 FIELD32(0x0008) +#define MAC_CSR19_BIT4 FIELD32(0x0010) +#define MAC_CSR19_BIT5 FIELD32(0x0020) +#define MAC_CSR19_BIT6 FIELD32(0x0040) +#define MAC_CSR19_BIT7 FIELD32(0x0080)/* * MAC_CSR20: LED control register.
drivers/net/wireless/rt2x00/rt73usb.c +21 -0
@@ -186,6 +186,18 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { };#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +#ifdef CONFIG_RT2X00_LIB_RFKILL +static int rt73usb_rfkill_poll (struct rt2x00_dev *rt2x00dev) +{ +u32 reg; + +rt2x00usb_register_read (rt2x00dev,MAC_CSR13 , ®); +return rt2x00_get_field32 (reg,MAC_CSR13_BIT7 ); +} +#else +#define rt73usb_rfkill_poll NULL +#endif /* CONFIG_RT2X00_LIB_RFKILL */ +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt73usb_brightness_set (struct led_classdev *led_cdev,enum led_brightness brightness)
@@ -1855,6 +1867,14 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)__set_bit (CONFIG_FRAME_TYPE , &rt2x00dev->flags);/* +* Detect if this device has an hardware controlled radio. +*/ +#ifdef CONFIG_RT2X00_LIB_RFKILL +if (rt2x00_get_field16 (eeprom,EEPROM_ANTENNA_HARDWARE_RADIO )) +__set_bit (CONFIG_SUPPORT_HW_BUTTON , &rt2x00dev->flags); +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + +/* * Read frequency offset. */ rt2x00_eeprom_read (rt2x00dev,EEPROM_FREQ , &eeprom);
@@ -2259,6 +2279,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .uninitialize = rt2x00usb_uninitialize, .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt73usb_set_device_state, + .rfkill_poll = rt73usb_rfkill_poll, .link_stats = rt73usb_link_stats, .reset_tuner = rt73usb_reset_tuner, .link_tuner = rt73usb_link_tuner,
drivers/net/wireless/rt2x00/rt73usb.h +13 -0
@@ -267,6 +267,19 @@ struct hw_pairwise_ta_entry {* MAC_CSR13: GPIO. */ #define MAC_CSR13 0x3034 +#define MAC_CSR13_BIT0 FIELD32(0x00000001) +#define MAC_CSR13_BIT1 FIELD32(0x00000002) +#define MAC_CSR13_BIT2 FIELD32(0x00000004) +#define MAC_CSR13_BIT3 FIELD32(0x00000008) +#define MAC_CSR13_BIT4 FIELD32(0x00000010) +#define MAC_CSR13_BIT5 FIELD32(0x00000020) +#define MAC_CSR13_BIT6 FIELD32(0x00000040) +#define MAC_CSR13_BIT7 FIELD32(0x00000080) +#define MAC_CSR13_BIT8 FIELD32(0x00000100) +#define MAC_CSR13_BIT9 FIELD32(0x00000200) +#define MAC_CSR13_BIT10 FIELD32(0x00000400) +#define MAC_CSR13_BIT11 FIELD32(0x00000800) +#define MAC_CSR13_BIT12 FIELD32(0x00001000)/* * MAC_CSR14: LED control register.
Signature · 1 line
1.5.6.1
PATCH 7/15 rt2x00: Rename CONFIG_CRYPTO_COPY_IV
Quoted 1 line
From
4c3622010fe750be76403ebe4ad53e6d06ac40daMon Sep 17 00:00:00 2001
From: Ivo van Doorn <[email protected]>
Date: Sat, 20 Dec 2008 10:22:25 +0100
Subject: [PATCH] rt2x00: Rename CONFIG_CRYPTO_COPY_IV
CONFIG_CRYPTO_COPY_IV is a bad name since it is part of the driver requirements instead of a configuration option.
--- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
drivers/net/wireless/rt2x00/rt2500usb.c +1 -1
@@ -1897,7 +1897,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)__set_bit (DRIVER_REQUIRE_SCHEDULED , &rt2x00dev->flags);if (!modparam_nohwcrypt) {__set_bit (CONFIG_SUPPORT_HW_CRYPTO , &rt2x00dev->flags); -__set_bit (CONFIG_CRYPTO_COPY_IV , &rt2x00dev->flags); +__set_bit (DRIVER_REQUIRE_COPY_IV , &rt2x00dev->flags); }__set_bit (CONFIG_DISABLE_LINK_TUNING , &rt2x00dev->flags);
drivers/net/wireless/rt2x00/rt2x00.h +1 -1
@@ -586,6 +586,7 @@ enum rt2x00_flags {DRIVER_REQUIRE_ATIM_QUEUE ,DRIVER_REQUIRE_SCHEDULED ,DRIVER_REQUIRE_DMA , + DRIVER_REQUIRE_COPY_IV,/* * Driver features
@@ -602,7 +603,6 @@ enum rt2x00_flags {CONFIG_EXTERNAL_LNA_BG ,CONFIG_DOUBLE_ANTENNA , CONFIG_DISABLE_LINK_TUNING, - CONFIG_CRYPTO_COPY_IV, };/*
drivers/net/wireless/rt2x00/rt2x00queue.c +1 -1
@@ -402,7 +402,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)*/ if (test_bit (ENTRY_TXD_ENCRYPT , &txdesc.flags) && !test_bit (ENTRY_TXD_ENCRYPT_IV , &txdesc.flags)) { -if (test_bit (CONFIG_CRYPTO_COPY_IV , &queue->rt2x00dev->flags)) +if (test_bit (DRIVER_REQUIRE_COPY_IV , &queue->rt2x00dev->flags))rt2x00crypto_tx_copy_iv (skb, iv_len);else rt2x00crypto_tx_remove_iv (skb, iv_len);
Signature · 1 line
1.5.6.1
PATCH 8/15 rt2x00: Implement WDS support
WDS support should be very easy to handle, mac80211 handles everything for us, so all that is needed is to set the support flags and handle it in the add_interface() callback.
--- drivers/net/wireless/rt2x00/rt2x00config.c | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 9 ++++++--- drivers/net/wireless/rt2x00/rt2x00mac.c | 1 + 3 files changed, 8 insertions(+), 3 deletions(-)
drivers/net/wireless/rt2x00/rt2x00config.c +1 -0
@@ -43,6 +43,7 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,case NL80211_IFTYPE_ADHOC :case NL80211_IFTYPE_AP :case NL80211_IFTYPE_MESH_POINT : +case NL80211_IFTYPE_WDS : conf.sync =TSF_SYNC_BEACON ;break ;case NL80211_IFTYPE_STATION :
drivers/net/wireless/rt2x00/rt2x00dev.c +6 -3
@@ -191,7 +191,8 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,if (vif->type !=NL80211_IFTYPE_AP && vif->type !=NL80211_IFTYPE_ADHOC && - vif->type !=NL80211_IFTYPE_MESH_POINT ) + vif->type !=NL80211_IFTYPE_MESH_POINT && + vif->type !=NL80211_IFTYPE_WDS )return ;/*
@@ -784,7 +785,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->wiphy->interface_modes |=BIT (NL80211_IFTYPE_ADHOC ) |BIT (NL80211_IFTYPE_AP ) | -BIT (NL80211_IFTYPE_MESH_POINT ); +BIT (NL80211_IFTYPE_MESH_POINT ) | +BIT (NL80211_IFTYPE_WDS );/* * Let the driver probe the device to detect the capabilities.
@@ -943,7 +945,8 @@ static void rt2x00lib_resume_intf(void *data, u8 *mac,*/ if (vif->type ==NL80211_IFTYPE_AP || vif->type ==NL80211_IFTYPE_ADHOC || - vif->type ==NL80211_IFTYPE_MESH_POINT ) + vif->type ==NL80211_IFTYPE_MESH_POINT || + vif->type ==NL80211_IFTYPE_WDS ) intf->delayed_flags |=DELAYED_UPDATE_BEACON ;spin_unlock (&intf->lock);
drivers/net/wireless/rt2x00/rt2x00mac.c +1 -0
@@ -227,6 +227,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,case NL80211_IFTYPE_STATION :case NL80211_IFTYPE_ADHOC :case NL80211_IFTYPE_MESH_POINT : +case NL80211_IFTYPE_WDS :/* * We don't support mixed combinations of * sta and ap interfaces.
Signature · 1 line
1.5.6.1
PATCH 9/15 rt2x00: Split EEPROM_NIC_TX_RX_FIXED
The 2 bits in EEPROM_NIC_TX_RX_FIXED each influence a different antenna. We might as well split the definition and directly read the correct bit.
--- drivers/net/wireless/rt2x00/rt61pci.c | 25 ++++++------------------- drivers/net/wireless/rt2x00/rt61pci.h | 3 ++- 2 files changed, 8 insertions(+), 20 deletions(-)
drivers/net/wireless/rt2x00/rt61pci.c +6 -19
@@ -2232,7 +2232,8 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)if (word ==0xffff ) {rt2x00_set_field16 (&word,EEPROM_NIC_ENABLE_DIVERSITY ,0 );rt2x00_set_field16 (&word,EEPROM_NIC_TX_DIVERSITY ,0 ); -rt2x00_set_field16 (&word,EEPROM_NIC_TX_RX_FIXED ,0 ); +rt2x00_set_field16 (&word,EEPROM_NIC_RX_FIXED ,0 ); +rt2x00_set_field16 (&word,EEPROM_NIC_TX_FIXED ,0 );rt2x00_set_field16 (&word,EEPROM_NIC_EXTERNAL_LNA_BG ,0 );rt2x00_set_field16 (&word,EEPROM_NIC_CARDBUS_ACCEL ,0 );rt2x00_set_field16 (&word,EEPROM_NIC_EXTERNAL_LNA_A ,0 );
@@ -2376,24 +2377,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)*/ if (rt2x00_rf (&rt2x00dev->chip,RF2529 ) && !test_bit (CONFIG_DOUBLE_ANTENNA , &rt2x00dev->flags)) { -switch (rt2x00_get_field16 (eeprom,EEPROM_NIC_TX_RX_FIXED )) { -case 0 : - rt2x00dev->default_ant.tx =ANTENNA_B ; - rt2x00dev->default_ant.rx =ANTENNA_A ; -break ; -case 1 : - rt2x00dev->default_ant.tx =ANTENNA_B ; - rt2x00dev->default_ant.rx =ANTENNA_B ; -break ; -case 2 : - rt2x00dev->default_ant.tx =ANTENNA_A ; - rt2x00dev->default_ant.rx =ANTENNA_A ; -break ; -case 3 : - rt2x00dev->default_ant.tx =ANTENNA_A ; - rt2x00dev->default_ant.rx =ANTENNA_B ; -break ; - } + rt2x00dev->default_ant.rx = +ANTENNA_A +rt2x00_get_field16 (eeprom,EEPROM_NIC_RX_FIXED ); + rt2x00dev->default_ant.tx = +ANTENNA_B -rt2x00_get_field16 (eeprom,EEPROM_NIC_TX_FIXED );if (rt2x00_get_field16 (eeprom,EEPROM_NIC_TX_DIVERSITY )) rt2x00dev->default_ant.tx =ANTENNA_SW_DIVERSITY ;
drivers/net/wireless/rt2x00/rt61pci.h +2 -1
@@ -1190,7 +1190,8 @@ struct hw_pairwise_ta_entry {#define EEPROM_NIC 0x0011#define EEPROM_NIC_ENABLE_DIVERSITY FIELD16(0x0001)#define EEPROM_NIC_TX_DIVERSITY FIELD16(0x0002) -#define EEPROM_NIC_TX_RX_FIXED FIELD16(0x000c) +#define EEPROM_NIC_RX_FIXED FIELD16(0x0004) +#define EEPROM_NIC_TX_FIXED FIELD16(0x0008)#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0010)#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0020)#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0040)
Signature · 1 line
1.5.6.1
PATCH 10/15 rt2x00: Move code into seperate functions
Some functions have grown rapidly in size over the last time, some of those functions (like the rt2x00queue_create_tx_descriptor) will further increase in size soon, so it is best to start cutting it into logical pieces.
--- drivers/net/wireless/rt2x00/rt2x00crypto.c | 13 ++- drivers/net/wireless/rt2x00/rt2x00lib.h | 6 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 40 +++--- drivers/net/wireless/rt2x00/rt2x00queue.c | 191 ++++++++++++++------------- 4 files changed, 137 insertions(+), 113 deletions(-)
drivers/net/wireless/rt2x00/rt2x00crypto.c +12 -1
@@ -49,9 +49,14 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)void rt2x00crypto_create_tx_descriptor (struct queue_entry *entry,struct txentry_desc *txdesc) { +struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;struct ieee80211_tx_info *tx_info =IEEE80211_SKB_CB (entry->skb);struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; +if (!test_bit (CONFIG_SUPPORT_HW_CRYPTO , &rt2x00dev->flags) || + !hw_key || entry->skb->do_not_encrypt) +return ; +__set_bit (ENTRY_TXD_ENCRYPT , &txdesc->flags); txdesc->cipher =rt2x00crypto_key_to_cipher (hw_key);
@@ -69,11 +74,17 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,__set_bit (ENTRY_TXD_ENCRYPT_MMIC , &txdesc->flags); } -unsigned int rt2x00crypto_tx_overhead (struct ieee80211_tx_info *tx_info) +unsigned int rt2x00crypto_tx_overhead (struct rt2x00_dev *rt2x00dev, +struct sk_buff *skb) { +struct ieee80211_tx_info *tx_info =IEEE80211_SKB_CB (skb);struct ieee80211_key_conf *key = tx_info->control.hw_key;unsigned int overhead =0 ; +if (!test_bit (CONFIG_SUPPORT_HW_CRYPTO , &rt2x00dev->flags) || + !key || skb->do_not_encrypt) +return overhead; +/* * Extend frame length to include IV/EIV/ICV/MMIC, * note that these lengths should only be added when
drivers/net/wireless/rt2x00/rt2x00lib.h +4 -2
@@ -293,7 +293,8 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,enum cipher rt2x00crypto_key_to_cipher (struct ieee80211_key_conf *key);void rt2x00crypto_create_tx_descriptor (struct queue_entry *entry,struct txentry_desc *txdesc); -unsigned int rt2x00crypto_tx_overhead (struct ieee80211_tx_info *tx_info); +unsigned int rt2x00crypto_tx_overhead (struct rt2x00_dev *rt2x00dev, +struct sk_buff *skb);void rt2x00crypto_tx_copy_iv (struct sk_buff *skb,unsigned int iv_len);void rt2x00crypto_tx_remove_iv (struct sk_buff *skb,unsigned int iv_len);void rt2x00crypto_tx_insert_iv (struct sk_buff *skb);
@@ -311,7 +312,8 @@ static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, { } -static inline unsigned int rt2x00crypto_tx_overhead (struct ieee80211_tx_info *tx_info) +static inline unsigned int rt2x00crypto_tx_overhead (struct rt2x00_dev *rt2x00dev, +struct sk_buff *skb) {return 0 ; }
drivers/net/wireless/rt2x00/rt2x00mac.c +22 -18
@@ -79,8 +79,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,* RTS/CTS frame should use the length of the frame plus any * encryption overhead that will be added by the hardware. */ -if (!frag_skb->do_not_encrypt) - data_length +=rt2x00crypto_tx_overhead (tx_info); + data_length +=rt2x00crypto_tx_overhead (rt2x00dev, skb);if (tx_info->control.rates[0 ].flags &IEEE80211_TX_RC_USE_CTS_PROTECT ) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
@@ -484,6 +483,24 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,EXPORT_SYMBOL_GPL (rt2x00mac_configure_filter);#ifdef CONFIG_RT2X00_LIB_CRYPTO +static void memcpy_tkip (struct rt2x00lib_crypto *crypto,u8 *key,u8 key_len) +{ +if (key_len >NL80211_TKIP_DATA_OFFSET_ENCR_KEY ) +memcpy (&crypto->key, + &key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY ], +sizeof (crypto->key)); + +if (key_len >NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ) +memcpy (&crypto->tx_mic, + &key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ], +sizeof (crypto->tx_mic)); + +if (key_len >NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ) +memcpy (&crypto->rx_mic, + &key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ], +sizeof (crypto->rx_mic)); +} +int rt2x00mac_set_key (struct ieee80211_hw *hw,enum set_key_cmd cmd,const u8 *local_address,const u8 *address,struct ieee80211_key_conf *key)
@@ -521,22 +538,9 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, crypto.cmd = cmd; crypto.address = address; -if (crypto.cipher ==CIPHER_TKIP ) { -if (key->keylen >NL80211_TKIP_DATA_OFFSET_ENCR_KEY ) -memcpy (&crypto.key, - &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY ], -sizeof (crypto.key)); - -if (key->keylen >NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ) -memcpy (&crypto.tx_mic, - &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ], -sizeof (crypto.tx_mic)); - -if (key->keylen >NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ) -memcpy (&crypto.rx_mic, - &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ], -sizeof (crypto.rx_mic)); - }else +if (crypto.cipher ==CIPHER_TKIP ) +memcpy_tkip (&crypto, &key->key[0 ], key->keylen); +else memcpy (&crypto.key, &key->key[0 ], key->keylen);/*
drivers/net/wireless/rt2x00/rt2x00queue.c +99 -92
228 lines not on this page · raw message
Signature · 1 line
1.5.6.1
PATCH 11/15 rt2x00: Remove ENTRY_TXD_OFDM_RATE
The flag ENTRY_TXD_OFDM_RATE isn't flexible enough to indicate which rate modulation should be used for a frame. This will become a problem when 11n support is added.
Remove the flag and replace it with an enum value which can better indicate the exact rate modulation.
--- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +++++- drivers/net/wireless/rt2x00/rt2x00queue.h | 5 +++-- drivers/net/wireless/rt2x00/rt2x00reg.h | 10 ++++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-)
drivers/net/wireless/rt2x00/rt2500pci.c +1 -1
@@ -1233,7 +1233,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,rt2x00_set_field32 (&word,TXD_W0_TIMESTAMP ,test_bit (ENTRY_TXD_REQ_TIMESTAMP , &txdesc->flags));rt2x00_set_field32 (&word,TXD_W0_OFDM , -test_bit (ENTRY_TXD_OFDM_RATE , &txdesc->flags)); + (txdesc->rate_mode ==RATE_MODE_OFDM ));rt2x00_set_field32 (&word,TXD_W0_CIPHER_OWNER ,1 );rt2x00_set_field32 (&word,TXD_W0_IFS , txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
drivers/net/wireless/rt2x00/rt2500usb.c +1 -1
@@ -1217,7 +1217,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,rt2x00_set_field32 (&word,TXD_W0_TIMESTAMP ,test_bit (ENTRY_TXD_REQ_TIMESTAMP , &txdesc->flags));rt2x00_set_field32 (&word,TXD_W0_OFDM , -test_bit (ENTRY_TXD_OFDM_RATE , &txdesc->flags)); + (txdesc->rate_mode ==RATE_MODE_OFDM ));rt2x00_set_field32 (&word,TXD_W0_NEW_SEQ ,test_bit (ENTRY_TXD_FIRST_FRAGMENT , &txdesc->flags));rt2x00_set_field32 (&word,TXD_W0_IFS , txdesc->ifs);
drivers/net/wireless/rt2x00/rt2x00queue.c +5 -1
@@ -313,9 +313,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, }else txdesc->ifs =IFS_SIFS ; +/* +* Determine rate modulation. +*/ hwrate =rt2x00_get_rate (rate->hw_value); + txdesc->rate_mode =RATE_MODE_CCK ;if (hwrate->flags &DEV_RATE_OFDM ) -__set_bit (ENTRY_TXD_OFDM_RATE , &txdesc->flags); + txdesc->rate_mode =RATE_MODE_OFDM ;/* * Apply TX descriptor handling by components
drivers/net/wireless/rt2x00/rt2x00queue.h +3 -2
@@ -222,7 +222,6 @@ struct txdone_entry_desc {* * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. -* @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. * @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter. * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
@@ -238,7 +237,6 @@ struct txdone_entry_desc {enum txentry_desc_flags {ENTRY_TXD_RTS_FRAME ,ENTRY_TXD_CTS_FRAME , -ENTRY_TXD_OFDM_RATE ,ENTRY_TXD_GENERATE_SEQ ,ENTRY_TXD_FIRST_FRAGMENT ,ENTRY_TXD_MORE_FRAG ,
@@ -263,6 +261,7 @@ enum txentry_desc_flags {* @length_low: PLCP length low word. * @signal: PLCP signal. * @service: PLCP service. +* @rate_mode: Rate mode (See @enum rate_modulation). * @retry_limit: Max number of retries. * @aifs: AIFS value. * @ifs: IFS value.
@@ -282,6 +281,8 @@ struct txentry_desc {u16 signal;u16 service; +u16 rate_mode; +short retry_limit;short aifs;short ifs;
drivers/net/wireless/rt2x00/rt2x00reg.h +10 -0
@@ -125,6 +125,16 @@ enum cipher { };/* +* Rate modulations +*/ +enum rate_modulation { +RATE_MODE_CCK =0 , +RATE_MODE_OFDM =1 , +RATE_MODE_HT_MIX =2 , +RATE_MODE_HT_GREENFIELD =3 , +}; + +/* * Register handlers. * We store the position of a register field inside a field structure, * This will simplify the process of setting and reading a certain field
drivers/net/wireless/rt2x00/rt61pci.c +1 -1
@@ -1847,7 +1847,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,rt2x00_set_field32 (&word,TXD_W0_TIMESTAMP ,test_bit (ENTRY_TXD_REQ_TIMESTAMP , &txdesc->flags));rt2x00_set_field32 (&word,TXD_W0_OFDM , -test_bit (ENTRY_TXD_OFDM_RATE , &txdesc->flags)); + (txdesc->rate_mode ==RATE_MODE_OFDM ));rt2x00_set_field32 (&word,TXD_W0_IFS , txdesc->ifs);rt2x00_set_field32 (&word,TXD_W0_RETRY_MODE ,test_bit (ENTRY_TXD_RETRY_MODE , &txdesc->flags));
drivers/net/wireless/rt2x00/rt73usb.c +1 -1
@@ -1498,7 +1498,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,rt2x00_set_field32 (&word,TXD_W0_TIMESTAMP ,test_bit (ENTRY_TXD_REQ_TIMESTAMP , &txdesc->flags));rt2x00_set_field32 (&word,TXD_W0_OFDM , -test_bit (ENTRY_TXD_OFDM_RATE , &txdesc->flags)); + (txdesc->rate_mode ==RATE_MODE_OFDM ));rt2x00_set_field32 (&word,TXD_W0_IFS , txdesc->ifs);rt2x00_set_field32 (&word,TXD_W0_RETRY_MODE ,test_bit (ENTRY_TXD_RETRY_MODE , &txdesc->flags));
Signature · 1 line
1.5.6.1
PATCH 12/15 Allow drivers to pass the noise value during rxdone
--- drivers/net/wireless/rt2x00/rt2x00dev.c | 1 + drivers/net/wireless/rt2x00/rt2x00queue.h | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-)
drivers/net/wireless/rt2x00/rt2x00dev.c +1 -0
@@ -407,6 +407,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, rx_status->rate_idx = idx; rx_status->qual =rt2x00link_calculate_signal (rt2x00dev, rxdesc.rssi); rx_status->signal = rxdesc.rssi; + rx_status->noise = rxdesc.noise; rx_status->flag = rxdesc.flags; rx_status->antenna = rt2x00dev->link.ant.active.rx;
drivers/net/wireless/rt2x00/rt2x00queue.h +2 -0
@@ -165,6 +165,7 @@ enum rxdone_entry_desc_flags {* @timestamp: RX Timestamp * @signal: Signal of the received frame. * @rssi: RSSI of the received frame. +* @noise: Measured noise during frame reception. * @size: Data size of the received frame. * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
@@ -177,6 +178,7 @@ struct rxdone_entry_desc {u64 timestamp;int signal;int rssi; +int noise;int size;int flags;int dev_flags;
Signature · 1 line
1.5.6.1
PATCH 13/15 rt2x00: Introduce RXDONE_SIGNAL_MASK mask
Improve error message reporting when a frame was received with unknown rate. Instead of using the boolean check if the frame is supposed to be a PLCP value or not, we should add a new mask (RXDONE_SIGNAL_MASK) which returns the type identification for a signal value (i.e. PLCP). At the moment we only have 2 different types, but more will arrive when support for 11n is added.
--- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00queue.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/net/wireless/rt2x00/rt2x00dev.c +2 -2
@@ -392,8 +392,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,if (idx <0 ) {WARNING (rt2x00dev,"Frame received with unrecognized signal," -"signal=0x%.2x, plcp=%d.\n" , rxdesc.signal, - !!(rxdesc.dev_flags &RXDONE_SIGNAL_PLCP )); +"signal=0x%.2x, type=%d.\n" , rxdesc.signal, + (rxdesc.dev_flags &RXDONE_SIGNAL_MASK )); idx =0 ; }
drivers/net/wireless/rt2x00/rt2x00queue.h +8 -0
@@ -158,6 +158,14 @@ enum rxdone_entry_desc_flags { };/** +* RXDONE_SIGNAL_MASK - Define to mask off all &rxdone_entry_desc_flags flags +* except for the RXDONE_SIGNAL_* flags. This is useful to convert the dev_flags +* from &rxdone_entry_desc to a signal value type. +*/ +#define RXDONE_SIGNAL_MASK \ + ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE ) + +/** * struct rxdone_entry_desc: RX Entry descriptor * * Summary of information that has been read from the RX frame descriptor.
Signature · 1 line
1.5.6.1
PATCH 14/15 rt2x00: Fix segementation fault
The queue_end() macro points to 1 position after the queue, which means that if we want to know if queue is at the end of the queue we should first increment the position and then check if it is a valid entry.
This fixes a segmentation fault which only occurs when the device has enough endpoints to provide a dedicated endpoint for all TX queues (which likely won't happen for rt2500usb and rt73usb, but will happen for rt2800usb).
--- drivers/net/wireless/rt2x00/rt2x00usb.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/net/wireless/rt2x00/rt2x00usb.c +3 -3
@@ -434,11 +434,11 @@ static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)if (usb_endpoint_is_bulk_in (ep_desc)) {rt2x00usb_assign_endpoint (rt2x00dev->rx, ep_desc); - }else if (usb_endpoint_is_bulk_out (ep_desc)) { + }else if (usb_endpoint_is_bulk_out (ep_desc) && + (queue !=queue_end (rt2x00dev))) {rt2x00usb_assign_endpoint (queue, ep_desc); + queue =queue_next (queue); -if (queue !=queue_end (rt2x00dev)) - queue =queue_next (queue); tx_ep_desc = ep_desc; } }
Signature · 1 line
1.5.6.1
PATCH 15/15 rt2x00: Release rt2x00 2.3.0
--- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/net/wireless/rt2x00/rt2x00.h +1 -1
@@ -44,7 +44,7 @@/* * Module information. */ -#define DRV_VERSION "2.2.3" +#define DRV_VERSION "2.3.0"#define DRV_PROJECT "http://rt2x00.serialmonkey.com"/*
Signature · 1 line
1.5.6.1
Re: [PATCH 10/15] rt2x00: Move code into seperate functions
In reply to Ivo van DoornHello,
I have a techinical problem with this patch.
It is strangley being cut before it is ended:
I tried it with thunderbird and mutt clients.
It is cutt after :
- */
- if (hwrate->bitrate == 110 && residual <= 30)
- txdesc->service |= 0x80;
- }
-
- txdesc->length_high = (duration >> 8) & 0xff;
- txdesc->length_low = duration & 0xff;
Therfore, I get a "corrupt patch" when trying to apply it Any ideas ?
Davids
Quoted 384 lines · Ivo van Doorn
Some functions have grown rapidly in size over the last time, some of those functions (like the
rt2x00queue_create_tx_descriptor) will further increase in size soon, so it is best to start cutting it into logical pieces.Signed-off-by Ivo van Doorn <[email protected]>--- drivers/net/wireless/rt2x00/rt2x00crypto.c | 13 ++- drivers/net/wireless/rt2x00/rt2x00lib.h | 6 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 40 +++--- drivers/net/wireless/rt2x00/rt2x00queue.c | 191 ++++++++++++++------------- 4 files changed, 137 insertions(+), 113 deletions(-)drivers/net/wireless/rt2x00/rt2x00crypto.c +12
-1@@ -49,9 +49,14 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)void rt2x00crypto_create_tx_descriptor (struct queue_entry *entry,struct txentry_desc *txdesc) { +struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;struct ieee80211_tx_info *tx_info =IEEE80211_SKB_CB (entry->skb);struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; +if (!test_bit (CONFIG_SUPPORT_HW_CRYPTO , &rt2x00dev->flags) || + !hw_key || entry->skb->do_not_encrypt) +return ; +__set_bit (ENTRY_TXD_ENCRYPT , &txdesc->flags); txdesc->cipher =rt2x00crypto_key_to_cipher (hw_key);@@ -69,11 +74,17 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,__set_bit (ENTRY_TXD_ENCRYPT_MMIC , &txdesc->flags); } -unsigned int rt2x00crypto_tx_overhead (struct ieee80211_tx_info *tx_info) +unsigned int rt2x00crypto_tx_overhead (struct rt2x00_dev *rt2x00dev, +struct sk_buff *skb) { +struct ieee80211_tx_info *tx_info =IEEE80211_SKB_CB (skb);struct ieee80211_key_conf *key = tx_info->control.hw_key;unsigned int overhead =0 ; +if (!test_bit (CONFIG_SUPPORT_HW_CRYPTO , &rt2x00dev->flags) || + !key || skb->do_not_encrypt) +return overhead; +/* * Extend frame length to include IV/EIV/ICV/MMIC, * note that these lengths should only be added when drivers/net/wireless/rt2x00/rt2x00lib.h +4
-2@@ -293,7 +293,8 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,enum cipher rt2x00crypto_key_to_cipher (struct ieee80211_key_conf *key);void rt2x00crypto_create_tx_descriptor (struct queue_entry *entry,struct txentry_desc *txdesc); -unsigned int rt2x00crypto_tx_overhead (struct ieee80211_tx_info *tx_info); +unsigned int rt2x00crypto_tx_overhead (struct rt2x00_dev *rt2x00dev, +struct sk_buff *skb);void rt2x00crypto_tx_copy_iv (struct sk_buff *skb,unsigned int iv_len);void rt2x00crypto_tx_remove_iv (struct sk_buff *skb,unsigned int iv_len);void rt2x00crypto_tx_insert_iv (struct sk_buff *skb);@@ -311,7 +312,8 @@ static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, { } -static inline unsigned int rt2x00crypto_tx_overhead (struct ieee80211_tx_info *tx_info) +static inline unsigned int rt2x00crypto_tx_overhead (struct rt2x00_dev *rt2x00dev, +struct sk_buff *skb) {return 0 ; }drivers/net/wireless/rt2x00/rt2x00mac.c +22
-18@@ -79,8 +79,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,* RTS/CTS frame should use the length of the frame plus any * encryption overhead that will be added by the hardware. */ -if (!frag_skb->do_not_encrypt) - data_length +=rt2x00crypto_tx_overhead (tx_info); + data_length +=rt2x00crypto_tx_overhead (rt2x00dev, skb);if (tx_info->control.rates[0 ].flags &IEEE80211_TX_RC_USE_CTS_PROTECT ) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,@@ -484,6 +483,24 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,EXPORT_SYMBOL_GPL (rt2x00mac_configure_filter);#ifdef CONFIG_RT2X00_LIB_CRYPTO +static void memcpy_tkip (struct rt2x00lib_crypto *crypto,u8 *key,u8 key_len) +{ +if (key_len >NL80211_TKIP_DATA_OFFSET_ENCR_KEY ) +memcpy (&crypto->key, + &key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY ], +sizeof (crypto->key)); + +if (key_len >NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ) +memcpy (&crypto->tx_mic, + &key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ], +sizeof (crypto->tx_mic)); + +if (key_len >NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ) +memcpy (&crypto->rx_mic, + &key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ], +sizeof (crypto->rx_mic)); +} +int rt2x00mac_set_key (struct ieee80211_hw *hw,enum set_key_cmd cmd,const u8 *local_address,const u8 *address,struct ieee80211_key_conf *key)@@ -521,22 +538,9 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, crypto.cmd = cmd; crypto.address = address; -if (crypto.cipher ==CIPHER_TKIP ) { -if (key->keylen >NL80211_TKIP_DATA_OFFSET_ENCR_KEY ) -memcpy (&crypto.key, - &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY ], -sizeof (crypto.key)); - -if (key->keylen >NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ) -memcpy (&crypto.tx_mic, - &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ], -sizeof (crypto.tx_mic)); - -if (key->keylen >NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ) -memcpy (&crypto.rx_mic, - &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ], -sizeof (crypto.rx_mic)); - }else +if (crypto.cipher ==CIPHER_TKIP ) +memcpy_tkip (&crypto, &key->key[0 ], key->keylen); +else memcpy (&crypto.key, &key->key[0 ], key->keylen);/* drivers/net/wireless/rt2x00/rt2x00queue.c +99
-93@@ -148,6 +148,95 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)dev_kfree_skb_any (skb); } +static void rt2x00queue_create_tx_descriptor_seq (struct queue_entry *entry, +struct txentry_desc *txdesc) +{ +struct ieee80211_tx_info *tx_info =IEEE80211_SKB_CB (entry->skb); +struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; +struct rt2x00_intf *intf =vif_to_intf (tx_info->control.vif); +unsigned long irqflags; + +if (!(tx_info->flags &IEEE80211_TX_CTL_ASSIGN_SEQ ) || +unlikely (!tx_info->control.vif)) +return ; + +/* +* Hardware should insert sequence counter. +* FIXME: We insert a software sequence counter first for +* hardware that doesn't support hardware sequence counting. +* +* This is wrong because beacons are not getting sequence +* numbers assigned properly. +* +* A secondary problem exists for drivers that cannot toggle +* sequence counting per-frame, since those will override the +* sequence counter given by mac80211. +*/ +spin_lock_irqsave (&intf->seqlock, irqflags); + +if (test_bit (ENTRY_TXD_FIRST_FRAGMENT , &txdesc->flags)) + intf->seqno +=0x10 ; + hdr->seq_ctrl &=cpu_to_le16 (IEEE80211_SCTL_FRAG ); + hdr->seq_ctrl |=cpu_to_le16 (intf->seqno); + +spin_unlock_irqrestore (&intf->seqlock, irqflags); + +__set_bit (ENTRY_TXD_GENERATE_SEQ , &txdesc->flags); +} + +static void rt2x00queue_create_tx_descriptor_plcp (struct queue_entry *entry, +struct txentry_desc *txdesc, +struct ieee80211_rate *rate) +{ +struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; +const struct rt2x00_rate *hwrate =rt2x00_get_rate (rate->hw_value); +unsigned int data_length; +unsigned int duration; +unsigned int residual; + +/* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */ + data_length = entry->skb->len +4 ; + data_length +=rt2x00crypto_tx_overhead (rt2x00dev, entry->skb); + +/* +* PLCP setup +* Length calculation depends on OFDM/CCK rate. +*/ + txdesc->signal = hwrate->plcp; + txdesc->service =0x04 ; + +if (hwrate->flags &DEV_RATE_OFDM ) { + txdesc->length_high = (data_length >>6 ) &0x3f ; + txdesc->length_low = data_length &0x3f ; + }else { +/* +* Convert length to microseconds. +*/ + residual =GET_DURATION_RES (data_length, hwrate->bitrate); + duration =GET_DURATION (data_length, hwrate->bitrate); + +if (residual !=0 ) { + duration++; + +/* +* Check if we need to set the Length Extension +*/ +if (hwrate->bitrate ==110 && residual <=30 ) + txdesc->service |=0x80 ; + } + + txdesc->length_high = (duration >>8 ) &0xff ; + txdesc->length_low = duration &0xff ; + +/* +* When preamble is enabled we should set the +* preamble bit for the signal. +*/ +if (rt2x00_get_rate_preamble (rate->hw_value)) + txdesc->signal |=0x08 ; + } +} +static void rt2x00queue_create_tx_descriptor (struct queue_entry *entry,struct txentry_desc *txdesc) {@@ -157,10 +246,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,struct ieee80211_rate *rate =ieee80211_get_tx_rate (rt2x00dev->hw, tx_info);const struct rt2x00_rate *hwrate; -unsigned int data_length; -unsigned int duration; -unsigned int residual; -unsigned long irqflags;memset (txdesc,0 ,sizeof (*txdesc));@@ -172,27 +257,12 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; -/* Data length + CRC */ - data_length = entry->skb->len +4 ; -/* * Check whether this frame is to be acked. */ if (!(tx_info->flags &IEEE80211_TX_CTL_NO_ACK ))__set_bit (ENTRY_TXD_ACK , &txdesc->flags); -if (test_bit (CONFIG_SUPPORT_HW_CRYPTO , &rt2x00dev->flags) && - !entry->skb->do_not_encrypt) { -/* Apply crypto specific descriptor information */ -rt2x00crypto_create_tx_descriptor (entry, txdesc); - -/* -* Extend frame length to include all encryption overhead -* that will be added by the hardware. -*/ - data_length +=rt2x00crypto_tx_overhead (tx_info); - } -/* * Check if this is a RTS/CTS frame */ @@ -236,86 +306,23 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,* Set ifs to IFS_SIFS when the this is not the first fragment, * or this fragment came after RTS/CTS. */ -if (test_bit (ENTRY_TXD_RTS_FRAME , &txdesc->flags)) { - txdesc->ifs =IFS_SIFS ; - }else if (tx_info->flags &IEEE80211_TX_CTL_FIRST_FRAGMENT ) { +if ((tx_info->flags &IEEE80211_TX_CTL_FIRST_FRAGMENT ) && + !test_bit (ENTRY_TXD_RTS_FRAME , &txdesc->flags)) {__set_bit (ENTRY_TXD_FIRST_FRAGMENT , &txdesc->flags); txdesc->ifs =IFS_BACKOFF ; - }else { + }else txdesc->ifs =IFS_SIFS ; - } - -/* -* Hardware should insert sequence counter. -* FIXME: We insert a software sequence counter first for -* hardware that doesn't support hardware sequence counting. -* -* This is wrong because beacons are not getting sequence -* numbers assigned properly. -* -* A secondary problem exists for drivers that cannot toggle -* sequence counting per-frame, since those will override the -* sequence counter given by mac80211. -*/ -if (tx_info->flags &IEEE80211_TX_CTL_ASSIGN_SEQ ) { -if (likely (tx_info->control.vif)) { -struct rt2x00_intf *intf; - - intf =vif_to_intf (tx_info->control.vif); -spin_lock_irqsave (&intf->seqlock, irqflags); - -if (test_bit (ENTRY_TXD_FIRST_FRAGMENT , &txdesc->flags)) - intf->seqno +=0x10 ; - hdr->seq_ctrl &=cpu_to_le16 (IEEE80211_SCTL_FRAG ); - hdr->seq_ctrl |=cpu_to_le16 (intf->seqno); - -spin_unlock_irqrestore (&intf->seqlock, irqflags); - -__set_bit (ENTRY_TXD_GENERATE_SEQ , &txdesc->flags); - } - } - -/* -* PLCP setup -* Length calculation depends on OFDM/CCK rate. -*/ hwrate =rt2x00_get_rate (rate->hw_value); - txdesc->signal = hwrate->plcp; - txdesc->service =0x04 ; - -if (hwrate->flags &DEV_RATE_OFDM ) { +if (hwrate->flags &DEV_RATE_OFDM )__set_bit (ENTRY_TXD_OFDM_RATE , &txdesc->flags); - txdesc->length_high = (data_length >>6 ) &0x3f ; - txdesc->length_low = data_length &0x3f ; - }else { -/* -* Convert length to microseconds. -*/ - residual =GET_DURATION_RES (data_length, hwrate->bitrate); - duration =GET_DURATION (data_length, hwrate->bitrate); - -if (residual !=0 ) { - duration++; - -/* -* Check if we need to set the Length Extension -*/ -if (hwrate->bitrate ==110 && residual <=30 ) - txdesc->service |=0x80 ; - } - - txdesc->length_high = (duration >>8 ) &0xff ; - txdesc->length_low = duration &0xff ; - -/* -* When preamble is enabled we should set the -* preamble bit for the signal. -*/ -if (rt2x00_get_rate_preamble (rate->hw_value)) - txdesc->signal |=0x08 ; - } +/* +* Apply TX descriptor handling by components +*/ +rt2x00crypto_create_tx_descriptor (entry, txdesc); +rt2x00queue_create_tx_descriptor_seq (entry, txdesc); +rt2x00queue_create_tx_descriptor_plcp (entry, txdesc, rate); } static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, --1.5.6.1
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
maintainerRe: [PATCH 8/15] rt2x00: Implement WDS support
In reply to Ivo van DoornQuoted 3 lines · Ivo van Doorn
WDS support should be very easy to handle, mac80211 handles everything for us, so all that is needed is to set the support flags and handle it in the
add_interface()callback.
Cool, you're the first, have you tested?
johannes
Re: [PATCH 8/15] rt2x00: Implement WDS support
Quoted 6 lines · Johannes Berg
Quoted 3 lines · Ivo van Doorn
WDS support should be very easy to handle, mac80211 handles everything for us, so all that is needed is to set the support flags and handle it in the
add_interface()callback.Cool, you're the first, have you tested?
Unfortunately neither Meshed mode as WDS have been tested,
I understood Meshed mode had worked some time ago on rt73usb, but now beaconing is broken (master mode isn't working either anymore).
btw, rt2x00 wasn't the first, I looked at the b43 code to see if they had do anything special in WDS mode. ;)
Ivo
Re: [PATCH 1/15] rt2x00: Implement Powersaving
In reply to Ivo van DoornHi,
Great new ! It seems to me that this is the first **usb** wireless device with power save support (and please correct me if I am wrong).
Regards,
DavidS
Quoted 329 lines · Ivo van Doorn
Listen to
IEEE80211_CONF_PSto determine if the device should drop into powersaving mode. This feature depends on the dynamic power save functionality in mac80211.Signed-off-by Ivo van Doorn <[email protected]>--- drivers/net/wireless/rt2x00/rt2400pci.c | 28 ++++++++++++++++ drivers/net/wireless/rt2x00/rt2500pci.c | 28 ++++++++++++++++ drivers/net/wireless/rt2x00/rt2500usb.c | 28 ++++++++++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 53 ++++++++++++++++++++++++++---- drivers/net/wireless/rt2x00/rt61pci.h | 4 ++ drivers/net/wireless/rt2x00/rt73usb.c | 40 +++++++++++++++++++++++ 6 files changed, 174 insertions(+), 7 deletions(-)drivers/net/wireless/rt2x00/rt2400pci.c +28
-0@@ -524,6 +524,32 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00pci_register_write (rt2x00dev,CSR12 , reg); } +static void rt2400pci_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00pci_register_read (rt2x00dev,CSR20 , ®); +rt2x00_set_field32 (®,CSR20_DELAY_AFTER_TBCN , + (libconf->conf->beacon_int -20 ) *16 ); +rt2x00_set_field32 (®,CSR20_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,0 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,1 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + } + + rt2x00dev->ops->lib->set_device_state (rt2x00dev, state); +} +static void rt2400pci_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)@@ -537,6 +563,8 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,rt2400pci_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt2400pci_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt2400pci_config_ps (rt2x00dev, libconf); } static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,drivers/net/wireless/rt2x00/rt2500pci.c +28
-0@@ -573,6 +573,32 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00pci_register_write (rt2x00dev,CSR12 , reg); } +static void rt2500pci_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00pci_register_read (rt2x00dev,CSR20 , ®); +rt2x00_set_field32 (®,CSR20_DELAY_AFTER_TBCN , + (libconf->conf->beacon_int -20 ) *16 ); +rt2x00_set_field32 (®,CSR20_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,0 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + +rt2x00_set_field32 (®,CSR20_AUTOWAKE ,1 ); +rt2x00pci_register_write (rt2x00dev,CSR20 , reg); + } + + rt2x00dev->ops->lib->set_device_state (rt2x00dev, state); +} +static void rt2500pci_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)@@ -588,6 +614,8 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,rt2500pci_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt2500pci_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt2500pci_config_ps (rt2x00dev, libconf); }/* drivers/net/wireless/rt2x00/rt2500usb.c +28
-0@@ -634,6 +634,32 @@ static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,rt2500usb_register_write (rt2x00dev,TXRX_CSR18 , reg); } +static void rt2500usb_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u16 reg; + +if (state ==STATE_SLEEP ) { +rt2500usb_register_read (rt2x00dev,MAC_CSR18 , ®); +rt2x00_set_field16 (®,MAC_CSR18_DELAY_AFTER_BEACON , + libconf->conf->beacon_int -20 ); +rt2x00_set_field16 (®,MAC_CSR18_BEACONS_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field16 (®,MAC_CSR18_AUTO_WAKE ,0 ); +rt2500usb_register_write (rt2x00dev,MAC_CSR18 , reg); + +rt2x00_set_field16 (®,MAC_CSR18_AUTO_WAKE ,1 ); +rt2500usb_register_write (rt2x00dev,MAC_CSR18 , reg); + } + + rt2x00dev->ops->lib->set_device_state (rt2x00dev, state); +} +static void rt2500usb_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)@@ -647,6 +673,8 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, libconf->conf->power_level);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt2500usb_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt2500usb_config_ps (rt2x00dev, libconf); }/* drivers/net/wireless/rt2x00/rt61pci.c +46
-7@@ -146,12 +146,6 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,mutex_unlock (&rt2x00dev->csr_mutex); } -#ifdef CONFIG_RT2X00_LIB_LEDS -/* -* This function is only called from rt61pci_led_brightness() -* make gcc happy by placing this function inside the -* same ifdef statement as the caller. -*/ static void rt61pci_mcu_request (struct rt2x00_dev *rt2x00dev,const u8 command,const u8 token,const u8 arg0,const u8 arg1)@@ -180,7 +174,6 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,mutex_unlock (&rt2x00dev->csr_mutex); } -#endif /* CONFIG_RT2X00_LIB_LEDS */ static void rt61pci_eepromregister_read (struct eeprom_93cx6 *eeprom) {@@ -967,6 +960,50 @@ static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00pci_register_write (rt2x00dev,TXRX_CSR9 , reg); } +static void rt61pci_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00pci_register_read (rt2x00dev,MAC_CSR11 , ®); +rt2x00_set_field32 (®,MAC_CSR11_DELAY_AFTER_TBCN , + libconf->conf->beacon_int -10 ); +rt2x00_set_field32 (®,MAC_CSR11_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); +rt2x00_set_field32 (®,MAC_CSR11_WAKEUP_LATENCY ,5 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,0 ); +rt2x00pci_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,1 ); +rt2x00pci_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00pci_register_write (rt2x00dev,SOFT_RESET_CSR ,0x00000005 ); +rt2x00pci_register_write (rt2x00dev,IO_CNTL_CSR ,0x0000001c ); +rt2x00pci_register_write (rt2x00dev,PCI_USEC_CSR ,0x00000060 ); + +rt61pci_mcu_request (rt2x00dev,MCU_SLEEP ,0xff ,0 ,0 ); + }else { +rt2x00pci_register_read (rt2x00dev,MAC_CSR11 , ®); +rt2x00_set_field32 (®,MAC_CSR11_DELAY_AFTER_TBCN ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_TBCN_BEFORE_WAKEUP ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_WAKEUP_LATENCY ,0 ); +rt2x00pci_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00pci_register_write (rt2x00dev,SOFT_RESET_CSR ,0x00000007 ); +rt2x00pci_register_write (rt2x00dev,IO_CNTL_CSR ,0x00000018 ); +rt2x00pci_register_write (rt2x00dev,PCI_USEC_CSR ,0x00000020 ); + +rt61pci_mcu_request (rt2x00dev,MCU_WAKEUP ,0xff ,0 ,0 ); + } +} +static void rt61pci_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)@@ -984,6 +1021,8 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev,rt61pci_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt61pci_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt61pci_config_ps (rt2x00dev, libconf); }/* drivers/net/wireless/rt2x00/rt61pci.h +4
-0@@ -88,8 +88,10 @@/* * SOFT_RESET_CSR +* FORCE_CLOCK_ON: Host force MAC clock ON */ #define SOFT_RESET_CSR 0x0010 +#define SOFT_RESET_CSR_FORCE_CLOCK_ON FIELD32(0x00000002)/* * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register. @@ -1054,8 +1056,10 @@ struct hw_pairwise_ta_entry {/* * IO_CNTL_CSR +* RF_PS: Set RF interface value to power save */ #define IO_CNTL_CSR 0x3498 +#define IO_CNTL_CSR_RF_PS FIELD32(0x00000004)/* * UART_INT_SOURCE_CSR drivers/net/wireless/rt2x00/rt73usb.c +40
-1@@ -844,6 +844,44 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,rt2x00usb_register_write (rt2x00dev,TXRX_CSR9 , reg); } +static void rt73usb_config_ps (struct rt2x00_dev *rt2x00dev, +struct rt2x00lib_conf *libconf) +{ +enum dev_state state = + (libconf->conf->flags &IEEE80211_CONF_PS ) ? +STATE_SLEEP :STATE_AWAKE ; +u32 reg; + +if (state ==STATE_SLEEP ) { +rt2x00usb_register_read (rt2x00dev,MAC_CSR11 , ®); +rt2x00_set_field32 (®,MAC_CSR11_DELAY_AFTER_TBCN , + libconf->conf->beacon_int -10 ); +rt2x00_set_field32 (®,MAC_CSR11_TBCN_BEFORE_WAKEUP , + libconf->conf->listen_interval -1 ); +rt2x00_set_field32 (®,MAC_CSR11_WAKEUP_LATENCY ,5 ); + +/* We must first disable autowake before it can be enabled */ +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,0 ); +rt2x00usb_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,1 ); +rt2x00usb_register_write (rt2x00dev,MAC_CSR11 , reg); + +rt2x00usb_vendor_request_sw (rt2x00dev,USB_DEVICE_MODE ,0 , +USB_MODE_SLEEP ,REGISTER_TIMEOUT ); + }else { +rt2x00usb_vendor_request_sw (rt2x00dev,USB_DEVICE_MODE ,0 , +USB_MODE_WAKEUP ,REGISTER_TIMEOUT ); + +rt2x00usb_register_read (rt2x00dev,MAC_CSR11 , ®); +rt2x00_set_field32 (®,MAC_CSR11_DELAY_AFTER_TBCN ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_TBCN_BEFORE_WAKEUP ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_AUTOWAKE ,0 ); +rt2x00_set_field32 (®,MAC_CSR11_WAKEUP_LATENCY ,0 ); +rt2x00usb_register_write (rt2x00dev,MAC_CSR11 , reg); + } +} +static void rt73usb_config (struct rt2x00_dev *rt2x00dev,struct rt2x00lib_conf *libconf,const unsigned int flags)@@ -861,6 +899,8 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev,rt73usb_config_retry_limit (rt2x00dev, libconf);if (flags &IEEE80211_CONF_CHANGE_BEACON_INTERVAL )rt73usb_config_duration (rt2x00dev, libconf); +if (flags &IEEE80211_CONF_CHANGE_PS ) +rt73usb_config_ps (rt2x00dev, libconf); }/* -- 1.5.6.1
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/15] rt2x00: Implement Powersaving
Quoted 4 lines
Hi,
Great new ! It seems to me that this is the first **usb** wireless device with power save support (and please correct me if I am wrong).
The libertas device as used in the OLPC ?
It's a non-mac80211 device, but uses powersave nethertheless.