From 906c110fcc24bdd5bf0fa22d89ac75d99c747e53 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:38:24 +0200 Subject: rt2x00: Implement HW encryption (rt73usb) rt73usb supports hardware encryption. rt73usb supports up to 4 shared keys and up to 64 pairwise keys. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 271 +++++++++++++++++++++++++++++++++- 1 file changed, 265 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 9761eaaa08be..ddba747fed98 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -357,6 +357,219 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ +static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + int timeout; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for shared keys. We have 1 register + * with key valid bits. The goal is simple, read + * the register, if that is full we have no slots + * left. + * Note that each BSS is allowed to have up to 4 + * shared keys, so put a mask over the allowed + * entries. + */ + mask = (0xf << crypto->bssidx); + + rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = SHARED_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + &key_entry, + sizeof(key_entry), + timeout); + + /* + * The cipher types are stored over 2 registers. + * bssidx 0 and 1 keys are stored in SEC_CSR1 and + * bssidx 1 and 2 keys are stored in SEC_CSR5. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + if (key->hw_key_idx < 8) { + field.bit_offset = (3 * key->hw_key_idx); + field.bit_mask = 0x7 << field.bit_offset; + + rt73usb_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt73usb_register_write(rt2x00dev, SEC_CSR1, reg); + } else { + field.bit_offset = (3 * (key->hw_key_idx - 8)); + field.bit_mask = 0x7 << field.bit_offset; + + rt73usb_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt73usb_register_write(rt2x00dev, SEC_CSR5, reg); + } + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * SEC_CSR0 contains only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + mask = 1 << key->hw_key_idx; + + rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt73usb_register_write(rt2x00dev, SEC_CSR0, reg); + + return 0; +} + +static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_pairwise_ta_entry addr_entry; + struct hw_key_entry key_entry; + int timeout; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for pairwise keys. We have 2 registers + * with key valid bits. The goal is simple, read + * the first register, if that is full move to + * the next register. + * When both registers are full, we drop the key, + * otherwise we use the first invalid entry. + */ + rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + if (reg && reg == ~0) { + key->hw_key_idx = 32; + rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + if (reg && reg == ~0) + return -ENOSPC; + } + + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + &key_entry, + sizeof(key_entry), + timeout); + + /* + * Send the address and cipher type to the hardware register. + * This data fits within the CSR cache size, so we can use + * rt73usb_register_multiwrite() directly. + */ + memset(&addr_entry, 0, sizeof(addr_entry)); + memcpy(&addr_entry, crypto->address, ETH_ALEN); + addr_entry.cipher = crypto->cipher; + + reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); + rt73usb_register_multiwrite(rt2x00dev, reg, + &addr_entry, sizeof(addr_entry)); + + /* + * Enable pairwise lookup table for given BSS idx, + * without this received frames will not be decrypted + * by the hardware. + */ + rt73usb_register_read(rt2x00dev, SEC_CSR4, ®); + reg |= (1 << crypto->bssidx); + rt73usb_register_write(rt2x00dev, SEC_CSR4, reg); + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + if (key->hw_key_idx < 32) { + mask = 1 << key->hw_key_idx; + + rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt73usb_register_write(rt2x00dev, SEC_CSR2, reg); + } else { + mask = 1 << (key->hw_key_idx - 32); + + rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt73usb_register_write(rt2x00dev, SEC_CSR3, reg); + } + + return 0; +} + static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -1265,8 +1478,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct txentry_desc *txdesc) + struct sk_buff *skb, + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1280,7 +1493,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_desc_write(txd, 1, word); @@ -1292,6 +1505,11 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { + _rt2x00_desc_write(txd, 3, skbdesc->iv); + _rt2x00_desc_write(txd, 4, skbdesc->eiv); + } + rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(rt2x00dev->tx_power)); @@ -1313,12 +1531,16 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, 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)); - rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, + test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, + test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len - skbdesc->desc_len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); } @@ -1468,6 +1690,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt73usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; u32 word0; @@ -1489,6 +1712,38 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); + rxdesc->cipher_status = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(rxd, 2, &rxdesc->iv); + _rt2x00_desc_read(rxd, 3, &rxdesc->eiv); + _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. It has provided the data seperately but rt2x00lib + * should decide if it should be reinserted. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + + /* + * FIXME: Legacy driver indicates that the frame does + * contain the Michael Mic. Unfortunately, in rt2x00 + * the MIC seems to be missing completely... + */ + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + /* * Obtain the status about this packet. * When frame was received with an OFDM bitrate, @@ -1496,7 +1751,7 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 100kbit/s. */ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->rssi = rt73usb_agc_to_rssi(rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) @@ -1938,6 +2193,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1997,6 +2253,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, @@ -2024,6 +2281,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, + .config_shared_key = rt73usb_config_shared_key, + .config_pairwise_key = rt73usb_config_pairwise_key, .config_filter = rt73usb_config_filter, .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, -- cgit From 8c5e7a5f59f9d11597bd47de28334da318ea0e80 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:38:47 +0200 Subject: rt2x00: Gather channel information in structure Channel information which is read from EEPROM should be read into an array containing per-channel information. This removes the requirement of multiple arrays and makes the channel handling a bit cleaner and easier to expand. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 43 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ddba747fed98..1bd6b3ffca09 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2107,10 +2107,11 @@ static const struct rf_channel rf_vals_5225_2527[] = { }; -static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -2126,21 +2127,11 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); - /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); @@ -2158,14 +2149,26 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels = rf_vals_5225_2527; } - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF5226)) { - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; - spec->tx_power_a = txpower; + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); } + + return 0; } static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -2186,7 +2189,9 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt73usb_probe_hw_mode(rt2x00dev); + retval = rt73usb_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires firmware. -- cgit From ba2ab47129eee76f6f0ef52b4beae30a12cee7f6 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 6 Aug 2008 16:22:17 +0200 Subject: rt2x00: Move lna_gain calculation to config() callback We can optimize lna calculation in IRQ context by calculating most of the value during the config() callback when most of the value is actually influenced. This will be required later by rt2800pci and rt2800usb as well, since they need the lna_gain value during config(). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 41 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 1bd6b3ffca09..4f2eb90aaf07 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -664,6 +664,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } +static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, const int basic_rate_mask) { @@ -918,6 +938,9 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { + /* Always recalculate LNA gain before changing configuration */ + rt73usb_config_lna_gain(rt2x00dev, libconf); + if (flags & CONFIG_UPDATE_PHYMODE) rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) @@ -1644,20 +1667,19 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, */ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) { - u16 eeprom; - u8 offset; + u8 offset = rt2x00dev->lna_gain; u8 lna; lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); switch (lna) { case 3: - offset = 90; + offset += 90; break; case 2: - offset = 74; + offset += 74; break; case 1: - offset = 64; + offset += 64; break; default: return 0; @@ -1673,15 +1695,6 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) else if (lna == 2) offset += 8; } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - offset += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; -- cgit From 008c44825db74c6cdcea13dfb1598896e74fe908 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 6 Aug 2008 17:27:31 +0200 Subject: rt2x00: Add module parameter to disable HW crypto Add a module parameter to rt61 and rt73 to disable HW crypto. The option should only be checked when determining if the SUPPORT_HW_CRYPTO flag should be set or not. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4f2eb90aaf07..f58fd059c9a0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -36,6 +36,13 @@ #include "rt2x00usb.h" #include "rt73usb.h" +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 0; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + /* * Register access. * All access to the CSR registers will go through the methods @@ -2211,7 +2218,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. -- cgit From 2af0a570b45ec315f364ea2c8a6d072cfcaa9d32 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:05:45 +0200 Subject: rt2x00: Initialize txop during conf_tx() callback The txop parameter is supported by rt61pci and rt73usb, and thus should be written to the register instead of using the fixed value set during initialization. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 69 +++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index f58fd059c9a0..636b4e0d0ef5 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1277,16 +1277,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -2246,6 +2236,63 @@ static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + 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; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_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; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + #if 0 /* * Mac80211 demands get_tsf must be atomic. @@ -2283,7 +2330,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, }; -- cgit From 6c6aa3c004e702532cb0f549a96eb2f75636bd3b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:07:16 +0200 Subject: rt2x00: Add Signal type flag Instead of using the PLCP flag to indicate if the signal value is plcp or the bitrate we should add a new flag to mark the bitrate type explicitely. This is usefull when new types are added later for rt2800. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 636b4e0d0ef5..cf236ec533a9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1766,6 +1766,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; -- cgit From 1abc3656e961e62218257a85b3fe0a90ccd9036c Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Fri, 29 Aug 2008 21:07:20 +0200 Subject: rt2x00: skb->data pointer should not include TX descriptor Make sure the skb->data pointer points to the frame data, not the TX descriptor. The frame dumping code relies on that. Signed-off-by: Mattias Nissler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cf236ec533a9..e698ae0efbce 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1556,8 +1556,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); -- cgit From 79636a5fbbdfb303dbf2bfe7a7fa396f40bfac31 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 8 Sep 2008 17:31:49 +0200 Subject: rt2x00: Revert "rt2x00: Fix the beacon length bug" This reverts: b93ce437eba7e0232683326f30d9d1167a872fad rt2x00: Fix the beacon length bug The workaround is no longer required since it has been correctly fixed in rt2x00usb now. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e698ae0efbce..d9ef34c6670c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1572,7 +1572,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); unsigned int beacon_base; u32 reg; - u32 word, len; /* * Add the descriptor in front of the skb. @@ -1581,17 +1580,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); skbdesc->desc = entry->skb->data; - /* - * Adjust the beacon databyte count. The current number is - * calculated before this function gets called, but falsely - * assumes that the descriptor was already present in the SKB. - */ - rt2x00_desc_read(skbdesc->desc, 0, &word); - len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); - len += skbdesc->desc_len; - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); - rt2x00_desc_write(skbdesc->desc, 0, word); - /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. -- cgit From 771fd565195727d12f0b75d918b9fcb9f33a5476 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 8 Sep 2008 19:07:15 +0200 Subject: rt2x00: Make rt2x00 LEDS invisible config option There isn't really a good reason to have the LED configuration options selectable per driver, lets make it default 'y' and make it depend on the NEW_LEDS and LEDS_CLASS interface. Signed-off-by: Ivo van Doorn --- drivers/net/wireless/rt2x00/rt73usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d9ef34c6670c..27dde3e34603 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -292,7 +292,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT73USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt73usb_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -359,7 +359,7 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt73usb_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT73USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1932,7 +1932,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led settings, for correct led behaviour. */ -#ifdef CONFIG_RT73USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); @@ -1965,7 +1965,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); -#endif /* CONFIG_RT73USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ return 0; } -- cgit From acaf908d408ccd49f13aeb46cbd4428a4db174d1 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 22 Sep 2008 19:40:04 +0200 Subject: rt2x00: Fix HW crypto key handling When a crypto key is being removed, rt2x00mac should not reset the key->hw_key_idx value because that will prevent the driver from removing the correct key from the hardware. Furthermore ffz() starts counting at 0 instead of 1, so we don't need to substract 1 from the resulting value. Signed-off-by: Stephen Blackheath Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt73usb.c') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 27dde3e34603..934f8e03c5aa 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -393,7 +393,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, if (reg && reg == mask) return -ENOSPC; - key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + key->hw_key_idx += reg ? ffz(reg) : 0; /* * Upload key to hardware @@ -494,7 +494,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, return -ENOSPC; } - key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + key->hw_key_idx += reg ? ffz(reg) : 0; /* * Upload key to hardware -- cgit