From 7d7f19ccb777946df0a8fb7c83189ba2ae08b02e Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 20 Dec 2008 10:52:42 +0100 Subject: rt2x00: Implement Powersaving Listen to IEEE80211_CONF_PS to determine if the device should drop into powersaving mode. This feature depends on the dynamic power save functionality in mac80211. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 53 ++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 987e89009f74..c7ab744f0052 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); } /* -- cgit v1.2.3 From eb20b4e8a6998ca68d9ac0963ee36a1a36fe241d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 20 Dec 2008 10:54:22 +0100 Subject: rt2x00: Reduce calls to bbp_read() The link_tuner() function will always call bbp_read() at the start of the function. Because this is an indirect register access has some costs attached to it (especially for USB hardware). We already store the value read from the register into the vgc_level value inside the link structure. Instead of reading from the register we can read that field directly and base the tuner on that value. This reduces the time the registers are locked with the csr_mutex and speeds up the link_tuner processing. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 49 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c7ab744f0052..94523f7f0d88 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); } /* -- cgit v1.2.3 From 5352ff6510422d9a9bf13b7272f865eb53247f4d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 20 Dec 2008 10:54:54 +0100 Subject: rt2x00: Restrict interface between rt2x00link and drivers Restrict drivers to only access link_qual structure during link tuning. The contents of these fields are for the drivers and all fields are allowed to be changed to values the driver considers correct. This means that some fields need to be moved outside of this structure to restrict access only to rt2x00link itself. This allows some code to be moved outside of the rt2x00.h header and into rt2x00link.c. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 49 ++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 94523f7f0d88..ed829879c941 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); } /* -- cgit v1.2.3 From 91581b627287d8cc3ee382ee038e04c4beca8176 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 20 Dec 2008 10:57:47 +0100 Subject: rt2x00: Split EEPROM_NIC_TX_RX_FIXED The 2 bits in EEPROM_NIC_TX_RX_FIXED each influence a different antenna. We might as well split the definition and directly read the correct bit. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ed829879c941..875bcdcf6bc8 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2230,7 +2230,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); @@ -2374,24 +2375,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; -- cgit v1.2.3 From 076f9582a6b82e54339ee815130315744b730787 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 20 Dec 2008 10:59:02 +0100 Subject: rt2x00: Remove ENTRY_TXD_OFDM_RATE The flag ENTRY_TXD_OFDM_RATE isn't flexible enough to indicate which rate modulation should be used for a frame. This will become a problem when 11n support is added. Remove the flag and replace it with an enum value which can better indicate the exact rate modulation. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 875bcdcf6bc8..82d35a5a4aa7 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)); -- cgit v1.2.3 From 4be8c3873e0b88397866d3ede578503e188f9ad2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Jan 2009 18:28:20 +0100 Subject: mac80211: extend/document powersave API This modifies hardware flags for powersave to support three different flags: * IEEE80211_HW_SUPPORTS_PS - indicates general PS support * IEEE80211_HW_PS_NULLFUNC_STACK - indicates nullfunc sending in software * IEEE80211_HW_SUPPORTS_DYNAMIC_PS - indicates dynamic PS on the device It also adds documentation for all this which explains how to set the various flags. Additionally, it fixes a few things: * a spot where && was used to test flags * enable CONF_PS only when associated again Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 82d35a5a4aa7..549480a963e9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2556,7 +2556,9 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM; + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; rt2x00dev->hw->extra_tx_headroom = 0; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); -- cgit v1.2.3 From 4e54c711b42c3cc8da8a3fdcde3407b86d67ebcc Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 17 Jan 2009 20:42:32 +0100 Subject: rt2x00: Update copyright year to 2009 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 549480a963e9..8a8753e29308 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From 5e790023620ee02486fd64c7e5a6115ce004495d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 17 Jan 2009 20:42:58 +0100 Subject: rt2x00: conf_tx() only need register access for WMM queues conf_tx() in rt61pci and rt73usb only have to check once if the queue_idx indicates a non-WMM queue and break of the function immediately if that is the case. Only the WMM queues need to have the TX configuration written to the registers. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8a8753e29308..3a7eccac8856 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2657,6 +2657,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, struct rt2x00_field32 field; int retval; u32 reg; + u32 offset; /* * First pass the configuration through rt2x00lib, that will @@ -2668,24 +2669,23 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, if (retval) return retval; + /* + * We only need to perform additional register initialization + * for WMM queues/ + */ + if (queue_idx >= 4) + return 0; + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); /* Update WMM TXOP register */ - if (queue_idx < 2) { - field.bit_offset = queue_idx * 16; - field.bit_mask = 0xffff << field.bit_offset; - - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, field, queue->txop); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - } else if (queue_idx < 4) { - field.bit_offset = (queue_idx - 2) * 16; - field.bit_mask = 0xffff << field.bit_offset; - - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, field, queue->txop); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - } + offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2))); + field.bit_offset = (queue_idx & 1) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, offset, reg); /* Update WMM registers */ field.bit_offset = queue_idx * 4; -- cgit v1.2.3 From 9752a7bd7f36557f34283f5d75dfa32578437f08 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 23 Jan 2009 17:03:24 +0100 Subject: rt2x00: Restrict firmware file lengths Add extra security to the drivers for firmware loading, check the firmware file length before uploading it to the hardware. Incorrect lengths might indicate a firmware upgrade (which is not yet supported by the driver) or otherwise incorrect firmware. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3a7eccac8856..d81a8de9dc17 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1199,6 +1199,11 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, int i; u32 reg; + if (len != 8192) { + ERROR(rt2x00dev, "Invalid firmware file length (len=%zu)\n", len); + return -ENOENT; + } + /* * Wait for stable hardware. */ -- cgit v1.2.3 From a2c9b652a12a550d3d8509e9bae43bac396c5076 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 28 Jan 2009 00:32:33 +0100 Subject: rt2x00: Add kill_tx_queue callback function provide rt2x00lib the possibility to kill a particular TX queue. This can be useful when disabling the radio, but more importantly will allow beaconing to be disabled when mac80211 requests this (during scanning for example) Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 37 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d81a8de9dc17..c7ad1b3d4765 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1696,24 +1696,10 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) { - u32 reg; - - rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818); - - /* - * Disable synchronisation. - */ - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); - /* - * Cancel RX and TX. + * Disable power */ - rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); - rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); + rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818); } static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) @@ -1936,6 +1922,24 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } +static void rt61pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid qid) +{ + u32 reg; + + if (qid == QID_BEACON) { + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); + return; + } + + rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, (qid == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, (qid == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, (qid == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, (qid == QID_AC_VO)); + rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); +} + /* * RX control handlers */ @@ -2761,6 +2765,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .write_tx_data = rt2x00pci_write_tx_data, .write_beacon = rt61pci_write_beacon, .kick_tx_queue = rt61pci_kick_tx_queue, + .kill_tx_queue = rt61pci_kill_tx_queue, .fill_rxdone = rt61pci_fill_rxdone, .config_shared_key = rt61pci_config_shared_key, .config_pairwise_key = rt61pci_config_pairwise_key, -- cgit v1.2.3 From 0cbe0064614ace61e08618948f82c6d525e75017 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 28 Jan 2009 00:33:47 +0100 Subject: rt2x00: Validate firmware in driver The get_firmware_crc() callback function isn't flexible enough when dealing with multiple firmware versions. It might in some cases be possible that the firmware file contains multiple CRC checksums. Create the check_firmware() callback function where the driver has complete freedom in how to validate the firmware. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c7ad1b3d4765..0be147f364e7 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1176,34 +1176,41 @@ static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) return fw_name; } -static u16 rt61pci_get_firmware_crc(const void *data, const size_t len) +static int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) { + u16 fw_crc; u16 crc; /* - * Use the crc itu-t algorithm. + * Only support 8kb firmware files. + */ + if (len != 8192) + return FW_BAD_LENGTH; + + /* * The last 2 bytes in the firmware array are the crc checksum itself, * this means that we should never pass those 2 bytes to the crc * algorithm. */ + fw_crc = (data[len - 2] << 8 | data[len - 1]); + + /* + * Use the crc itu-t algorithm. + */ crc = crc_itu_t(0, data, len - 2); crc = crc_itu_t_byte(crc, 0); crc = crc_itu_t_byte(crc, 0); - return crc; + return (fw_crc == crc) ? FW_OK : FW_BAD_CRC; } -static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, - const size_t len) +static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) { int i; u32 reg; - if (len != 8192) { - ERROR(rt2x00dev, "Invalid firmware file length (len=%zu)\n", len); - return -ENOENT; - } - /* * Wait for stable hardware. */ @@ -2750,7 +2757,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .irq_handler = rt61pci_interrupt, .probe_hw = rt61pci_probe_hw, .get_firmware_name = rt61pci_get_firmware_name, - .get_firmware_crc = rt61pci_get_firmware_crc, + .check_firmware = rt61pci_check_firmware, .load_firmware = rt61pci_load_firmware, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, -- cgit v1.2.3 From 53bc647a1a96189be53b68b9e8c40df0f42fc300 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 15 Feb 2009 17:42:48 +0100 Subject: rt2x00: Remove check for rf word 0 The only way rf_write() can be called with word 0 is when the user sends the wrong word index through debugfs. However the values which are send through debugfs are validated using the RF_BASE and RF_SIZE macro values, the most logical solution is to increase RF_BASE with 4 and decrease RF_SIZE with 4 (RF_SIZE has always been 1 word too big) Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 0be147f364e7..2ca8b7a9722c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -123,9 +123,6 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, { u32 reg; - if (!word) - return; - mutex_lock(&rt2x00dev->csr_mutex); /* -- cgit v1.2.3