diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2400pci.c | 84 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500pci.c | 98 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.c | 207 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 113 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00config.c | 119 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 154 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00lib.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00mac.c | 152 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00pci.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.c | 169 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 179 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.h | 17 |
15 files changed, 826 insertions, 530 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index fc161084a8d3..61766ed800e3 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -246,50 +246,50 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, - __le32 *mac) +static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) { - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, - (2 * sizeof(__le32))); -} + unsigned int bcn_preload; + u32 reg; -static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, - __le32 *bssid) -{ - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, - (2 * sizeof(__le32))); -} + if (flags & CONFIG_UPDATE_TYPE) { + rt2x00pci_register_write(rt2x00dev, CSR14, 0); -static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) -{ - u32 reg; + /* + * Enable beacon config + */ + bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); + rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); + rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); - rt2x00pci_register_write(rt2x00dev, CSR14, 0); + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, + (conf->sync == TSF_SYNC_BEACON)); + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + } - /* - * Enable beacon config - */ - rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); - rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 20)); - rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + if (flags & CONFIG_UPDATE_MAC) + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, + conf->mac, sizeof(conf->mac)); - /* - * Enable synchronisation. - */ - rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON)); - rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); + if (flags & CONFIG_UPDATE_BSSID) + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, + conf->bssid, sizeof(conf->bssid)); } -static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static int rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { int preamble_mask; u32 reg; @@ -327,6 +327,8 @@ static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + return 0; } static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, @@ -481,8 +483,8 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, } static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, - const unsigned int flags, - struct rt2x00lib_conf *libconf) + struct rt2x00lib_conf *libconf, + const unsigned int flags) { if (flags & CONFIG_UPDATE_PHYMODE) rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); @@ -1553,9 +1555,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .write_tx_data = rt2x00pci_write_tx_data, .kick_tx_queue = rt2400pci_kick_tx_queue, .fill_rxdone = rt2400pci_fill_rxdone, - .config_mac_addr = rt2400pci_config_mac_addr, - .config_bssid = rt2400pci_config_bssid, - .config_type = rt2400pci_config_type, + .config_intf = rt2400pci_config_intf, .config_preamble = rt2400pci_config_preamble, .config = rt2400pci_config, }; @@ -1590,6 +1590,8 @@ static const struct data_queue_desc rt2400pci_queue_atim = { static const struct rt2x00_ops rt2400pci_ops = { .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .rx = &rt2400pci_queue_rx, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0a54b6512207..6a558bf74f11 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -246,53 +246,53 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, - __le32 *mac) -{ - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, - (2 * sizeof(__le32))); -} - -static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, - __le32 *bssid) -{ - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, - (2 * sizeof(__le32))); -} - -static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + unsigned int bcn_preload; u32 reg; - rt2x00pci_register_write(rt2x00dev, CSR14, 0); + if (flags & CONFIG_UPDATE_TYPE) { + rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Enable beacon config - */ - rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); - rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 20)); - rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min); - rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + /* + * Enable beacon config + */ + bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); + rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); + rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min); + rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); - /* - * Enable synchronisation. - */ - rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON)); - rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, + (conf->sync == TSF_SYNC_BEACON)); + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + } + + if (flags & CONFIG_UPDATE_MAC) + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, + conf->mac, sizeof(conf->mac)); + + if (flags & CONFIG_UPDATE_BSSID) + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, + conf->bssid, sizeof(conf->bssid)); } -static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static int rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { int preamble_mask; u32 reg; @@ -330,6 +330,8 @@ static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + return 0; } static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, @@ -529,8 +531,8 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, } static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, - const unsigned int flags, - struct rt2x00lib_conf *libconf) + struct rt2x00lib_conf *libconf, + const unsigned int flags) { if (flags & CONFIG_UPDATE_PHYMODE) rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); @@ -609,9 +611,10 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * To prevent collisions with MAC ASIC on chipsets * up to version C the link tuning should halt after 20 - * seconds. + * seconds while being associated. */ if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D && + rt2x00dev->intf_associated && rt2x00dev->link.count > 20) return; @@ -619,9 +622,12 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Chipset versions C and lower should directly continue - * to the dynamic CCA tuning. + * to the dynamic CCA tuning. Chipset version D and higher + * should go straight to dynamic CCA tuning when they + * are not associated. */ - if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D) + if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D || + !rt2x00dev->intf_associated) goto dynamic_cca_tune; /* @@ -1861,9 +1867,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .write_tx_data = rt2x00pci_write_tx_data, .kick_tx_queue = rt2500pci_kick_tx_queue, .fill_rxdone = rt2500pci_fill_rxdone, - .config_mac_addr = rt2500pci_config_mac_addr, - .config_bssid = rt2500pci_config_bssid, - .config_type = rt2500pci_config_type, + .config_intf = rt2500pci_config_intf, .config_preamble = rt2500pci_config_preamble, .config = rt2500pci_config, }; @@ -1898,6 +1902,8 @@ static const struct data_queue_desc rt2500pci_queue_atim = { static const struct rt2x00_ops rt2500pci_ops = { .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .rx = &rt2500pci_queue_rx, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index edc16a5fc754..31258ee24ee3 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -285,70 +285,65 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { /* * Configuration handlers. */ -static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, - __le32 *mac) -{ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac, - (3 * sizeof(__le16))); -} - -static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, - __le32 *bssid) -{ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid, - (3 * sizeof(__le16))); -} - -static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) { + unsigned int bcn_preload; u16 reg; - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + if (flags & CONFIG_UPDATE_TYPE) { + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); - /* - * Enable beacon config - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); - rt2x00_set_field16(®, TXRX_CSR20_OFFSET, - (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6); - if (type == IEEE80211_IF_TYPE_STA) - rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); - else - rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); - rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg); + /* + * Enable beacon config + */ + bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); + rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); + rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, + 2 * (conf->type != IEEE80211_IF_TYPE_STA)); + rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg); - /* - * Enable synchronisation. - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); - rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0); - rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); + /* + * Enable synchronisation. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, + (conf->sync == TSF_SYNC_BEACON)); + rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + } - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, - (tsf_sync == TSF_SYNC_BEACON)); - rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, tsf_sync); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + if (flags & CONFIG_UPDATE_MAC) + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, conf->mac, + (3 * sizeof(__le16))); + + if (flags & CONFIG_UPDATE_BSSID) + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, conf->bssid, + (3 * sizeof(__le16))); } -static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static int rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { u16 reg; /* - * When in atomic context, reschedule and let rt2x00lib - * call this function again. + * When in atomic context, we should let rt2x00lib + * try this configuration again later. */ - if (in_atomic()) { - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); - return; - } + if (in_atomic()) + return -EAGAIN; rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, ack_timeout); @@ -358,6 +353,8 @@ static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); + + return 0; } static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, @@ -518,8 +515,8 @@ static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, } static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, - const unsigned int flags, - struct rt2x00lib_conf *libconf) + struct rt2x00lib_conf *libconf, + const unsigned int flags) { if (flags & CONFIG_UPDATE_PHYMODE) rt2500usb_config_phymode(rt2x00dev, libconf->phymode, @@ -626,6 +623,24 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) u8 low_bound; /* + * Read current r17 value, as well as the sensitivity values + * for the r17 register. + */ + rt2500usb_bbp_read(rt2x00dev, 17, &r17); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound); + up_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER); + low_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCLOWER); + + /* + * If we are not associated, we should go straight to the + * dynamic CCA tuning. + */ + if (!rt2x00dev->intf_associated) + goto dynamic_cca_tune; + + /* * Determine the BBP tuning threshold and correctly * set BBP 24, 25 and 61. */ @@ -651,13 +666,6 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) rt2500usb_bbp_write(rt2x00dev, 61, r61); /* - * Read current r17 value, as well as the sensitivity values - * for the r17 register. - */ - rt2500usb_bbp_read(rt2x00dev, 17, &r17); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens); - - /* * A too low RSSI will cause too much false CCA which will * then corrupt the R17 tuning. To remidy this the tuning should * be stopped (While making sure the R17 value will not exceed limits) @@ -692,14 +700,9 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) * Leave short or middle distance condition, restore r17 * to the dynamic tuning range. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound); - vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER); - low_bound = 0x32; - if (rssi >= -77) - up_bound = vgc_bound; - else - up_bound = vgc_bound - (-77 - rssi); + if (rssi < -77) + up_bound -= (-77 - rssi); if (up_bound < low_bound) up_bound = low_bound; @@ -707,7 +710,16 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) if (r17 > up_bound) { rt2500usb_bbp_write(rt2x00dev, 17, up_bound); rt2x00dev->link.vgc_level = up_bound; - } else if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { + return; + } + +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 < up_bound) { rt2500usb_bbp_write(rt2x00dev, 17, ++r17); rt2x00dev->link.vgc_level = r17; } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { @@ -1203,6 +1215,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; u8 *mac; + u8 bbp; rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); @@ -1257,9 +1270,17 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word); } + /* + * Switch lower vgc bound to current BBP R17 value, + * lower the value a bit for better quality. + */ + rt2500usb_bbp_read(rt2x00dev, 17, &bbp); + bbp -= 6; + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word); } @@ -1270,6 +1291,9 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41); rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word); EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word); + } else { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); } rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word); @@ -1705,40 +1729,40 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); + struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_usb_bcn *priv_bcn; struct skb_frame_desc *skbdesc; - struct data_queue *queue; - struct queue_entry *entry; int pipe = usb_sndbulkpipe(usb_dev, 1); int length; - /* - * Just in case the ieee80211 doesn't set this, - * but we need this queue set for the descriptor - * initialization. - */ - control->queue = IEEE80211_TX_QUEUE_BEACON; - queue = rt2x00queue_get_queue(rt2x00dev, control->queue); - entry = rt2x00queue_get_entry(queue, Q_INDEX); - priv_bcn = entry->priv_data; + if (unlikely(!intf->beacon)) + return -ENOBUFS; + + priv_bcn = intf->beacon->priv_data; /* * Add the descriptor in front of the skb. */ - skb_push(skb, queue->desc_size); - memset(skb->data, 0, queue->desc_size); + skb_push(skb, intf->beacon->queue->desc_size); + memset(skb->data, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->data = skb->data + queue->desc_size; - skbdesc->data_len = queue->data_size; + skbdesc->data = skb->data + intf->beacon->queue->desc_size; + skbdesc->data_len = skb->len - intf->beacon->queue->desc_size; skbdesc->desc = skb->data; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + /* + * Just in case mac80211 doesn't set this correctly, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* @@ -1749,7 +1773,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, length = rt2500usb_get_tx_data_len(rt2x00dev, skb); usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe, - skb->data, length, rt2500usb_beacondone, entry); + skb->data, length, rt2500usb_beacondone, + intf->beacon); /* * Second we need to create the guardian byte. @@ -1759,7 +1784,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, priv_bcn->guardian_data = 0; usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe, &priv_bcn->guardian_data, 1, rt2500usb_beacondone, - entry); + intf->beacon); /* * Send out the guardian byte. @@ -1769,7 +1794,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, /* * Enable beacon generation. */ - rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + rt2500usb_kick_tx_queue(rt2x00dev, control->queue); return 0; } @@ -1805,9 +1830,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, - .config_mac_addr = rt2500usb_config_mac_addr, - .config_bssid = rt2500usb_config_bssid, - .config_type = rt2500usb_config_type, + .config_intf = rt2500usb_config_intf, .config_preamble = rt2500usb_config_preamble, .config = rt2500usb_config, }; @@ -1842,6 +1865,8 @@ static const struct data_queue_desc rt2500usb_queue_atim = { static const struct rt2x00_ops rt2500usb_ops = { .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .rx = &rt2500usb_queue_rx, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index e9f2cd90da58..23ba0c15741f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -686,6 +686,7 @@ */ #define EEPROM_BBPTUNE_VGC 0x0034 #define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff) +#define EEPROM_BBPTUNE_VGCLOWER FIELD16(0xff00) /* * EEPROM BBP R17 Tuning. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6a25195816db..2363ca4903cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -343,20 +343,22 @@ static inline int rt2x00_update_ant_rssi(struct link *link, int rssi) /* * Interface structure - * Configuration details about the current interface. + * Per interface configuration details, this structure + * is allocated as the private data for ieee80211_vif. */ -struct interface { +struct rt2x00_intf { /* - * Interface identification. The value is assigned - * to us by the 80211 stack, and is used to request - * new beacons. + * All fields within the rt2x00_intf structure + * must be protected with a spinlock. */ - struct ieee80211_vif *id; + spinlock_t lock; /* - * Current working type (IEEE80211_IF_TYPE_*). + * BSS configuration. Copied from the structure + * passed to us through the bss_info_changed() + * callback funtion. */ - int type; + struct ieee80211_bss_conf conf; /* * MAC of the device. @@ -367,16 +369,25 @@ struct interface { * BBSID of the AP to associate with. */ u8 bssid[ETH_ALEN]; -}; -static inline int is_interface_present(struct interface *intf) -{ - return !!intf->id; -} + /* + * Entry in the beacon queue which belongs to + * this interface. Each interface has its own + * dedicated beacon entry. + */ + struct queue_entry *beacon; -static inline int is_interface_type(struct interface *intf, int type) + /* + * Actions that needed rescheduling. + */ + unsigned int delayed_flags; +#define DELAYED_UPDATE_BEACON 0x00000001 +#define DELAYED_CONFIG_PREAMBLE 0x00000002 +}; + +static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) { - return intf->type == type; + return (struct rt2x00_intf *)vif->drv_priv; } /* @@ -430,6 +441,37 @@ struct rt2x00lib_conf { }; /* + * Configuration structure wrapper around the + * rt2x00 interface configuration handler. + */ +struct rt2x00intf_conf { + /* + * Interface type + */ + enum ieee80211_if_types type; + + /* + * TSF sync value, this is dependant on the operation type. + */ + enum tsf_sync sync; + + /* + * The MAC and BSSID addressess are simple array of bytes, + * these arrays are little endian, so when sending the addressess + * to the drivers, copy the it into a endian-signed variable. + * + * Note that all devices (except rt2500usb) have 32 bits + * register word sizes. This means that whatever variable we + * pass _must_ be a multiple of 32 bits. Otherwise the device + * might not accept what we are sending to it. + * This will also make it easier for the driver to write + * the data to the device. + */ + __le32 mac[2]; + __le32 bssid[2]; +}; + +/* * rt2x00lib callback functions. */ struct rt2x00lib_ops { @@ -495,16 +537,21 @@ struct rt2x00lib_ops { /* * Configuration handlers. */ - void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); - void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); - void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync); - void (*config_preamble) (struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time); - void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct rt2x00lib_conf *libconf); + void (*config_intf) (struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags); +#define CONFIG_UPDATE_TYPE ( 1 << 1 ) +#define CONFIG_UPDATE_MAC ( 1 << 2 ) +#define CONFIG_UPDATE_BSSID ( 1 << 3 ) + + int (*config_preamble) (struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time); + void (*config) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags); #define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) #define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) #define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) @@ -519,6 +566,8 @@ struct rt2x00lib_ops { */ struct rt2x00_ops { const char *name; + const unsigned int max_sta_intf; + const unsigned int max_ap_intf; const unsigned int eeprom_size; const unsigned int rf_size; const struct data_queue_desc *rx; @@ -550,6 +599,7 @@ enum rt2x00_flags { /* * Driver features */ + DRIVER_SUPPORT_MIXED_INTERFACES, DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T, DRIVER_REQUIRE_FIRMWARE_CCITT, @@ -566,7 +616,6 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, - CONFIG_SHORT_PREAMBLE, }; /* @@ -670,9 +719,14 @@ struct rt2x00_dev { unsigned int packet_filter; /* - * Interface configuration. + * Interface details: + * - Open ap interface count. + * - Open sta interface count. + * - Association count. */ - struct interface interface; + unsigned int intf_ap_count; + unsigned int intf_sta_count; + unsigned int intf_associated; /* * Link quality @@ -738,9 +792,8 @@ struct rt2x00_dev { /* * Scheduled work. */ - struct work_struct beacon_work; + struct work_struct intf_work; struct work_struct filter_work; - struct work_struct config_work; /* * Data queue arrays for RX, TX and Beacon. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index c247ee77b3a3..20231e0c53fa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -29,64 +29,89 @@ #include "rt2x00.h" #include "rt2x00lib.h" - -/* - * The MAC and BSSID addressess are simple array of bytes, - * these arrays are little endian, so when sending the addressess - * to the drivers, copy the it into a endian-signed variable. - * - * Note that all devices (except rt2500usb) have 32 bits - * register word sizes. This means that whatever variable we - * pass _must_ be a multiple of 32 bits. Otherwise the device - * might not accept what we are sending to it. - * This will also make it easier for the driver to write - * the data to the device. - * - * Also note that when NULL is passed as address the - * we will send 00:00:00:00:00 to the device to clear the address. - * This will prevent the device being confused when it wants - * to ACK frames or consideres itself associated. - */ -void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) +void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + enum ieee80211_if_types type, + u8 *mac, u8 *bssid) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - if (mac) - memcpy(®, mac, ETH_ALEN); - - rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, ®[0]); -} + struct rt2x00intf_conf conf; + unsigned int flags = 0; -void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) -{ - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - if (bssid) - memcpy(®, bssid, ETH_ALEN); - - rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]); -} - -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) -{ - int tsf_sync; + conf.type = type; switch (type) { case IEEE80211_IF_TYPE_IBSS: case IEEE80211_IF_TYPE_AP: - tsf_sync = TSF_SYNC_BEACON; + conf.sync = TSF_SYNC_BEACON; break; case IEEE80211_IF_TYPE_STA: - tsf_sync = TSF_SYNC_INFRA; + conf.sync = TSF_SYNC_INFRA; break; default: - tsf_sync = TSF_SYNC_NONE; + conf.sync = TSF_SYNC_NONE; break; } - rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); + /* + * Note that when NULL is passed as address we will send + * 00:00:00:00:00 to the device to clear the address. + * This will prevent the device being confused when it wants + * to ACK frames or consideres itself associated. + */ + memset(&conf.mac, 0, sizeof(conf.mac)); + if (mac) + memcpy(&conf.mac, mac, ETH_ALEN); + + memset(&conf.bssid, 0, sizeof(conf.bssid)); + if (bssid) + memcpy(&conf.bssid, bssid, ETH_ALEN); + + flags |= CONFIG_UPDATE_TYPE; + if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)) + flags |= CONFIG_UPDATE_MAC; + if (bssid || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)) + flags |= CONFIG_UPDATE_BSSID; + + rt2x00dev->ops->lib->config_intf(rt2x00dev, intf, &conf, flags); +} + +void rt2x00lib_config_preamble(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + const unsigned int short_preamble) +{ + int retval; + int ack_timeout; + int ack_consume_time; + + ack_timeout = PLCP + get_duration(ACK_SIZE, 10); + ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); + + if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) + ack_timeout += SHORT_DIFS; + else + ack_timeout += DIFS; + + if (short_preamble) { + ack_timeout += SHORT_PREAMBLE; + ack_consume_time += SHORT_PREAMBLE; + } else { + ack_timeout += PREAMBLE; + ack_consume_time += PREAMBLE; + } + + retval = rt2x00dev->ops->lib->config_preamble(rt2x00dev, + short_preamble, + ack_timeout, + ack_consume_time); + + spin_lock(&intf->lock); + + if (retval) { + intf->delayed_flags |= DELAYED_CONFIG_PREAMBLE; + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); + } + + spin_unlock(&intf->lock); } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, @@ -113,7 +138,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf); + rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA); rt2x00lib_reset_link_tuner(rt2x00dev); rt2x00dev->link.ant.active.rx = libconf.ant.rx; @@ -266,7 +291,7 @@ config: /* * Start configuration. */ - rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf); + rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags); /* * Some configuration changes affect the link quality diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index bc07c56f89b3..014c307c270c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -136,12 +136,10 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Stop all scheduled work. */ - if (work_pending(&rt2x00dev->beacon_work)) - cancel_work_sync(&rt2x00dev->beacon_work); + if (work_pending(&rt2x00dev->intf_work)) + cancel_work_sync(&rt2x00dev->intf_work); if (work_pending(&rt2x00dev->filter_work)) cancel_work_sync(&rt2x00dev->filter_work); - if (work_pending(&rt2x00dev->config_work)) - cancel_work_sync(&rt2x00dev->config_work); /* * Stop the TX queues. @@ -173,7 +171,7 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) * When we are enabling the RX, we should also start the link tuner. */ if (state == STATE_RADIO_RX_ON && - is_interface_present(&rt2x00dev->interface)) + (rt2x00dev->intf_ap_count || rt2x00dev->intf_sta_count)) rt2x00lib_start_link_tuner(rt2x00dev); } @@ -401,10 +399,10 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) unsigned int filter = rt2x00dev->packet_filter; /* - * Since we had stored the filter inside interface.filter, + * Since we had stored the filter inside rt2x00dev->packet_filter, * we should now clear that field. Otherwise the driver will * assume nothing has changed (*total_flags will be compared - * to interface.filter to determine if any action is required). + * to rt2x00dev->packet_filter to determine if any action is required). */ rt2x00dev->packet_filter = 0; @@ -412,41 +410,72 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) filter, &filter, 0, NULL); } -static void rt2x00lib_configuration_scheduled(struct work_struct *work) +static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) { - struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, config_work); - struct ieee80211_bss_conf bss_conf; + struct rt2x00_dev *rt2x00dev = data; + struct rt2x00_intf *intf = vif_to_intf(vif); + struct sk_buff *skb; + struct ieee80211_tx_control control; + struct ieee80211_bss_conf conf; + int delayed_flags; + + /* + * Copy all data we need during this action under the protection + * of a spinlock. Otherwise race conditions might occur which results + * into an invalid configuration. + */ + spin_lock(&intf->lock); + + memcpy(&conf, &intf->conf, sizeof(conf)); + delayed_flags = intf->delayed_flags; + intf->delayed_flags = 0; + + spin_unlock(&intf->lock); + + if (delayed_flags & DELAYED_UPDATE_BEACON) { + skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); + if (skb) { + rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, + &control); + dev_kfree_skb(skb); + } + } + + if (delayed_flags & DELAYED_CONFIG_PREAMBLE) + rt2x00lib_config_preamble(rt2x00dev, intf, + intf->conf.use_short_preamble); +} - bss_conf.use_short_preamble = - test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); +static void rt2x00lib_intf_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, intf_work); /* - * FIXME: shouldn't invoke it this way because all other contents - * of bss_conf is invalid. + * Iterate over each interface and perform the + * requested configurations. */ - rt2x00mac_bss_info_changed(rt2x00dev->hw, rt2x00dev->interface.id, - &bss_conf, BSS_CHANGED_ERP_PREAMBLE); + ieee80211_iterate_active_interfaces(rt2x00dev->hw, + rt2x00lib_intf_scheduled_iter, + rt2x00dev); } /* * Interrupt context handlers. */ -static void rt2x00lib_beacondone_scheduled(struct work_struct *work) +static void rt2x00lib_beacondone_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) { - struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, beacon_work); - struct ieee80211_tx_control control; - struct sk_buff *skb; + struct rt2x00_intf *intf = vif_to_intf(vif); - skb = ieee80211_beacon_get(rt2x00dev->hw, - rt2x00dev->interface.id, &control); - if (!skb) + if (vif->type != IEEE80211_IF_TYPE_AP && + vif->type != IEEE80211_IF_TYPE_IBSS) return; - rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, &control); - - dev_kfree_skb(skb); + spin_lock(&intf->lock); + intf->delayed_flags |= DELAYED_UPDATE_BEACON; + spin_unlock(&intf->lock); } void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) @@ -454,7 +483,11 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) return; - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work); + ieee80211_iterate_active_interfaces(rt2x00dev->hw, + rt2x00lib_beacondone_iter, + rt2x00dev); + + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); @@ -1037,6 +1070,10 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) return retval; } + rt2x00dev->intf_ap_count = 0; + rt2x00dev->intf_sta_count = 0; + rt2x00dev->intf_associated = 0; + __set_bit(DEVICE_STARTED, &rt2x00dev->flags); return 0; @@ -1053,6 +1090,10 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) */ rt2x00lib_disable_radio(rt2x00dev); + rt2x00dev->intf_ap_count = 0; + rt2x00dev->intf_sta_count = 0; + rt2x00dev->intf_associated = 0; + __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } @@ -1064,6 +1105,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) int retval = -ENOMEM; /* + * Make room for rt2x00_intf inside the per-interface + * structure ieee80211_vif. + */ + rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); + + /* * Let the driver probe the device to detect the capabilities. */ retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); @@ -1075,17 +1122,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Initialize configuration work. */ - INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); - INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* - * Reset current working type. - */ - rt2x00dev->interface.type = IEEE80211_IF_TYPE_INVALID; - - /* * Allocate queue array. */ retval = rt2x00queue_allocate(rt2x00dev); @@ -1203,9 +1244,30 @@ exit: } EXPORT_SYMBOL_GPL(rt2x00lib_suspend); +static void rt2x00lib_resume_intf(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct rt2x00_dev *rt2x00dev = data; + struct rt2x00_intf *intf = vif_to_intf(vif); + + spin_lock(&intf->lock); + + rt2x00lib_config_intf(rt2x00dev, intf, + vif->type, intf->mac, intf->bssid); + + + /* + * Master or Ad-hoc mode require a new beacon update. + */ + if (vif->type == IEEE80211_IF_TYPE_AP || + vif->type == IEEE80211_IF_TYPE_IBSS) + intf->delayed_flags |= DELAYED_UPDATE_BEACON; + + spin_unlock(&intf->lock); +} + int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) { - struct interface *intf = &rt2x00dev->interface; int retval; NOTICE(rt2x00dev, "Waking up.\n"); @@ -1235,9 +1297,12 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) if (!rt2x00dev->hw->conf.radio_enabled) rt2x00lib_disable_radio(rt2x00dev); - rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); - rt2x00lib_config_bssid(rt2x00dev, intf->bssid); - rt2x00lib_config_type(rt2x00dev, intf->type); + /* + * Iterator over each active interface to + * reconfigure the hardware. + */ + ieee80211_iterate_active_interfaces(rt2x00dev->hw, + rt2x00lib_resume_intf, rt2x00dev); /* * We are ready again to receive requests from mac80211. @@ -1253,12 +1318,11 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) ieee80211_start_queues(rt2x00dev->hw); /* - * When in Master or Ad-hoc mode, - * restart Beacon transmitting by faking a beacondone event. + * During interface iteration we might have changed the + * delayed_flags, time to handles the event by calling + * the work handler directly. */ - if (intf->type == IEEE80211_IF_TYPE_AP || - intf->type == IEEE80211_IF_TYPE_IBSS) - rt2x00lib_beacondone(rt2x00dev); + rt2x00lib_intf_scheduled(&rt2x00dev->intf_work); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 5c835f42a455..f6789fdaaf6e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -50,9 +50,13 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev); /* * Configuration handlers. */ -void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); -void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); +void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + enum ieee80211_if_types type, + u8 *mac, u8 *bssid); +void rt2x00lib_config_preamble(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + const unsigned int short_preamble); void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, enum antenna rx, enum antenna tx); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f08c151ee4ba..65a2bcd18aa1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -52,11 +52,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, skb_put(skb, size); if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id, + ieee80211_ctstoself_get(rt2x00dev->hw, control->vif, frag_skb->data, frag_skb->len, control, (struct ieee80211_cts *)(skb->data)); else - ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, + ieee80211_rts_get(rt2x00dev->hw, control->vif, frag_skb->data, frag_skb->len, control, (struct ieee80211_rts *)(skb->data)); @@ -162,19 +162,67 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; + struct rt2x00_intf *intf = vif_to_intf(conf->vif); + struct data_queue *queue = + rt2x00queue_get_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct queue_entry *entry = NULL; + unsigned int i; /* - * Don't allow interfaces to be added while - * either the device has disappeared or when - * another interface is already present. + * Don't allow interfaces to be added + * the device has disappeared. */ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - is_interface_present(intf)) + !test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + return -ENODEV; + + /* + * When we don't support mixed interfaces (a combination + * of sta and ap virtual interfaces) then we can only + * add this interface when the rival interface count is 0. + */ + if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) && + ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) || + (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))) + return -ENOBUFS; + + /* + * Check if we exceeded the maximum amount of supported interfaces. + */ + if ((conf->type == IEEE80211_IF_TYPE_AP && + rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) || + (conf->type != IEEE80211_IF_TYPE_AP && + rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)) + return -ENOBUFS; + + /* + * Loop through all beacon queues to find a free + * entry. Since there are as much beacon entries + * as the maximum interfaces, this search shouldn't + * fail. + */ + for (i = 0; i < queue->limit; i++) { + entry = &queue->entries[i]; + if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) + break; + } + + if (unlikely(i == queue->limit)) return -ENOBUFS; - intf->id = conf->vif; - intf->type = conf->type; + /* + * We are now absolutely sure the interface can be created, + * increase interface count and start initialization. + */ + + if (conf->type == IEEE80211_IF_TYPE_AP) + rt2x00dev->intf_ap_count++; + else + rt2x00dev->intf_sta_count++; + + spin_lock_init(&intf->lock); + intf->beacon = entry; + if (conf->type == IEEE80211_IF_TYPE_AP) memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); @@ -184,8 +232,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * has been initialized. Otherwise the device can reset * the MAC registers. */ - rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); - rt2x00lib_config_type(rt2x00dev, conf->type); + rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL); return 0; } @@ -195,7 +242,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; + struct rt2x00_intf *intf = vif_to_intf(conf->vif); /* * Don't allow interfaces to be remove while @@ -203,21 +250,27 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * no interface is present. */ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - !is_interface_present(intf)) + (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || + (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) return; - intf->id = NULL; - intf->type = IEEE80211_IF_TYPE_INVALID; - memset(&intf->bssid, 0x00, ETH_ALEN); - memset(&intf->mac, 0x00, ETH_ALEN); + if (conf->type == IEEE80211_IF_TYPE_AP) + rt2x00dev->intf_ap_count--; + else + rt2x00dev->intf_sta_count--; + + /* + * Release beacon entry so it is available for + * new interfaces again. + */ + __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); /* * Make sure the bssid and mac address registers * are cleared to prevent false ACKing of frames. */ - rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); - rt2x00lib_config_bssid(rt2x00dev, intf->bssid); - rt2x00lib_config_type(rt2x00dev, intf->type); + rt2x00lib_config_intf(rt2x00dev, intf, + IEEE80211_IF_TYPE_INVALID, NULL, NULL); } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); @@ -262,7 +315,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; + struct rt2x00_intf *intf = vif_to_intf(vif); int status; /* @@ -272,12 +325,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; - /* - * If the given type does not match the configured type, - * there has been a problem. - */ - if (conf->type != intf->type) - return -EINVAL; + spin_lock(&intf->lock); /* * If the interface does not work in master mode, @@ -286,7 +334,9 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, */ if (conf->type != IEEE80211_IF_TYPE_AP) memcpy(&intf->bssid, conf->bssid, ETH_ALEN); - rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, intf->bssid); + + spin_unlock(&intf->lock); /* * We only need to initialize the beacon when master mode is enabled. @@ -342,35 +392,35 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct rt2x00_dev *rt2x00dev = hw->priv; - int short_preamble; - int ack_timeout; - int ack_consume_time; - int difs; - int preamble; + struct rt2x00_intf *intf = vif_to_intf(vif); /* - * We only support changing preamble mode. + * When the association status has changed we must reset the link + * tuner counter. This is because some drivers determine if they + * should perform link tuning based on the number of seconds + * while associated or not associated. */ - if (!(changes & BSS_CHANGED_ERP_PREAMBLE)) - return; - - short_preamble = bss_conf->use_short_preamble; - preamble = bss_conf->use_short_preamble ? - SHORT_PREAMBLE : PREAMBLE; + if (changes & BSS_CHANGED_ASSOC) { + rt2x00dev->link.count = 0; - difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS; - ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10); - - ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + if (bss_conf->assoc) + rt2x00dev->intf_associated++; + else + rt2x00dev->intf_associated--; + } - if (short_preamble) - __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); - else - __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + /* + * When the preamble mode has changed, we should perform additional + * configuration steps. For all other changes we are already done. + */ + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + rt2x00lib_config_preamble(rt2x00dev, intf, + bss_conf->use_short_preamble); - rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, - ack_timeout, ack_consume_time); + spin_lock(&intf->lock); + memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); + spin_unlock(&intf->lock); + } } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 63cfe33e95da..764147dd5aea 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -38,20 +38,14 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct rt2x00_intf *intf = vif_to_intf(control->vif); struct queue_entry_priv_pci_tx *priv_tx; struct skb_frame_desc *skbdesc; - struct data_queue *queue; - struct queue_entry *entry; - /* - * Just in case mac80211 doesn't set this correctly, - * but we need this queue set for the descriptor - * initialization. - */ - control->queue = IEEE80211_TX_QUEUE_BEACON; - queue = rt2x00queue_get_queue(rt2x00dev, control->queue); - entry = rt2x00queue_get_entry(queue, Q_INDEX); - priv_tx = entry->priv_data; + if (unlikely(!intf->beacon)) + return -ENOBUFS; + + priv_tx = intf->beacon->priv_data; /* * Fill in skb descriptor @@ -59,17 +53,25 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->data = skb->data; - skbdesc->data_len = queue->data_size; + skbdesc->data_len = skb->len; skbdesc->desc = priv_tx->desc; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; - memcpy(priv_tx->data, skb->data, skb->len); + /* + * Just in case mac80211 doesn't set this correctly, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * Enable beacon generation. + * Write entire beacon with descriptor to register, + * and kick the beacon generator. */ + memcpy(priv_tx->data, skb->data, skb->len); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 507116c6c9fe..75af48eddc25 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -46,9 +46,6 @@ * queue would be sufficient. Although this is almost one third of * the amount the legacy driver allocated, the queues aren't getting * filled to the maximum even when working with the maximum rate. - * - * FIXME: For virtual interfaces we need a different number - * of beacons, since more interfaces require more beacons. */ #define RX_ENTRIES 12 #define TX_ENTRIES 12 diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index b5ab771bbac2..b432cc21d248 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -271,63 +271,60 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) +static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) { - u32 tmp; - - tmp = le32_to_cpu(mac[1]); - rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); - mac[1] = cpu_to_le32(tmp); - - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac, - (2 * sizeof(__le32))); -} + unsigned int beacon_base; + u32 reg; -static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) -{ - u32 tmp; + if (flags & CONFIG_UPDATE_TYPE) { + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); + rt2x00pci_register_write(rt2x00dev, beacon_base, 0); - tmp = le32_to_cpu(bssid[1]); - rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - bssid[1] = cpu_to_le32(tmp); + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, + (conf->sync == TSF_SYNC_BEACON)); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + } - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, - (2 * sizeof(__le32))); -} + if (flags & CONFIG_UPDATE_MAC) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); -static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) -{ - u32 reg; + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, + conf->mac, sizeof(conf->mac)); + } - /* - * Clear current synchronisation setup. - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + if (flags & CONFIG_UPDATE_BSSID) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); + conf->bssid[1] = cpu_to_le32(reg); - /* - * Enable synchronisation. - */ - rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, - (tsf_sync == TSF_SYNC_BEACON)); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, + conf->bssid, sizeof(conf->bssid)); + } } -static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static int rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { u32 reg; @@ -339,6 +336,8 @@ static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); + + return 0; } static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, @@ -667,8 +666,8 @@ static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, } static void rt61pci_config(struct rt2x00_dev *rt2x00dev, - const unsigned int flags, - struct rt2x00lib_conf *libconf) + struct rt2x00lib_conf *libconf, + const unsigned int flags) { if (flags & CONFIG_UPDATE_PHYMODE) rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); @@ -816,6 +815,13 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) } /* + * If we are not associated, we should go straight to the + * dynamic CCA tuning. + */ + if (!rt2x00dev->intf_associated) + goto dynamic_cca_tune; + + /* * Special big-R17 for very short distance */ if (rssi >= -35) { @@ -866,6 +872,8 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) return; } +dynamic_cca_tune: + /* * r17 does not yet exceed upper limit, continue and base * the r17 tuning on the false CCA count. @@ -1215,6 +1223,17 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); /* + * Clear all beacons + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + + /* * We must clear the error counters. * These registers are cleared on read, * so we may pass a useless variable to store the value. @@ -2378,25 +2397,20 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct rt2x00_intf *intf = vif_to_intf(control->vif); struct skb_frame_desc *skbdesc; - struct data_queue *queue; - struct queue_entry *entry; + unsigned int beacon_base; - /* - * Just in case the ieee80211 doesn't set this, - * but we need this queue set for the descriptor - * initialization. - */ - control->queue = IEEE80211_TX_QUEUE_BEACON; - queue = rt2x00queue_get_queue(rt2x00dev, control->queue); - entry = rt2x00queue_get_entry(queue, Q_INDEX); + if (unlikely(!intf->beacon)) + return -ENOBUFS; /* * We need to append the descriptor in front of the * beacon frame. */ - if (skb_headroom(skb) < queue->desc_size) { - if (pskb_expand_head(skb, queue->desc_size, 0, GFP_ATOMIC)) { + if (skb_headroom(skb) < intf->beacon->queue->desc_size) { + if (pskb_expand_head(skb, intf->beacon->queue->desc_size, + 0, GFP_ATOMIC)) { dev_kfree_skb(skb); return -ENOMEM; } @@ -2405,29 +2419,36 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, /* * Add the descriptor in front of the skb. */ - skb_push(skb, queue->desc_size); - memset(skb->data, 0, queue->desc_size); + skb_push(skb, intf->beacon->queue->desc_size); + memset(skb->data, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->data = skb->data + queue->desc_size; - skbdesc->data_len = queue->data_size; + skbdesc->data = skb->data + intf->beacon->queue->desc_size; + skbdesc->data_len = skb->len - intf->beacon->queue->desc_size; skbdesc->desc = skb->data; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, skb->data, skb->len); - rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + rt61pci_kick_tx_queue(rt2x00dev, control->queue); return 0; } @@ -2469,9 +2490,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .write_tx_data = rt2x00pci_write_tx_data, .kick_tx_queue = rt61pci_kick_tx_queue, .fill_rxdone = rt61pci_fill_rxdone, - .config_mac_addr = rt61pci_config_mac_addr, - .config_bssid = rt61pci_config_bssid, - .config_type = rt61pci_config_type, + .config_intf = rt61pci_config_intf, .config_preamble = rt61pci_config_preamble, .config = rt61pci_config, }; @@ -2491,7 +2510,7 @@ static const struct data_queue_desc rt61pci_queue_tx = { }; static const struct data_queue_desc rt61pci_queue_bcn = { - .entry_num = BEACON_ENTRIES, + .entry_num = 4 * BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci_tx), @@ -2499,6 +2518,8 @@ static const struct data_queue_desc rt61pci_queue_bcn = { static const struct rt2x00_ops rt61pci_ops = { .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .rx = &rt61pci_queue_rx, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 10519f8c5783..d291c0fe405c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -161,7 +161,9 @@ struct hw_pairwise_ta_entry { #define HW_BEACON_BASE1 0x2d00 #define HW_BEACON_BASE2 0x2e00 #define HW_BEACON_BASE3 0x2f00 -#define HW_BEACON_OFFSET 0x0100 + +#define HW_BEACON_OFFSET(__index) \ + ( HW_BEACON_BASE0 + (__index * 0x0100) ) /* * HOST-MCU shared memory. @@ -234,6 +236,11 @@ struct hw_pairwise_ta_entry { /* * MAC_CSR3: STA MAC register 1. + * UNICAST_TO_ME_MASK: + * Used to mask off bits from byte 5 of the MAC address + * to determine the UNICAST_TO_ME bit for RX frames. + * The full mask is complemented by BSS_ID_MASK: + * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK */ #define MAC_CSR3 0x300c #define MAC_CSR3_BYTE4 FIELD32(0x000000ff) @@ -251,7 +258,14 @@ struct hw_pairwise_ta_entry { /* * MAC_CSR5: BSSID register 1. - * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID. + * BSS_ID_MASK: + * This mask is used to mask off bits 0 and 1 of byte 5 of the + * BSSID. This will make sure that those bits will be ignored + * when determining the MY_BSS of RX frames. + * 0: 1-BSSID mode (BSS index = 0) + * 1: 2-BSSID mode (BSS index: Byte5, bit 0) + * 2: 2-BSSID mode (BSS index: byte5, bit 1) + * 3: 4-BSSID mode (BSS index: byte5, bit 0 - 1) */ #define MAC_CSR5 0x3014 #define MAC_CSR5_BYTE4 FIELD32(0x000000ff) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 8ebf3fed9815..7907fd0d4aa5 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -281,74 +281,69 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { /* * Configuration handlers. */ -static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) +static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) { - u32 tmp; - - tmp = le32_to_cpu(mac[1]); - rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); - mac[1] = cpu_to_le32(tmp); - - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac, - (2 * sizeof(__le32))); -} + unsigned int beacon_base; + u32 reg; -static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) -{ - u32 tmp; + if (flags & CONFIG_UPDATE_TYPE) { + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + rt73usb_register_write(rt2x00dev, beacon_base, 0); - tmp = le32_to_cpu(bssid[1]); - rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - bssid[1] = cpu_to_le32(tmp); + /* + * Enable synchronisation. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, + (conf->sync == TSF_SYNC_BEACON)); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + } - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, - (2 * sizeof(__le32))); -} + if (flags & CONFIG_UPDATE_MAC) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); -static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) -{ - u32 reg; + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, + conf->mac, sizeof(conf->mac)); + } - /* - * Clear current synchronisation setup. - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + if (flags & CONFIG_UPDATE_BSSID) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); + conf->bssid[1] = cpu_to_le32(reg); - /* - * Enable synchronisation. - */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, - (tsf_sync == TSF_SYNC_BEACON)); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, + conf->bssid, sizeof(conf->bssid)); + } } -static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static int rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { u32 reg; /* - * When in atomic context, reschedule and let rt2x00lib - * call this function again. + * When in atomic context, we should let rt2x00lib + * try this configuration again later. */ - if (in_atomic()) { - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); - return; - } + if (in_atomic()) + return -EAGAIN; rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); @@ -358,6 +353,8 @@ static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!short_preamble); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + + return 0; } static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, @@ -617,8 +614,8 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, } static void rt73usb_config(struct rt2x00_dev *rt2x00dev, - const unsigned int flags, - struct rt2x00lib_conf *libconf) + struct rt2x00lib_conf *libconf, + const unsigned int flags) { if (flags & CONFIG_UPDATE_PHYMODE) rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); @@ -766,6 +763,13 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) } /* + * If we are not associated, we should go straight to the + * dynamic CCA tuning. + */ + if (!rt2x00dev->intf_associated) + goto dynamic_cca_tune; + + /* * Special big-R17 for very short distance */ if (rssi > -35) { @@ -815,6 +819,8 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) return; } +dynamic_cca_tune: + /* * r17 does not yet exceed upper limit, continue and base * the r17 tuning on the false CCA count. @@ -1021,6 +1027,17 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); /* + * Clear all beacons + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + + /* * We must clear the error counters. * These registers are cleared on read, * so we may pass a useless variable to store the value. @@ -1985,52 +2002,52 @@ static void rt73usb_reset_tsf(struct ieee80211_hw *hw) } static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct rt2x00_intf *intf = vif_to_intf(control->vif); struct skb_frame_desc *skbdesc; - struct data_queue *queue; - struct queue_entry *entry; - int timeout; + unsigned int beacon_base; + unsigned int timeout; - /* - * Just in case the ieee80211 doesn't set this, - * but we need this queue set for the descriptor - * initialization. - */ - control->queue = IEEE80211_TX_QUEUE_BEACON; - queue = rt2x00queue_get_queue(rt2x00dev, control->queue); - entry = rt2x00queue_get_entry(queue, Q_INDEX); + if (unlikely(!intf->beacon)) + return -ENOBUFS; /* * Add the descriptor in front of the skb. */ - skb_push(skb, queue->desc_size); - memset(skb->data, 0, queue->desc_size); + skb_push(skb, intf->beacon->queue->desc_size); + memset(skb->data, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor */ skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->data = skb->data + queue->desc_size; - skbdesc->data_len = queue->data_size; + skbdesc->data = skb->data + intf->beacon->queue->desc_size; + skbdesc->data_len = skb->len - intf->beacon->queue->desc_size; skbdesc->desc = skb->data; - skbdesc->desc_len = queue->desc_size; - skbdesc->entry = entry; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * Write entire beacon with descriptor to register, * and kick the beacon generator. */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, - HW_BEACON_BASE0, 0x0000, + USB_VENDOR_REQUEST_OUT, beacon_base, 0, skb->data, skb->len, timeout); - rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + rt73usb_kick_tx_queue(rt2x00dev, control->queue); return 0; } @@ -2071,9 +2088,7 @@ 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_mac_addr = rt73usb_config_mac_addr, - .config_bssid = rt73usb_config_bssid, - .config_type = rt73usb_config_type, + .config_intf = rt73usb_config_intf, .config_preamble = rt73usb_config_preamble, .config = rt73usb_config, }; @@ -2093,7 +2108,7 @@ static const struct data_queue_desc rt73usb_queue_tx = { }; static const struct data_queue_desc rt73usb_queue_bcn = { - .entry_num = BEACON_ENTRIES, + .entry_num = 4 * BEACON_ENTRIES, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb_tx), @@ -2101,6 +2116,8 @@ static const struct data_queue_desc rt73usb_queue_bcn = { static const struct rt2x00_ops rt73usb_ops = { .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .rx = &rt73usb_queue_rx, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index da62b4f091a7..3f9675655eb9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -114,6 +114,9 @@ struct hw_pairwise_ta_entry { #define HW_BEACON_BASE2 0x2600 #define HW_BEACON_BASE3 0x2700 +#define HW_BEACON_OFFSET(__index) \ + ( HW_BEACON_BASE0 + (__index * 0x0100) ) + /* * MAC Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. @@ -146,6 +149,11 @@ struct hw_pairwise_ta_entry { /* * MAC_CSR3: STA MAC register 1. + * UNICAST_TO_ME_MASK: + * Used to mask off bits from byte 5 of the MAC address + * to determine the UNICAST_TO_ME bit for RX frames. + * The full mask is complemented by BSS_ID_MASK: + * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK */ #define MAC_CSR3 0x300c #define MAC_CSR3_BYTE4 FIELD32(0x000000ff) @@ -163,7 +171,14 @@ struct hw_pairwise_ta_entry { /* * MAC_CSR5: BSSID register 1. - * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID. + * BSS_ID_MASK: + * This mask is used to mask off bits 0 and 1 of byte 5 of the + * BSSID. This will make sure that those bits will be ignored + * when determining the MY_BSS of RX frames. + * 0: 1-BSSID mode (BSS index = 0) + * 1: 2-BSSID mode (BSS index: Byte5, bit 0) + * 2: 2-BSSID mode (BSS index: byte5, bit 1) + * 3: 4-BSSID mode (BSS index: byte5, bit 0 - 1) */ #define MAC_CSR5 0x3014 #define MAC_CSR5_BYTE4 FIELD32(0x000000ff) |