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
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.
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index fabcd71..031cb0a 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -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,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index a9add81..780c96b 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -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);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index d8c48fd..4de1bc1 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -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);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 3b9015a..3f91a6e 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -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);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 65fe333..86590c6 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -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
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 563be0b..8a365c9 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -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
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00dev.c | 4 ++--
drivers/net/wireless/rt2x00/rt2x00queue.h | 8 ++++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 841879d..ab8aa97 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -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;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 1bd1a95..98209d2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -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.
--
1.5.6.1
Move link and antenna tuning into a seperate file named rt2x00link.c,
this makes the interface to the link tuner a lot cleaner.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 917cb4f..f22d808 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -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
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 39ecf3b..19c0687 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -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
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index e66fb31..2f4cb8d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -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;
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 54dd100..cc19406 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -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;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 6d92542..1c49a9c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -30,60 +30,6 @@
#include "rt2x00lib.h"
/*
- * Link tuning handlers
- */
-void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- return;
-
- /*
- * Reset link information.
- * Both the currently active vgc level as well as
- * the link tuner counter should be reset. Resetting
- * the counter is important for devices where the
- * device should only perform link tuning during the
- * first minute after being enabled.
- */
- rt2x00dev->link.count = 0;
- rt2x00dev->link.vgc_level = 0;
-
- /*
- * Reset the link tuner.
- */
- rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
-}
-
-static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
-{
- /*
- * Clear all (possibly) pre-existing quality statistics.
- */
- memset(&rt2x00dev->link.qual, 0, sizeof(rt2x00dev->link.qual));
-
- /*
- * The RX and TX percentage should start at 50%
- * this will assure we will get at least get some
- * decent value when the link tuner starts.
- * The value will be dropped and overwritten with
- * the correct (measured )value anyway during the
- * first run of the link tuner.
- */
- rt2x00dev->link.qual.rx_percentage = 50;
- rt2x00dev->link.qual.tx_percentage = 50;
-
- rt2x00lib_reset_link_tuner(rt2x00dev);
-
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
-}
-
-static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev)
-{
- cancel_delayed_work_sync(&rt2x00dev->link.work);
-}
-
-/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -161,238 +107,15 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
* When we are disabling the RX, we should also stop the link tuner.
*/
if (state == STATE_RADIO_RX_OFF)
- rt2x00lib_stop_link_tuner(rt2x00dev);
+ rt2x00link_stop_tuner(rt2x00dev);
rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
/*
* When we are enabling the RX, we should also start the link tuner.
*/
- if (state == STATE_RADIO_RX_ON &&
- (rt2x00dev->intf_ap_count || rt2x00dev->intf_sta_count))
- rt2x00lib_start_link_tuner(rt2x00dev);
-}
-
-static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
-{
- struct antenna_setup ant;
- int sample_a =
- rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A);
- int sample_b =
- rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B);
-
- memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
-
- /*
- * We are done sampling. Now we should evaluate the results.
- */
- rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
-
- /*
- * During the last period we have sampled the RSSI
- * from both antenna's. It now is time to determine
- * which antenna demonstrated the best performance.
- * When we are already on the antenna with the best
- * performance, then there really is nothing for us
- * left to do.
- */
- if (sample_a == sample_b)
- return;
-
- if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
- ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
-
- if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
- ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
-
- rt2x00lib_config_antenna(rt2x00dev, &ant);
-}
-
-static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
-{
- struct antenna_setup ant;
- int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link);
- int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr);
-
- memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
-
- /*
- * Legacy driver indicates that we should swap antenna's
- * when the difference in RSSI is greater that 5. This
- * also should be done when the RSSI was actually better
- * then the previous sample.
- * When the difference exceeds the threshold we should
- * sample the rssi from the other antenna to make a valid
- * comparison between the 2 antennas.
- */
- if (abs(rssi_curr - rssi_old) < 5)
- return;
-
- rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
-
- if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
- ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
-
- if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
- ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
-
- rt2x00lib_config_antenna(rt2x00dev, &ant);
-}
-
-static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
-{
- /*
- * Determine if software diversity is enabled for
- * either the TX or RX antenna (or both).
- * Always perform this check since within the link
- * tuner interval the configuration might have changed.
- */
- rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
- rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
-
- if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
- rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
- if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
- rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
-
- if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
- !(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) {
- rt2x00dev->link.ant.flags = 0;
- return;
- }
-
- /*
- * If we have only sampled the data over the last period
- * we should now harvest the data. Otherwise just evaluate
- * the data. The latter should only be performed once
- * every 2 seconds.
- */
- if (rt2x00dev->link.ant.flags & ANTENNA_MODE_SAMPLE)
- rt2x00lib_evaluate_antenna_sample(rt2x00dev);
- else if (rt2x00dev->link.count & 1)
- rt2x00lib_evaluate_antenna_eval(rt2x00dev);
-}
-
-static void rt2x00lib_update_link_stats(struct link *link, int rssi)
-{
- int avg_rssi = rssi;
-
- /*
- * Update global RSSI
- */
- if (link->qual.avg_rssi)
- avg_rssi = MOVING_AVERAGE(link->qual.avg_rssi, rssi, 8);
- link->qual.avg_rssi = avg_rssi;
-
- /*
- * Update antenna RSSI
- */
- if (link->ant.rssi_ant)
- rssi = MOVING_AVERAGE(link->ant.rssi_ant, rssi, 8);
- link->ant.rssi_ant = rssi;
-}
-
-static void rt2x00lib_precalculate_link_signal(struct link_qual *qual)
-{
- if (qual->rx_failed || qual->rx_success)
- qual->rx_percentage =
- (qual->rx_success * 100) /
- (qual->rx_failed + qual->rx_success);
- else
- qual->rx_percentage = 50;
-
- if (qual->tx_failed || qual->tx_success)
- qual->tx_percentage =
- (qual->tx_success * 100) /
- (qual->tx_failed + qual->tx_success);
- else
- qual->tx_percentage = 50;
-
- qual->rx_success = 0;
- qual->rx_failed = 0;
- qual->tx_success = 0;
- qual->tx_failed = 0;
-}
-
-static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
- int rssi)
-{
- int rssi_percentage = 0;
- int signal;
-
- /*
- * We need a positive value for the RSSI.
- */
- if (rssi < 0)
- rssi += rt2x00dev->rssi_offset;
-
- /*
- * Calculate the different percentages,
- * which will be used for the signal.
- */
- if (rt2x00dev->rssi_offset)
- rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
-
- /*
- * Add the individual percentages and use the WEIGHT
- * defines to calculate the current link signal.
- */
- signal = ((WEIGHT_RSSI * rssi_percentage) +
- (WEIGHT_TX * rt2x00dev->link.qual.tx_percentage) +
- (WEIGHT_RX * rt2x00dev->link.qual.rx_percentage)) / 100;
-
- return (signal > 100) ? 100 : signal;
-}
-
-static void rt2x00lib_link_tuner(struct work_struct *work)
-{
- struct rt2x00_dev *rt2x00dev =
- container_of(work, struct rt2x00_dev, link.work.work);
-
- /*
- * When the radio is shutting down we should
- * immediately cease all link tuning.
- */
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- return;
-
- /*
- * Update statistics.
- */
- rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual);
- rt2x00dev->low_level_stats.dot11FCSErrorCount +=
- rt2x00dev->link.qual.rx_failed;
-
- /*
- * Only perform the link tuning when Link tuning
- * has been enabled (This could have been disabled from the EEPROM).
- */
- if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
- rt2x00dev->ops->lib->link_tuner(rt2x00dev);
-
- /*
- * Precalculate a portion of the link signal which is
- * in based on the tx/rx success/failure counters.
- */
- rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual);
-
- /*
- * Send a signal to the led to update the led signal strength.
- */
- rt2x00leds_led_quality(rt2x00dev, rt2x00dev->link.qual.avg_rssi);
-
- /*
- * Evaluate antenna setup, make this the last step since this could
- * possibly reset some statistics.
- */
- rt2x00lib_evaluate_antenna(rt2x00dev);
-
- /*
- * Increase tuner counter, and reschedule the next link tuner run.
- */
- rt2x00dev->link.count++;
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+ if (state == STATE_RADIO_RX_ON)
+ rt2x00link_start_tuner(rt2x00dev);
}
static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -597,7 +320,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb;
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
struct ieee80211_supported_band *sband;
- struct ieee80211_hdr *hdr;
const struct rt2x00_rate *rate;
unsigned int header_length;
unsigned int align;
@@ -674,23 +396,14 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
}
/*
- * Only update link status if this is a beacon frame carrying our bssid.
+ * Update extra components
*/
- hdr = (struct ieee80211_hdr *)entry->skb->data;
- if (ieee80211_is_beacon(hdr->frame_control) &&
- (rxdesc.dev_flags & RXDONE_MY_BSS))
- rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);
-
- rt2x00debug_update_crypto(rt2x00dev,
- rxdesc.cipher,
- rxdesc.cipher_status);
-
- rt2x00dev->link.qual.rx_success++;
+ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
+ rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
rx_status->mactime = rxdesc.timestamp;
rx_status->rate_idx = idx;
- rx_status->qual =
- rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc.rssi);
+ rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi);
rx_status->signal = rxdesc.rssi;
rx_status->flag = rxdesc.flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;
@@ -1085,7 +798,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
- INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
/*
* Allocate queue array.
@@ -1106,6 +818,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
/*
* Register extra components.
*/
+ rt2x00link_register(rt2x00dev);
rt2x00leds_register(rt2x00dev);
rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 0302432..a6b7e00 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -74,7 +74,6 @@ static inline int rt2x00_get_rate_preamble(const u16 hw_value)
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state);
-void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev);
/*
* Initialization handlers.
@@ -165,6 +164,81 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_free(struct rt2x00_dev *rt2x00dev);
+/**
+ * rt2x00link_update_stats - Update link statistics from RX frame
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: Received frame
+ * @rxdesc: Received frame descriptor
+ *
+ * Update link statistics based on the information from the
+ * received frame descriptor.
+ */
+void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct rxdone_entry_desc *rxdesc);
+
+/**
+ * rt2x00link_calculate_signal - Calculate signal quality
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @rssi: RX Frame RSSI
+ *
+ * Calculate the signal quality of a frame based on the rssi
+ * measured during the receiving of the frame and the global
+ * link quality statistics measured since the start of the
+ * link tuning. The result is a value between 0 and 100 which
+ * is an indication of the signal quality.
+ */
+int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi);
+
+/**
+ * rt2x00link_start_tuner - Start periodic link tuner work
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This start the link tuner periodic work, this work will
+ * be executed periodically until &rt2x00link_stop_tuner has
+ * been called.
+ */
+void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_stop_tuner - Stop periodic link tuner work
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * After this function completed the link tuner will not
+ * be running until &rt2x00link_start_tuner is called.
+ */
+void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_reset_tuner - Reset periodic link tuner work
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @antenna: Should the antenna tuning also be reset
+ *
+ * The VGC limit configured in the hardware will be reset to 0
+ * which forces the driver to rediscover the correct value for
+ * the current association. This is needed when configuration
+ * options have changed which could drastically change the
+ * SNR level or link quality (i.e. changing the antenna setting).
+ *
+ * Resetting the link tuner will also cause the periodic work counter
+ * to be reset. Any driver which has a fixed limit on the number
+ * of rounds the link tuner is supposed to work will accept the
+ * tuner actions again if this limit was previously reached.
+ *
+ * If @antenna is set to true a the software antenna diversity
+ * tuning will also be reset.
+ */
+void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
+
+/**
+ * rt2x00link_register - Initialize link tuning functionality
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * Initialize work structure and all link tuning related
+ * paramters. This will not start the link tuning process itself.
+ */
+void rt2x00link_register(struct rt2x00_dev *rt2x00dev);
+
/*
* Firmware handlers.
*/
@@ -190,7 +264,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct sk_buff *skb);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
- enum cipher cipher, enum rx_crypto status);
+ struct rxdone_entry_desc *rxdesc);
#else
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
@@ -207,8 +281,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
}
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
- enum cipher cipher,
- enum rx_crypto status)
+ struct rxdone_entry_desc *rxdesc)
{
}
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
new file mode 100644
index 0000000..0462d5a
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -0,0 +1,402 @@
+/*
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 generic link tuning routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
+{
+ struct link_ant *ant = &rt2x00dev->link.ant;
+
+ if (ant->rssi_ant && rt2x00dev->link.qual.rx_success)
+ return ant->rssi_ant;
+ return DEFAULT_RSSI;
+}
+
+static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev,
+ enum antenna antenna)
+{
+ struct link_ant *ant = &rt2x00dev->link.ant;
+
+ if (ant->rssi_history[antenna - ANTENNA_A])
+ return ant->rssi_history[antenna - ANTENNA_A];
+ return DEFAULT_RSSI;
+}
+/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
+#define rt2x00link_antenna_get_rssi_rx_history(__dev) \
+ rt2x00link_antenna_get_rssi_history((__dev), \
+ (__dev)->link.ant.active.rx)
+#define rt2x00link_antenna_get_rssi_tx_history(__dev) \
+ rt2x00link_antenna_get_rssi_history((__dev), \
+ (__dev)->link.ant.active.tx)
+
+static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
+ enum antenna antenna,
+ int rssi)
+{
+ struct link_ant *ant = &rt2x00dev->link.ant;
+ ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi;
+}
+/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
+#define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \
+ rt2x00link_antenna_update_rssi_history((__dev), \
+ (__dev)->link.ant.active.rx, \
+ (__rssi))
+#define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \
+ rt2x00link_antenna_update_rssi_history((__dev), \
+ (__dev)->link.ant.active.tx, \
+ (__rssi))
+
+static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00dev->link.ant.rssi_ant = 0;
+}
+
+static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
+{
+ struct link_ant *ant = &rt2x00dev->link.ant;
+ struct antenna_setup new_ant;
+ int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A);
+ int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B);
+
+ memcpy(&new_ant, &ant->active, sizeof(new_ant));
+
+ /*
+ * We are done sampling. Now we should evaluate the results.
+ */
+ ant->flags &= ~ANTENNA_MODE_SAMPLE;
+
+ /*
+ * During the last period we have sampled the RSSI
+ * from both antenna's. It now is time to determine
+ * which antenna demonstrated the best performance.
+ * When we are already on the antenna with the best
+ * performance, then there really is nothing for us
+ * left to do.
+ */
+ if (sample_a == sample_b)
+ return;
+
+ if (ant->flags & ANTENNA_RX_DIVERSITY)
+ new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+
+ if (ant->flags & ANTENNA_TX_DIVERSITY)
+ new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+
+ rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+}
+
+static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
+{
+ struct link_ant *ant = &rt2x00dev->link.ant;
+ struct antenna_setup new_ant;
+ int rssi_curr;
+ int rssi_old;
+
+ memcpy(&new_ant, &ant->active, sizeof(new_ant));
+
+ /*
+ * Get current RSSI value along with the historical value,
+ * after that update the history with the current value.
+ */
+ rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
+ rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev);
+ rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr);
+
+ /*
+ * Legacy driver indicates that we should swap antenna's
+ * when the difference in RSSI is greater that 5. This
+ * also should be done when the RSSI was actually better
+ * then the previous sample.
+ * When the difference exceeds the threshold we should
+ * sample the rssi from the other antenna to make a valid
+ * comparison between the 2 antennas.
+ */
+ if (abs(rssi_curr - rssi_old) < 5)
+ return;
+
+ ant->flags |= ANTENNA_MODE_SAMPLE;
+
+ if (ant->flags & ANTENNA_RX_DIVERSITY)
+ new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+
+ if (ant->flags & ANTENNA_TX_DIVERSITY)
+ new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+
+ rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+}
+
+static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
+{
+ struct link_ant *ant = &rt2x00dev->link.ant;
+
+ /*
+ * Determine if software diversity is enabled for
+ * either the TX or RX antenna (or both).
+ * Always perform this check since within the link
+ * tuner interval the configuration might have changed.
+ */
+ ant->flags &= ~ANTENNA_RX_DIVERSITY;
+ ant->flags &= ~ANTENNA_TX_DIVERSITY;
+
+ if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+ ant->flags |= ANTENNA_RX_DIVERSITY;
+ if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+ ant->flags |= ANTENNA_TX_DIVERSITY;
+
+ if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
+ !(ant->flags & ANTENNA_TX_DIVERSITY)) {
+ ant->flags = 0;
+ return;
+ }
+
+ /*
+ * If we have only sampled the data over the last period
+ * we should now harvest the data. Otherwise just evaluate
+ * the data. The latter should only be performed once
+ * every 2 seconds.
+ */
+ if (ant->flags & ANTENNA_MODE_SAMPLE)
+ rt2x00lib_antenna_diversity_sample(rt2x00dev);
+ else if (rt2x00dev->link.count & 1)
+ rt2x00lib_antenna_diversity_eval(rt2x00dev);
+}
+
+void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct link_qual *qual = &rt2x00dev->link.qual;
+ struct link_ant *ant = &rt2x00dev->link.ant;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ int avg_rssi = rxdesc->rssi;
+ int ant_rssi = rxdesc->rssi;
+
+ /*
+ * Frame was received successfully since non-succesfull
+ * frames would have been dropped by the hardware.
+ */
+ qual->rx_success++;
+
+ /*
+ * We are only interested in quality statistics from
+ * beacons which came from the BSS which we are
+ * associated with.
+ */
+ if (!ieee80211_is_beacon(hdr->frame_control) ||
+ !(rxdesc->dev_flags & RXDONE_MY_BSS))
+ return;
+
+ /*
+ * Update global RSSI
+ */
+ if (qual->avg_rssi)
+ avg_rssi = MOVING_AVERAGE(qual->avg_rssi, rxdesc->rssi, 8);
+ qual->avg_rssi = avg_rssi;
+
+ /*
+ * Update antenna RSSI
+ */
+ if (ant->rssi_ant)
+ ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8);
+ ant->rssi_ant = ant_rssi;
+}
+
+static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
+{
+ struct link_qual *qual = &rt2x00dev->link.qual;
+
+ if (qual->rx_failed || qual->rx_success)
+ qual->rx_percentage =
+ (qual->rx_success * 100) /
+ (qual->rx_failed + qual->rx_success);
+ else
+ qual->rx_percentage = 50;
+
+ if (qual->tx_failed || qual->tx_success)
+ qual->tx_percentage =
+ (qual->tx_success * 100) /
+ (qual->tx_failed + qual->tx_success);
+ else
+ qual->tx_percentage = 50;
+
+ qual->rx_success = 0;
+ qual->rx_failed = 0;
+ qual->tx_success = 0;
+ qual->tx_failed = 0;
+}
+
+int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+ struct link_qual *qual = &rt2x00dev->link.qual;
+ int rssi_percentage = 0;
+ int signal;
+
+ /*
+ * We need a positive value for the RSSI.
+ */
+ if (rssi < 0)
+ rssi += rt2x00dev->rssi_offset;
+
+ /*
+ * Calculate the different percentages,
+ * which will be used for the signal.
+ */
+ rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
+
+ /*
+ * Add the individual percentages and use the WEIGHT
+ * defines to calculate the current link signal.
+ */
+ signal = ((WEIGHT_RSSI * rssi_percentage) +
+ (WEIGHT_TX * qual->tx_percentage) +
+ (WEIGHT_RX * qual->rx_percentage)) / 100;
+
+ return max_t(int, signal, 100);
+}
+
+void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ struct link_qual *qual = &rt2x00dev->link.qual;
+
+ /*
+ * Link tuning should only be performed when
+ * an active sta or master interface exists.
+ * Single monitor mode interfaces should never have
+ * work with link tuners.
+ */
+ if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
+ return;
+
+ /*
+ * Clear all (possibly) pre-existing quality statistics.
+ */
+ memset(qual, 0, sizeof(*qual));
+
+ /*
+ * The RX and TX percentage should start at 50%
+ * this will assure we will get at least get some
+ * decent value when the link tuner starts.
+ * The value will be dropped and overwritten with
+ * the correct (measured) value anyway during the
+ * first run of the link tuner.
+ */
+ qual->rx_percentage = 50;
+ qual->tx_percentage = 50;
+
+ rt2x00link_reset_tuner(rt2x00dev, false);
+
+ queue_delayed_work(rt2x00dev->hw->workqueue,
+ &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+}
+
+void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ cancel_delayed_work_sync(&rt2x00dev->link.work);
+}
+
+void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
+{
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Reset link information.
+ * Both the currently active vgc level as well as
+ * the link tuner counter should be reset. Resetting
+ * the counter is important for devices where the
+ * device should only perform link tuning during the
+ * first minute after being enabled.
+ */
+ rt2x00dev->link.count = 0;
+ rt2x00dev->link.vgc_level = 0;
+
+ /*
+ * Reset the link tuner.
+ */
+ rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+
+ if (antenna)
+ rt2x00link_antenna_reset(rt2x00dev);
+}
+
+static void rt2x00link_tuner(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, link.work.work);
+ struct link_qual *qual = &rt2x00dev->link.qual;
+
+ /*
+ * When the radio is shutting down we should
+ * immediately cease all link tuning.
+ */
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Update statistics.
+ */
+ rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
+ rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
+
+ /*
+ * Only perform the link tuning when Link tuning
+ * has been enabled (This could have been disabled from the EEPROM).
+ */
+ if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
+ rt2x00dev->ops->lib->link_tuner(rt2x00dev);
+
+ /*
+ * Precalculate a portion of the link signal which is
+ * in based on the tx/rx success/failure counters.
+ */
+ rt2x00link_precalculate_signal(rt2x00dev);
+
+ /*
+ * Send a signal to the led to update the led signal strength.
+ */
+ rt2x00leds_led_quality(rt2x00dev, qual->avg_rssi);
+
+ /*
+ * Evaluate antenna setup, make this the last step since this could
+ * possibly reset some statistics.
+ */
+ rt2x00lib_antenna_diversity(rt2x00dev);
+
+ /*
+ * Increase tuner counter, and reschedule the next link tuner run.
+ */
+ rt2x00dev->link.count++;
+ queue_delayed_work(rt2x00dev->hw->workqueue,
+ &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+}
+
+void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
+{
+ INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
+}
--
1.5.6.1
> 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.
Hello,
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
On Sat, Dec 20, 2008 at 11:58 AM, Ivo van Doorn <[email protected]> wrote:
> 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(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
> index 37ad0d2..f30bda2 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
> @@ -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
> diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
> index a6b7e00..1e80a83 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00lib.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
> @@ -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;
> }
> diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
> index e6fba83..bf7755a 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00mac.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
> @@ -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);
>
> /*
> diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
> index 0777120..efb2875 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00queue.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
> @@ -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
>
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.
Signed-off-by: Andrey Yurovsky <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 2f4cb8d..a35265c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -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:
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 1c49a9c..b484197 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 38edee5..137386e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -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.
--
1.5.6.1
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).
Regards,
DavidS
On Sat, Dec 20, 2008 at 11:52 AM, Ivo van Doorn <[email protected]> wrote:
> 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.
>
> 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(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
> index fabcd71..031cb0a 100644
> --- a/drivers/net/wireless/rt2x00/rt2400pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2400pci.c
> @@ -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,
> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
> index a9add81..780c96b 100644
> --- a/drivers/net/wireless/rt2x00/rt2500pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2500pci.c
> @@ -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);
> }
>
> /*
> diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
> index d8c48fd..4de1bc1 100644
> --- a/drivers/net/wireless/rt2x00/rt2500usb.c
> +++ b/drivers/net/wireless/rt2x00/rt2500usb.c
> @@ -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);
> }
>
> /*
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
> index 3b9015a..3f91a6e 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.c
> +++ b/drivers/net/wireless/rt2x00/rt61pci.c
> @@ -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);
> }
>
> /*
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
> index 65fe333..86590c6 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.h
> +++ b/drivers/net/wireless/rt2x00/rt61pci.h
> @@ -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
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
> index 563be0b..8a365c9 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.c
> +++ b/drivers/net/wireless/rt2x00/rt73usb.c
> @@ -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
>
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).
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00usb.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 83df312..0b29d76 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -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;
}
}
--
1.5.6.1
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index a35265c..ab139f2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -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:
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index b484197..3cb417f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 137386e..e6fba83 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -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.
--
1.5.6.1
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00dev.c | 1 +
drivers/net/wireless/rt2x00/rt2x00queue.h | 2 ++
2 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 3cb417f..841879d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -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;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 5a9d2c3..1bd1a95 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -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;
--
1.5.6.1
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 1612a9c..1ef3434 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -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"
/*
--
1.5.6.1
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 37ad0d2..f30bda2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -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
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index a6b7e00..1e80a83 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -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;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index e6fba83..bf7755a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -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);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 0777120..efb2875 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -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
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 90333ee..76f016d 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -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,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 8a53f9b..81400ea 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index efb2875..fc28e23 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -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
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 2829371..5a9d2c3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -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;
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index c2fba7c..93f8427 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -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
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 875acb3..f1150a7 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -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));
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 2268d5c..891554e 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -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));
--
1.5.6.1
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 79f0771..ce76a87 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -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,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 4347dfd..e1f714e 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -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.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 5992c8f..2268d5c 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -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,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 46e1405..204bbd5 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -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.
--
1.5.6.1
On Sat, 2008-12-20 at 10:57 +0100, Ivo van Doorn wrote:
> 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
On Sunday 21 December 2008, Johannes Berg wrote:
> On Sat, 2008-12-20 at 10:57 +0100, Ivo van Doorn wrote:
> > 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
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt61pci.c | 25 ++++++-------------------
drivers/net/wireless/rt2x00/rt61pci.h | 3 ++-
2 files changed, 8 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 2b72010..875acb3 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -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;
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 86590c6..cd86def 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -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)
--
1.5.6.1
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 031cb0a..a186e4b 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -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);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 780c96b..dd1f2c0 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -639,16 +639,23 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
}
+static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
+{
+ if (rt2x00dev->link.vgc_level_reg != vgc_level) {
+ rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
+ rt2x00dev->link.vgc_level_reg = vgc_level;
+ }
+}
+
static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
{
- rt2500pci_bbp_write(rt2x00dev, 17, 0x48);
- rt2x00dev->link.vgc_level = 0x48;
+ rt2500pci_set_vgc(rt2x00dev, 0x48);
}
static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
{
- int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
- u8 r17;
+ struct link *link = &rt2x00dev->link;
+ int rssi = rt2x00_get_link_rssi(link);
/*
* To prevent collisions with MAC ASIC on chipsets
@@ -656,12 +663,9 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* seconds while being associated.
*/
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
- rt2x00dev->intf_associated &&
- rt2x00dev->link.count > 20)
+ rt2x00dev->intf_associated && link->count > 20)
return;
- rt2500pci_bbp_read(rt2x00dev, 17, &r17);
-
/*
* Chipset versions C and lower should directly continue
* to the dynamic CCA tuning. Chipset version D and higher
@@ -677,11 +681,9 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* then corrupt the R17 tuning. To remidy this the tuning should
* be stopped (While making sure the R17 value will not exceed limits)
*/
- if (rssi < -80 && rt2x00dev->link.count > 20) {
- if (r17 >= 0x41) {
- r17 = rt2x00dev->link.vgc_level;
- rt2500pci_bbp_write(rt2x00dev, 17, r17);
- }
+ if (rssi < -80 && link->count > 20) {
+ if (link->vgc_level_reg >= 0x41)
+ rt2500pci_set_vgc(rt2x00dev, link->vgc_level);
return;
}
@@ -689,8 +691,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for short distance
*/
if (rssi >= -58) {
- if (r17 != 0x50)
- rt2500pci_bbp_write(rt2x00dev, 17, 0x50);
+ rt2500pci_set_vgc(rt2x00dev, 0x50);
return;
}
@@ -698,8 +699,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special mid-R17 for middle distance
*/
if (rssi >= -74) {
- if (r17 != 0x41)
- rt2500pci_bbp_write(rt2x00dev, 17, 0x41);
+ rt2500pci_set_vgc(rt2x00dev, 0x41);
return;
}
@@ -707,8 +707,8 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Leave short or middle distance condition, restore r17
* to the dynamic tuning range.
*/
- if (r17 >= 0x41) {
- rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.vgc_level);
+ if (link->vgc_level_reg >= 0x41) {
+ rt2500pci_set_vgc(rt2x00dev, link->vgc_level);
return;
}
@@ -718,12 +718,12 @@ dynamic_cca_tune:
* R17 is inside the dynamic tuning range,
* start tuning the link based on the false cca counter.
*/
- if (rt2x00dev->link.qual.false_cca > 512 && r17 < 0x40) {
- rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
- rt2x00dev->link.vgc_level = r17;
- } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > 0x32) {
- rt2500pci_bbp_write(rt2x00dev, 17, --r17);
- rt2x00dev->link.vgc_level = r17;
+ if (link->qual.false_cca > 512 && link->vgc_level_reg < 0x40) {
+ rt2500pci_set_vgc(rt2x00dev, ++link->vgc_level_reg);
+ link->vgc_level = link->vgc_level_reg;
+ } else if (link->qual.false_cca < 100 && link->vgc_level_reg > 0x32) {
+ rt2500pci_set_vgc(rt2x00dev, --link->vgc_level_reg);
+ link->vgc_level = link->vgc_level_reg;
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 19c0687..8935f2c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -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.
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 3f91a6e..abd7b43 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1046,21 +1046,27 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
+static inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
+{
+ if (rt2x00dev->link.vgc_level != vgc_level) {
+ rt61pci_bbp_write(rt2x00dev, 17, vgc_level);
+ rt2x00dev->link.vgc_level = vgc_level;
+ rt2x00dev->link.vgc_level_reg = vgc_level;
+ }
+}
+
static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
{
- rt61pci_bbp_write(rt2x00dev, 17, 0x20);
- rt2x00dev->link.vgc_level = 0x20;
+ rt61pci_set_vgc(rt2x00dev, 0x20);
}
static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
{
- int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
- u8 r17;
+ struct link *link = &rt2x00dev->link;
+ int rssi = rt2x00_get_link_rssi(link);
u8 up_bound;
u8 low_bound;
- rt61pci_bbp_read(rt2x00dev, 17, &r17);
-
/*
* Determine r17 bounds.
*/
@@ -1091,8 +1097,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for very short distance
*/
if (rssi >= -35) {
- if (r17 != 0x60)
- rt61pci_bbp_write(rt2x00dev, 17, 0x60);
+ rt61pci_set_vgc(rt2x00dev, 0x60);
return;
}
@@ -1100,8 +1105,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for short distance
*/
if (rssi >= -58) {
- if (r17 != up_bound)
- rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+ rt61pci_set_vgc(rt2x00dev, up_bound);
return;
}
@@ -1109,9 +1113,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for middle-short distance
*/
if (rssi >= -66) {
- low_bound += 0x10;
- if (r17 != low_bound)
- rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+ rt61pci_set_vgc(rt2x00dev, low_bound + 0x10);
return;
}
@@ -1119,9 +1121,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special mid-R17 for middle distance
*/
if (rssi >= -74) {
- low_bound += 0x08;
- if (r17 != low_bound)
- rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+ rt61pci_set_vgc(rt2x00dev, low_bound + 0x08);
return;
}
@@ -1133,8 +1133,8 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
if (low_bound > up_bound)
up_bound = low_bound;
- if (r17 > up_bound) {
- rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+ if (link->vgc_level > up_bound) {
+ rt61pci_set_vgc(rt2x00dev, up_bound);
return;
}
@@ -1144,15 +1144,10 @@ dynamic_cca_tune:
* r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count.
*/
- if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
- if (++r17 > up_bound)
- r17 = up_bound;
- rt61pci_bbp_write(rt2x00dev, 17, r17);
- } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
- if (--r17 < low_bound)
- r17 = low_bound;
- rt61pci_bbp_write(rt2x00dev, 17, r17);
- }
+ if ((link->qual.false_cca > 512) && (link->vgc_level < up_bound))
+ rt61pci_set_vgc(rt2x00dev, ++link->vgc_level);
+ else if ((link->qual.false_cca < 100) && (link->vgc_level > low_bound))
+ rt61pci_set_vgc(rt2x00dev, --link->vgc_level);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 8a365c9..49fd42a 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -924,21 +924,27 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
+static inline void rt73usb_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
+{
+ if (rt2x00dev->link.vgc_level != vgc_level) {
+ rt73usb_bbp_write(rt2x00dev, 17, vgc_level);
+ rt2x00dev->link.vgc_level = vgc_level;
+ rt2x00dev->link.vgc_level_reg = vgc_level;
+ }
+}
+
static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
{
- rt73usb_bbp_write(rt2x00dev, 17, 0x20);
- rt2x00dev->link.vgc_level = 0x20;
+ rt73usb_set_vgc(rt2x00dev, 0x20);
}
static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
{
- int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
- u8 r17;
+ struct link *link = &rt2x00dev->link;
+ int rssi = rt2x00_get_link_rssi(link);
u8 up_bound;
u8 low_bound;
- rt73usb_bbp_read(rt2x00dev, 17, &r17);
-
/*
* Determine r17 bounds.
*/
@@ -979,8 +985,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for very short distance
*/
if (rssi > -35) {
- if (r17 != 0x60)
- rt73usb_bbp_write(rt2x00dev, 17, 0x60);
+ rt73usb_set_vgc(rt2x00dev, 0x60);
return;
}
@@ -988,8 +993,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for short distance
*/
if (rssi >= -58) {
- if (r17 != up_bound)
- rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+ rt73usb_set_vgc(rt2x00dev, up_bound);
return;
}
@@ -997,9 +1001,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special big-R17 for middle-short distance
*/
if (rssi >= -66) {
- low_bound += 0x10;
- if (r17 != low_bound)
- rt73usb_bbp_write(rt2x00dev, 17, low_bound);
+ rt73usb_set_vgc(rt2x00dev, low_bound + 0x10);
return;
}
@@ -1007,8 +1009,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special mid-R17 for middle distance
*/
if (rssi >= -74) {
- if (r17 != (low_bound + 0x10))
- rt73usb_bbp_write(rt2x00dev, 17, low_bound + 0x08);
+ rt73usb_set_vgc(rt2x00dev, low_bound + 0x08);
return;
}
@@ -1020,8 +1021,8 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
if (low_bound > up_bound)
up_bound = low_bound;
- if (r17 > up_bound) {
- rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+ if (link->vgc_level > up_bound) {
+ rt73usb_set_vgc(rt2x00dev, up_bound);
return;
}
@@ -1031,17 +1032,12 @@ dynamic_cca_tune:
* r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count.
*/
- if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
- r17 += 4;
- if (r17 > up_bound)
- r17 = up_bound;
- rt73usb_bbp_write(rt2x00dev, 17, r17);
- } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
- r17 -= 4;
- if (r17 < low_bound)
- r17 = low_bound;
- rt73usb_bbp_write(rt2x00dev, 17, r17);
- }
+ if ((link->qual.false_cca > 512) && (link->vgc_level < up_bound))
+ rt73usb_set_vgc(rt2x00dev,
+ min_t(u8, link->vgc_level + 4, up_bound));
+ else if ((link->qual.false_cca < 100) && (link->vgc_level > low_bound))
+ rt73usb_set_vgc(rt2x00dev,
+ max_t(u8, link->vgc_level - 4, low_bound));
}
/*
--
1.5.6.1
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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index a186e4b..9c02231 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -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);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index dd1f2c0..90333ee 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -639,31 +639,31 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
}
-static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
+static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, u8 vgc_level)
{
- if (rt2x00dev->link.vgc_level_reg != vgc_level) {
+ if (qual->vgc_level_reg != vgc_level) {
rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
- rt2x00dev->link.vgc_level_reg = vgc_level;
+ qual->vgc_level_reg = vgc_level;
}
}
-static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
{
- rt2500pci_set_vgc(rt2x00dev, 0x48);
+ rt2500pci_set_vgc(rt2x00dev, qual, 0x48);
}
-static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, const u32 count)
{
- struct link *link = &rt2x00dev->link;
- int rssi = rt2x00_get_link_rssi(link);
-
/*
* To prevent collisions with MAC ASIC on chipsets
* up to version C the link tuning should halt after 20
* seconds while being associated.
*/
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
- rt2x00dev->intf_associated && link->count > 20)
+ rt2x00dev->intf_associated && count > 20)
return;
/*
@@ -681,25 +681,25 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* then corrupt the R17 tuning. To remidy this the tuning should
* be stopped (While making sure the R17 value will not exceed limits)
*/
- if (rssi < -80 && link->count > 20) {
- if (link->vgc_level_reg >= 0x41)
- rt2500pci_set_vgc(rt2x00dev, link->vgc_level);
+ if (qual->rssi < -80 && count > 20) {
+ if (qual->vgc_level_reg >= 0x41)
+ rt2500pci_set_vgc(rt2x00dev, qual, qual->vgc_level);
return;
}
/*
* Special big-R17 for short distance
*/
- if (rssi >= -58) {
- rt2500pci_set_vgc(rt2x00dev, 0x50);
+ if (qual->rssi >= -58) {
+ rt2500pci_set_vgc(rt2x00dev, qual, 0x50);
return;
}
/*
* Special mid-R17 for middle distance
*/
- if (rssi >= -74) {
- rt2500pci_set_vgc(rt2x00dev, 0x41);
+ if (qual->rssi >= -74) {
+ rt2500pci_set_vgc(rt2x00dev, qual, 0x41);
return;
}
@@ -707,8 +707,8 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Leave short or middle distance condition, restore r17
* to the dynamic tuning range.
*/
- if (link->vgc_level_reg >= 0x41) {
- rt2500pci_set_vgc(rt2x00dev, link->vgc_level);
+ if (qual->vgc_level_reg >= 0x41) {
+ rt2500pci_set_vgc(rt2x00dev, qual, qual->vgc_level);
return;
}
@@ -718,12 +718,12 @@ dynamic_cca_tune:
* R17 is inside the dynamic tuning range,
* start tuning the link based on the false cca counter.
*/
- if (link->qual.false_cca > 512 && link->vgc_level_reg < 0x40) {
- rt2500pci_set_vgc(rt2x00dev, ++link->vgc_level_reg);
- link->vgc_level = link->vgc_level_reg;
- } else if (link->qual.false_cca < 100 && link->vgc_level_reg > 0x32) {
- rt2500pci_set_vgc(rt2x00dev, --link->vgc_level_reg);
- link->vgc_level = link->vgc_level_reg;
+ if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40) {
+ rt2500pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level_reg);
+ qual->vgc_level = qual->vgc_level_reg;
+ } else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32) {
+ rt2500pci_set_vgc(rt2x00dev, qual, --qual->vgc_level_reg);
+ qual->vgc_level = qual->vgc_level_reg;
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 4de1bc1..79f0771 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -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;
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 8935f2c..dea5022 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -177,52 +177,41 @@ struct antenna_setup {
*/
struct link_qual {
/*
- * Statistics required for Link tuning.
- * For the average RSSI value we use the "Walking average" approach.
- * When adding RSSI to the average value the following calculation
- * is needed:
- *
- * avg_rssi = ((avg_rssi * 7) + rssi) / 8;
+ * Statistics required for Link tuning by driver
+ * The rssi value is provided by rt2x00lib during the
+ * link_tuner() callback function.
+ * The false_cca field is filled during the link_stats()
+ * callback function and could be used during the
+ * link_tuner() callback function.
+ */
+ int rssi;
+ int false_cca;
+
+ /*
+ * VGC levels
+ * Hardware driver will tune the VGC level during each call
+ * to the link_tuner() callback function. This vgc_level is
+ * is determined based on the link quality statistics like
+ * average RSSI and the false CCA count.
*
- * The advantage of this approach is that we only need 1 variable
- * to store the average in (No need for a count and a total).
- * But more importantly, normal average values will over time
- * move less and less towards newly added values this results
- * that with link tuning, the device can have a very good RSSI
- * for a few minutes but when the device is moved away from the AP
- * the average will not decrease fast enough to compensate.
- * The walking average compensates this and will move towards
- * the new values correctly allowing a effective link tuning.
+ * In some cases the drivers need to differentiate between
+ * the currently "desired" VGC level and the level configured
+ * in the hardware. The latter is important to reduce the
+ * number of BBP register reads to reduce register access
+ * overhead. For this reason we store both values here.
*/
- int avg_rssi;
- int false_cca;
+ u8 vgc_level;
+ u8 vgc_level_reg;
/*
* Statistics required for Signal quality calculation.
- * For calculating the Signal quality we have to determine
- * the total number of success and failed RX and TX frames.
- * After that we also use the average RSSI value to help
- * determining the signal quality.
- * For the calculation we will use the following algorithm:
- *
- * rssi_percentage = (avg_rssi * 100) / rssi_offset
- * rx_percentage = (rx_success * 100) / rx_total
- * tx_percentage = (tx_success * 100) / tx_total
- * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
- * (WEIGHT_TX * tx_percentage) +
- * (WEIGHT_RX * rx_percentage)) / 100
- *
- * This value should then be checked to not be greater then 100.
+ * These fields might be changed during the link_stats()
+ * callback function.
*/
- int rx_percentage;
int rx_success;
int rx_failed;
- int tx_percentage;
int tx_success;
int tx_failed;
-#define WEIGHT_RSSI 20
-#define WEIGHT_RX 40
-#define WEIGHT_TX 40
};
/*
@@ -286,14 +275,16 @@ struct link {
struct link_ant ant;
/*
- * Active VGC level (for false cca tuning)
+ * Currently active average RSSI value
*/
- u8 vgc_level;
+ int avg_rssi;
/*
- * VGC level as configured in register
+ * Currently precalculated percentages of successful
+ * TX and RX frames.
*/
- u8 vgc_level_reg;
+ int rx_percentage;
+ int tx_percentage;
/*
* Work structure for scheduling periodic link tuning.
@@ -302,28 +293,6 @@ struct link {
};
/*
- * Small helper macro to work with moving/walking averages.
- */
-#define MOVING_AVERAGE(__avg, __val, __samples) \
- ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
-
-/*
- * When we lack RSSI information return something less then -80 to
- * tell the driver to tune the device to maximum sensitivity.
- */
-#define DEFAULT_RSSI ( -128 )
-
-/*
- * Link quality access functions.
- */
-static inline int rt2x00_get_link_rssi(struct link *link)
-{
- if (link->qual.avg_rssi && link->qual.rx_success)
- return link->qual.avg_rssi;
- return DEFAULT_RSSI;
-}
-
-/*
* Interface structure
* Per interface configuration details, this structure
* is allocated as the private data for ieee80211_vif.
@@ -522,8 +491,10 @@ struct rt2x00lib_ops {
int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
void (*link_stats) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual);
- void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
- void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
+ void (*reset_tuner) (struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual);
+ void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, const u32 count);
/*
* TX control handlers
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 0462d5a..ee08f11 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -29,6 +29,71 @@
#include "rt2x00.h"
#include "rt2x00lib.h"
+/*
+ * When we lack RSSI information return something less then -80 to
+ * tell the driver to tune the device to maximum sensitivity.
+ */
+#define DEFAULT_RSSI -128
+
+/*
+ * When no TX/RX percentage could be calculated due to lack of
+ * frames on the air, we fallback to a percentage of 50%.
+ * This will assure we will get at least get some decent value
+ * when the link tuner starts.
+ * The value will be dropped and overwritten with the correct (measured)
+ * value anyway during the first run of the link tuner.
+ */
+#define DEFAULT_PERCENTAGE 50
+
+/*
+ * Small helper macro to work with moving/walking averages.
+ * When adding a value to the average value the following calculation
+ * is needed:
+ *
+ * avg_rssi = ((avg_rssi * 7) + rssi) / 8;
+ *
+ * The advantage of this approach is that we only need 1 variable
+ * to store the average in (No need for a count and a total).
+ * But more importantly, normal average values will over time
+ * move less and less towards newly added values this results
+ * that with link tuning, the device can have a very good RSSI
+ * for a few minutes but when the device is moved away from the AP
+ * the average will not decrease fast enough to compensate.
+ * The walking average compensates this and will move towards
+ * the new values correctly allowing a effective link tuning.
+ */
+#define MOVING_AVERAGE(__avg, __val, __samples) \
+ ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
+
+/*
+ * Small helper macro for percentage calculation
+ * This is a very simple macro with the only catch that it will
+ * produce a default value in case no total value was provided.
+ */
+#define PERCENTAGE(__value, __total) \
+ ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
+
+/*
+ * For calculating the Signal quality we have determined
+ * the total number of success and failed RX and TX frames.
+ * With the addition of the average RSSI value we can determine
+ * the link quality using the following algorithm:
+ *
+ * rssi_percentage = (avg_rssi * 100) / rssi_offset
+ * rx_percentage = (rx_success * 100) / rx_total
+ * tx_percentage = (tx_success * 100) / tx_total
+ * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
+ * (WEIGHT_TX * tx_percentage) +
+ * (WEIGHT_RX * rx_percentage)) / 100
+ *
+ * This value should then be checked to not be greater then 100.
+ * This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must
+ * sum up to 100 as well.
+ */
+#define WEIGHT_RSSI 20
+#define WEIGHT_RX 40
+#define WEIGHT_TX 40
+
static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
@@ -191,6 +256,7 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
{
+ struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
struct link_ant *ant = &rt2x00dev->link.ant;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -215,9 +281,9 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update global RSSI
*/
- if (qual->avg_rssi)
- avg_rssi = MOVING_AVERAGE(qual->avg_rssi, rxdesc->rssi, 8);
- qual->avg_rssi = avg_rssi;
+ if (link->avg_rssi)
+ avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8);
+ link->avg_rssi = avg_rssi;
/*
* Update antenna RSSI
@@ -229,21 +295,13 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
{
+ struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
- if (qual->rx_failed || qual->rx_success)
- qual->rx_percentage =
- (qual->rx_success * 100) /
- (qual->rx_failed + qual->rx_success);
- else
- qual->rx_percentage = 50;
-
- if (qual->tx_failed || qual->tx_success)
- qual->tx_percentage =
- (qual->tx_success * 100) /
- (qual->tx_failed + qual->tx_success);
- else
- qual->tx_percentage = 50;
+ link->rx_percentage =
+ PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success);
+ link->tx_percentage =
+ PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success);
qual->rx_success = 0;
qual->rx_failed = 0;
@@ -253,7 +311,7 @@ static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
{
- struct link_qual *qual = &rt2x00dev->link.qual;
+ struct link *link = &rt2x00dev->link;
int rssi_percentage = 0;
int signal;
@@ -267,22 +325,22 @@ int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
* Calculate the different percentages,
* which will be used for the signal.
*/
- rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
+ rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset);
/*
* Add the individual percentages and use the WEIGHT
* defines to calculate the current link signal.
*/
signal = ((WEIGHT_RSSI * rssi_percentage) +
- (WEIGHT_TX * qual->tx_percentage) +
- (WEIGHT_RX * qual->rx_percentage)) / 100;
+ (WEIGHT_TX * link->tx_percentage) +
+ (WEIGHT_RX * link->rx_percentage)) / 100;
return max_t(int, signal, 100);
}
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
{
- struct link_qual *qual = &rt2x00dev->link.qual;
+ struct link *link = &rt2x00dev->link;
/*
* Link tuning should only be performed when
@@ -293,26 +351,13 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
return;
- /*
- * Clear all (possibly) pre-existing quality statistics.
- */
- memset(qual, 0, sizeof(*qual));
-
- /*
- * The RX and TX percentage should start at 50%
- * this will assure we will get at least get some
- * decent value when the link tuner starts.
- * The value will be dropped and overwritten with
- * the correct (measured) value anyway during the
- * first run of the link tuner.
- */
- qual->rx_percentage = 50;
- qual->tx_percentage = 50;
+ link->rx_percentage = DEFAULT_PERCENTAGE;
+ link->tx_percentage = DEFAULT_PERCENTAGE;
rt2x00link_reset_tuner(rt2x00dev, false);
queue_delayed_work(rt2x00dev->hw->workqueue,
- &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
@@ -322,6 +367,8 @@ void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
{
+ struct link_qual *qual = &rt2x00dev->link.qual;
+
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
@@ -334,12 +381,12 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
* first minute after being enabled.
*/
rt2x00dev->link.count = 0;
- rt2x00dev->link.vgc_level = 0;
+ memset(qual, 0, sizeof(*qual));
/*
* Reset the link tuner.
*/
- rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+ rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
if (antenna)
rt2x00link_antenna_reset(rt2x00dev);
@@ -349,6 +396,7 @@ static void rt2x00link_tuner(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, link.work.work);
+ struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
/*
@@ -365,11 +413,22 @@ static void rt2x00link_tuner(struct work_struct *work)
rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
/*
+ * Update quality RSSI for link tuning,
+ * when we have received some frames and we managed to
+ * collect the RSSI data we could use this. Otherwise we
+ * must fallback to the default RSSI value.
+ */
+ if (!link->avg_rssi || !qual->rx_success)
+ qual->rssi = DEFAULT_RSSI;
+ else
+ qual->rssi = link->avg_rssi;
+
+ /*
* Only perform the link tuning when Link tuning
* has been enabled (This could have been disabled from the EEPROM).
*/
if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
- rt2x00dev->ops->lib->link_tuner(rt2x00dev);
+ rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
* Precalculate a portion of the link signal which is
@@ -380,7 +439,7 @@ static void rt2x00link_tuner(struct work_struct *work)
/*
* Send a signal to the led to update the led signal strength.
*/
- rt2x00leds_led_quality(rt2x00dev, qual->avg_rssi);
+ rt2x00leds_led_quality(rt2x00dev, link->avg_rssi);
/*
* Evaluate antenna setup, make this the last step since this could
@@ -391,9 +450,9 @@ static void rt2x00link_tuner(struct work_struct *work)
/*
* Increase tuner counter, and reschedule the next link tuner run.
*/
- rt2x00dev->link.count++;
+ link->count++;
queue_delayed_work(rt2x00dev->hw->workqueue,
- &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index abd7b43..2b72010 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1046,24 +1046,25 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
-static inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
+static inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, u8 vgc_level)
{
- if (rt2x00dev->link.vgc_level != vgc_level) {
+ if (qual->vgc_level != vgc_level) {
rt61pci_bbp_write(rt2x00dev, 17, 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 rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
{
- rt61pci_set_vgc(rt2x00dev, 0x20);
+ rt61pci_set_vgc(rt2x00dev, qual, 0x20);
}
-static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, const u32 count)
{
- struct link *link = &rt2x00dev->link;
- int rssi = rt2x00_get_link_rssi(link);
u8 up_bound;
u8 low_bound;
@@ -1096,32 +1097,32 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
/*
* Special big-R17 for very short distance
*/
- if (rssi >= -35) {
- rt61pci_set_vgc(rt2x00dev, 0x60);
+ if (qual->rssi >= -35) {
+ rt61pci_set_vgc(rt2x00dev, qual, 0x60);
return;
}
/*
* Special big-R17 for short distance
*/
- if (rssi >= -58) {
- rt61pci_set_vgc(rt2x00dev, up_bound);
+ if (qual->rssi >= -58) {
+ rt61pci_set_vgc(rt2x00dev, qual, up_bound);
return;
}
/*
* Special big-R17 for middle-short distance
*/
- if (rssi >= -66) {
- rt61pci_set_vgc(rt2x00dev, low_bound + 0x10);
+ if (qual->rssi >= -66) {
+ rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x10);
return;
}
/*
* Special mid-R17 for middle distance
*/
- if (rssi >= -74) {
- rt61pci_set_vgc(rt2x00dev, low_bound + 0x08);
+ if (qual->rssi >= -74) {
+ rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x08);
return;
}
@@ -1129,12 +1130,12 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special case: Change up_bound based on the rssi.
* Lower up_bound when rssi is weaker then -74 dBm.
*/
- up_bound -= 2 * (-74 - rssi);
+ up_bound -= 2 * (-74 - qual->rssi);
if (low_bound > up_bound)
up_bound = low_bound;
- if (link->vgc_level > up_bound) {
- rt61pci_set_vgc(rt2x00dev, up_bound);
+ if (qual->vgc_level > up_bound) {
+ rt61pci_set_vgc(rt2x00dev, qual, up_bound);
return;
}
@@ -1144,10 +1145,10 @@ dynamic_cca_tune:
* r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count.
*/
- if ((link->qual.false_cca > 512) && (link->vgc_level < up_bound))
- rt61pci_set_vgc(rt2x00dev, ++link->vgc_level);
- else if ((link->qual.false_cca < 100) && (link->vgc_level > low_bound))
- rt61pci_set_vgc(rt2x00dev, --link->vgc_level);
+ if ((qual->false_cca > 512) && (qual->vgc_level < up_bound))
+ rt61pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level);
+ else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound))
+ rt61pci_set_vgc(rt2x00dev, qual, --qual->vgc_level);
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 49fd42a..5992c8f 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -924,24 +924,25 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
-static inline void rt73usb_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
+static inline void rt73usb_set_vgc(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, u8 vgc_level)
{
- if (rt2x00dev->link.vgc_level != vgc_level) {
+ if (qual->vgc_level != vgc_level) {
rt73usb_bbp_write(rt2x00dev, 17, 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 rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
{
- rt73usb_set_vgc(rt2x00dev, 0x20);
+ rt73usb_set_vgc(rt2x00dev, qual, 0x20);
}
-static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, const u32 count)
{
- struct link *link = &rt2x00dev->link;
- int rssi = rt2x00_get_link_rssi(link);
u8 up_bound;
u8 low_bound;
@@ -957,10 +958,10 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
up_bound += 0x10;
}
} else {
- if (rssi > -82) {
+ if (qual->rssi > -82) {
low_bound = 0x1c;
up_bound = 0x40;
- } else if (rssi > -84) {
+ } else if (qual->rssi > -84) {
low_bound = 0x1c;
up_bound = 0x20;
} else {
@@ -984,32 +985,32 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
/*
* Special big-R17 for very short distance
*/
- if (rssi > -35) {
- rt73usb_set_vgc(rt2x00dev, 0x60);
+ if (qual->rssi > -35) {
+ rt73usb_set_vgc(rt2x00dev, qual, 0x60);
return;
}
/*
* Special big-R17 for short distance
*/
- if (rssi >= -58) {
- rt73usb_set_vgc(rt2x00dev, up_bound);
+ if (qual->rssi >= -58) {
+ rt73usb_set_vgc(rt2x00dev, qual, up_bound);
return;
}
/*
* Special big-R17 for middle-short distance
*/
- if (rssi >= -66) {
- rt73usb_set_vgc(rt2x00dev, low_bound + 0x10);
+ if (qual->rssi >= -66) {
+ rt73usb_set_vgc(rt2x00dev, qual, low_bound + 0x10);
return;
}
/*
* Special mid-R17 for middle distance
*/
- if (rssi >= -74) {
- rt73usb_set_vgc(rt2x00dev, low_bound + 0x08);
+ if (qual->rssi >= -74) {
+ rt73usb_set_vgc(rt2x00dev, qual, low_bound + 0x08);
return;
}
@@ -1017,12 +1018,12 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
* Special case: Change up_bound based on the rssi.
* Lower up_bound when rssi is weaker then -74 dBm.
*/
- up_bound -= 2 * (-74 - rssi);
+ up_bound -= 2 * (-74 - qual->rssi);
if (low_bound > up_bound)
up_bound = low_bound;
- if (link->vgc_level > up_bound) {
- rt73usb_set_vgc(rt2x00dev, up_bound);
+ if (qual->vgc_level > up_bound) {
+ rt73usb_set_vgc(rt2x00dev, qual, up_bound);
return;
}
@@ -1032,12 +1033,12 @@ dynamic_cca_tune:
* r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count.
*/
- if ((link->qual.false_cca > 512) && (link->vgc_level < up_bound))
- rt73usb_set_vgc(rt2x00dev,
- min_t(u8, link->vgc_level + 4, up_bound));
- else if ((link->qual.false_cca < 100) && (link->vgc_level > low_bound))
- rt73usb_set_vgc(rt2x00dev,
- max_t(u8, link->vgc_level - 4, low_bound));
+ if ((qual->false_cca > 512) && (qual->vgc_level < up_bound))
+ rt73usb_set_vgc(rt2x00dev, qual,
+ min_t(u8, qual->vgc_level + 4, up_bound));
+ else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound))
+ rt73usb_set_vgc(rt2x00dev, qual,
+ max_t(u8, qual->vgc_level - 4, low_bound));
}
/*
--
1.5.6.1
>From 4c3622010fe750be76403ebe4ad53e6d06ac40da Mon 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.
Signed-off-by: Ivo van Doorn <[email protected]>
---
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(-)
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index ce76a87..8a53f9b 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index dea5022..1612a9c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -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,
};
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index eaec6bd..0777120 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -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);
--
1.5.6.1