Commit 6bb40dd1 authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville

rt2x00: Add per-interface structure

Rework the interface handling. Delete the interface structure
and replace it with a per-interface structure. This changes the
way rt2x00 handles the active interface drastically.

Copy ieee80211_bss_conf to the this rt2x00_intf structure during
the bss_info_changed() callback function. This will allow us to
reference it later, and removes the requirement for the device flag
SHORT_PREAMBLE flag which is interface specific.

Drivers receive the option to give the maximum number of virtual
interfaces the device can handle. Virtual interface support:
rt2400pci: 1 sta or 1 ap, * monitor interfaces
rt2500pci: 1 sta or 1 ap, * monitor interfaces
rt2500usb: 1 sta or 1 ap, * monitor interfaces
rt61pci: 1 sta or 4 ap, * monitor interfaces
rt73usb: 1 sta or 4 ap, * monitor interfaces

At the moment none of the drivers support AP and STA interfaces
simultaneously, this is a hardware limitation so future support
will be very unlikely.

Each interface structure receives its dedicated beacon entry,
with this we can easily work with beaconing while multiple master
mode interfaces are currently active.

The configuration handlers for the MAC, BSSID and type are
often called together since they all belong to the interface
configuration. Merge the 3 configuration calls and cleanup
the API between rt2x00lib and the drivers. While we are cleaning
up the interface configuration anyway, we might as well clean up
the configuration handler as well.
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9404ef34
...@@ -246,33 +246,23 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) ...@@ -246,33 +246,23 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
/* /*
* Configuration handlers. * Configuration handlers.
*/ */
static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
__le32 *mac) struct rt2x00_intf *intf,
{ struct rt2x00intf_conf *conf,
rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, const unsigned int flags)
(2 * sizeof(__le32)));
}
static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev,
__le32 *bssid)
{
rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
(2 * sizeof(__le32)));
}
static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
const int tsf_sync)
{ {
unsigned int bcn_preload;
u32 reg; u32 reg;
if (flags & CONFIG_UPDATE_TYPE) {
rt2x00pci_register_write(rt2x00dev, CSR14, 0); rt2x00pci_register_write(rt2x00dev, CSR14, 0);
/* /*
* Enable beacon config * Enable beacon config
*/ */
bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg); rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
PREAMBLE + get_duration(IEEE80211_HEADER, 20));
rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
/* /*
...@@ -280,13 +270,23 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, ...@@ -280,13 +270,23 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
*/ */
rt2x00pci_register_read(rt2x00dev, CSR14, &reg); rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1); rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field32(&reg, CSR14_TBCN,
(conf->sync == TSF_SYNC_BEACON));
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0); rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync); rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync);
rt2x00pci_register_write(rt2x00dev, CSR14, reg); 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 rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, static int rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev,
const int short_preamble, const int short_preamble,
const int ack_timeout, const int ack_timeout,
const int ack_consume_time) const int ack_consume_time)
...@@ -327,6 +327,8 @@ static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, ...@@ -327,6 +327,8 @@ static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
return 0;
} }
static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
...@@ -481,8 +483,8 @@ static void rt2400pci_config_duration(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, 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) if (flags & CONFIG_UPDATE_PHYMODE)
rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
...@@ -1553,9 +1555,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { ...@@ -1553,9 +1555,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.write_tx_data = rt2x00pci_write_tx_data, .write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2400pci_kick_tx_queue, .kick_tx_queue = rt2400pci_kick_tx_queue,
.fill_rxdone = rt2400pci_fill_rxdone, .fill_rxdone = rt2400pci_fill_rxdone,
.config_mac_addr = rt2400pci_config_mac_addr, .config_intf = rt2400pci_config_intf,
.config_bssid = rt2400pci_config_bssid,
.config_type = rt2400pci_config_type,
.config_preamble = rt2400pci_config_preamble, .config_preamble = rt2400pci_config_preamble,
.config = rt2400pci_config, .config = rt2400pci_config,
}; };
...@@ -1590,6 +1590,8 @@ static const struct data_queue_desc rt2400pci_queue_atim = { ...@@ -1590,6 +1590,8 @@ static const struct data_queue_desc rt2400pci_queue_atim = {
static const struct rt2x00_ops rt2400pci_ops = { static const struct rt2x00_ops rt2400pci_ops = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.rx = &rt2400pci_queue_rx, .rx = &rt2400pci_queue_rx,
......
...@@ -246,35 +246,25 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) ...@@ -246,35 +246,25 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
/* /*
* Configuration handlers. * Configuration handlers.
*/ */
static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
__le32 *mac) struct rt2x00_intf *intf,
{ struct rt2x00intf_conf *conf,
rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, const unsigned int flags)
(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)
{ {
struct data_queue *queue = struct data_queue *queue =
rt2x00queue_get_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); rt2x00queue_get_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
unsigned int bcn_preload;
u32 reg; u32 reg;
if (flags & CONFIG_UPDATE_TYPE) {
rt2x00pci_register_write(rt2x00dev, CSR14, 0); rt2x00pci_register_write(rt2x00dev, CSR14, 0);
/* /*
* Enable beacon config * Enable beacon config
*/ */
bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg); rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
PREAMBLE + get_duration(IEEE80211_HEADER, 20));
rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN, queue->cw_min); rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN, queue->cw_min);
rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
...@@ -283,13 +273,23 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, ...@@ -283,13 +273,23 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
*/ */
rt2x00pci_register_read(rt2x00dev, CSR14, &reg); rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1); rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field32(&reg, CSR14_TBCN,
(conf->sync == TSF_SYNC_BEACON));
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0); rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync); rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync);
rt2x00pci_register_write(rt2x00dev, CSR14, reg); 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, static int rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev,
const int short_preamble, const int short_preamble,
const int ack_timeout, const int ack_timeout,
const int ack_consume_time) const int ack_consume_time)
...@@ -330,6 +330,8 @@ static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, ...@@ -330,6 +330,8 @@ static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
return 0;
} }
static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
...@@ -529,8 +531,8 @@ static void rt2500pci_config_duration(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, 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) if (flags & CONFIG_UPDATE_PHYMODE)
rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
...@@ -609,9 +611,10 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) ...@@ -609,9 +611,10 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
/* /*
* To prevent collisions with MAC ASIC on chipsets * To prevent collisions with MAC ASIC on chipsets
* up to version C the link tuning should halt after 20 * up to version C the link tuning should halt after 20
* seconds. * seconds while being associated.
*/ */
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D && if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
rt2x00dev->intf_associated &&
rt2x00dev->link.count > 20) rt2x00dev->link.count > 20)
return; return;
...@@ -619,9 +622,12 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) ...@@ -619,9 +622,12 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
/* /*
* Chipset versions C and lower should directly continue * 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; goto dynamic_cca_tune;
/* /*
...@@ -1861,9 +1867,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { ...@@ -1861,9 +1867,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.write_tx_data = rt2x00pci_write_tx_data, .write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2500pci_kick_tx_queue, .kick_tx_queue = rt2500pci_kick_tx_queue,
.fill_rxdone = rt2500pci_fill_rxdone, .fill_rxdone = rt2500pci_fill_rxdone,
.config_mac_addr = rt2500pci_config_mac_addr, .config_intf = rt2500pci_config_intf,
.config_bssid = rt2500pci_config_bssid,
.config_type = rt2500pci_config_type,
.config_preamble = rt2500pci_config_preamble, .config_preamble = rt2500pci_config_preamble,
.config = rt2500pci_config, .config = rt2500pci_config,
}; };
...@@ -1898,6 +1902,8 @@ static const struct data_queue_desc rt2500pci_queue_atim = { ...@@ -1898,6 +1902,8 @@ static const struct data_queue_desc rt2500pci_queue_atim = {
static const struct rt2x00_ops rt2500pci_ops = { static const struct rt2x00_ops rt2500pci_ops = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.rx = &rt2500pci_queue_rx, .rx = &rt2500pci_queue_rx,
......
This diff is collapsed.
...@@ -686,6 +686,7 @@ ...@@ -686,6 +686,7 @@
*/ */
#define EEPROM_BBPTUNE_VGC 0x0034 #define EEPROM_BBPTUNE_VGC 0x0034
#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff) #define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff)
#define EEPROM_BBPTUNE_VGCLOWER FIELD16(0xff00)
/* /*
* EEPROM BBP R17 Tuning. * EEPROM BBP R17 Tuning.
......
...@@ -343,20 +343,22 @@ static inline int rt2x00_update_ant_rssi(struct link *link, int rssi) ...@@ -343,20 +343,22 @@ static inline int rt2x00_update_ant_rssi(struct link *link, int rssi)
/* /*
* Interface structure * 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 * All fields within the rt2x00_intf structure
* to us by the 80211 stack, and is used to request * must be protected with a spinlock.
* new beacons.
*/ */
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. * MAC of the device.
...@@ -367,16 +369,25 @@ struct interface { ...@@ -367,16 +369,25 @@ struct interface {
* BBSID of the AP to associate with. * BBSID of the AP to associate with.
*/ */
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
};
static inline int is_interface_present(struct interface *intf) /*
{ * Entry in the beacon queue which belongs to
return !!intf->id; * this interface. Each interface has its own
} * dedicated beacon entry.
*/
struct queue_entry *beacon;
/*
* Actions that needed rescheduling.
*/
unsigned int delayed_flags;
#define DELAYED_UPDATE_BEACON 0x00000001
#define DELAYED_CONFIG_PREAMBLE 0x00000002
};
static inline int is_interface_type(struct interface *intf, int type) static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
{ {
return intf->type == type; return (struct rt2x00_intf *)vif->drv_priv;
} }
/* /*
...@@ -429,6 +440,37 @@ struct rt2x00lib_conf { ...@@ -429,6 +440,37 @@ struct rt2x00lib_conf {
short eifs; short eifs;
}; };
/*
* 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. * rt2x00lib callback functions.
*/ */
...@@ -495,16 +537,21 @@ struct rt2x00lib_ops { ...@@ -495,16 +537,21 @@ struct rt2x00lib_ops {
/* /*
* Configuration handlers. * Configuration handlers.
*/ */
void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); void (*config_intf) (struct rt2x00_dev *rt2x00dev,
void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); struct rt2x00_intf *intf,
void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type, struct rt2x00intf_conf *conf,
const int tsf_sync); const unsigned int flags);
void (*config_preamble) (struct rt2x00_dev *rt2x00dev, #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 short_preamble,
const int ack_timeout, const int ack_timeout,
const int ack_consume_time); const int ack_consume_time);
void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, void (*config) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf); struct rt2x00lib_conf *libconf,
const unsigned int flags);
#define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) #define CONFIG_UPDATE_PHYMODE ( 1 << 1 )
#define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) #define CONFIG_UPDATE_CHANNEL ( 1 << 2 )
#define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) #define CONFIG_UPDATE_TXPOWER ( 1 << 3 )
...@@ -519,6 +566,8 @@ struct rt2x00lib_ops { ...@@ -519,6 +566,8 @@ struct rt2x00lib_ops {
*/ */
struct rt2x00_ops { struct rt2x00_ops {
const char *name; const char *name;
const unsigned int max_sta_intf;
const unsigned int max_ap_intf;
const unsigned int eeprom_size; const unsigned int eeprom_size;
const unsigned int rf_size; const unsigned int rf_size;
const struct data_queue_desc *rx; const struct data_queue_desc *rx;
...@@ -550,6 +599,7 @@ enum rt2x00_flags { ...@@ -550,6 +599,7 @@ enum rt2x00_flags {
/* /*
* Driver features * Driver features
*/ */
DRIVER_SUPPORT_MIXED_INTERFACES,
DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_FIRMWARE,
DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T, DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T,
DRIVER_REQUIRE_FIRMWARE_CCITT, DRIVER_REQUIRE_FIRMWARE_CCITT,
...@@ -566,7 +616,6 @@ enum rt2x00_flags { ...@@ -566,7 +616,6 @@ enum rt2x00_flags {
CONFIG_EXTERNAL_LNA_BG, CONFIG_EXTERNAL_LNA_BG,
CONFIG_DOUBLE_ANTENNA, CONFIG_DOUBLE_ANTENNA,
CONFIG_DISABLE_LINK_TUNING, CONFIG_DISABLE_LINK_TUNING,
CONFIG_SHORT_PREAMBLE,
}; };
/* /*
...@@ -670,9 +719,14 @@ struct rt2x00_dev { ...@@ -670,9 +719,14 @@ struct rt2x00_dev {
unsigned int packet_filter; 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 * Link quality
...@@ -738,9 +792,8 @@ struct rt2x00_dev { ...@@ -738,9 +792,8 @@ struct rt2x00_dev {
/* /*
* Scheduled work. * Scheduled work.
*/ */
struct work_struct beacon_work; struct work_struct intf_work;
struct work_struct filter_work; struct work_struct filter_work;
struct work_struct config_work;
/* /*
* Data queue arrays for RX, TX and Beacon. * Data queue arrays for RX, TX and Beacon.
......
...@@ -29,64 +29,89 @@ ...@@ -29,64 +29,89 @@
#include "rt2x00.h" #include "rt2x00.h"
#include "rt2x00lib.h" #include "rt2x00lib.h"
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
enum ieee80211_if_types type,
u8 *mac, u8 *bssid)
{
struct rt2x00intf_conf conf;
unsigned int flags = 0;
/* conf.type = type;
* The MAC and BSSID addressess are simple array of bytes,
* these arrays are little endian, so when sending the addressess switch (type) {
* to the drivers, copy the it into a endian-signed variable. case IEEE80211_IF_TYPE_IBSS:
* case IEEE80211_IF_TYPE_AP:
* Note that all devices (except rt2500usb) have 32 bits conf.sync = TSF_SYNC_BEACON;
* register word sizes. This means that whatever variable we break;
* pass _must_ be a multiple of 32 bits. Otherwise the device case IEEE80211_IF_TYPE_STA:
* might not accept what we are sending to it. conf.sync = TSF_SYNC_INFRA;
* This will also make it easier for the driver to write break;
* the data to the device. default:
* conf.sync = TSF_SYNC_NONE;
* Also note that when NULL is passed as address the break;
* we will send 00:00:00:00:00 to the device to clear the address. }
/*
* 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 * This will prevent the device being confused when it wants
* to ACK frames or consideres itself associated. * to ACK frames or consideres itself associated.
*/ */
void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) memset(&conf.mac, 0, sizeof(conf.mac));
{
__le32 reg[2];
memset(&reg, 0, sizeof(reg));
if (mac) if (mac)
memcpy(&reg, mac, ETH_ALEN); memcpy(&conf.mac, mac, ETH_ALEN);
rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, &reg[0]); memset(&conf.bssid, 0, sizeof(conf.bssid));
}
void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
{
__le32 reg[2];
memset(&reg, 0, sizeof(reg));
if (bssid) if (bssid)
memcpy(&reg, bssid, ETH_ALEN); memcpy(&conf.bssid, bssid, ETH_ALEN);
rt2x00dev->ops->lib->config_bssid(rt2x00dev, &reg[0]); 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_type(struct rt2x00_dev *rt2x00dev, const int type) void rt2x00lib_config_preamble(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
const unsigned int short_preamble)
{ {
int tsf_sync; 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;
}
switch (type) { retval = rt2x00dev->ops->lib->config_preamble(rt2x00dev,
case IEEE80211_IF_TYPE_IBSS: short_preamble,
case IEEE80211_IF_TYPE_AP: ack_timeout,
tsf_sync = TSF_SYNC_BEACON; ack_consume_time);
break;
case IEEE80211_IF_TYPE_STA: spin_lock(&intf->lock);
tsf_sync = TSF_SYNC_INFRA;
break; if (retval) {
default: intf->delayed_flags |= DELAYED_CONFIG_PREAMBLE;
tsf_sync = TSF_SYNC_NONE; queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
break;
} }
rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); spin_unlock(&intf->lock);
} }
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
...@@ -113,7 +138,7 @@ 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 * The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup. * 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); rt2x00lib_reset_link_tuner(rt2x00dev);
rt2x00dev->link.ant.active.rx = libconf.ant.rx; rt2x00dev->link.ant.active.rx = libconf.ant.rx;
...@@ -266,7 +291,7 @@ config: ...@@ -266,7 +291,7 @@ config:
/* /*
* Start configuration. * Start configuration.
*/ */
rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf); rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags);
/* /*
* Some configuration changes affect the link quality * Some configuration changes affect the link quality
......
...@@ -136,12 +136,10 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) ...@@ -136,12 +136,10 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
/* /*
* Stop all scheduled work. * Stop all scheduled work.
*/ */
if (work_pending(&rt2x00dev->beacon_work)) if (work_pending(&rt2x00dev->intf_work))
cancel_work_sync(&rt2x00dev->beacon_work); cancel_work_sync(&rt2x00dev->intf_work);
if (work_pending(&rt2x00dev->filter_work)) if (work_pending(&rt2x00dev->filter_work))
cancel_work_sync(&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. * Stop the TX queues.
...@@ -173,7 +171,7 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) ...@@ -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. * When we are enabling the RX, we should also start the link tuner.
*/ */
if (state == STATE_RADIO_RX_ON && if (state == STATE_RADIO_RX_ON &&
is_interface_present(&rt2x00dev->interface)) (rt2x00dev->intf_ap_count || rt2x00dev->intf_sta_count))
rt2x00lib_start_link_tuner(rt2x00dev); rt2x00lib_start_link_tuner(rt2x00dev);
} }
...@@ -401,10 +399,10 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) ...@@ -401,10 +399,10 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
unsigned int filter = rt2x00dev->packet_filter; 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 * we should now clear that field. Otherwise the driver will
* assume nothing has changed (*total_flags will be compared * 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; rt2x00dev->packet_filter = 0;
...@@ -412,41 +410,72 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) ...@@ -412,41 +410,72 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
filter, &filter, 0, NULL); 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 = struct rt2x00_dev *rt2x00dev = data;
container_of(work, struct rt2x00_dev, config_work); struct rt2x00_intf *intf = vif_to_intf(vif);
struct ieee80211_bss_conf bss_conf; 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);
bss_conf.use_short_preamble = memcpy(&conf, &intf->conf, sizeof(conf));
test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); 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);
}
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 * Iterate over each interface and perform the
* of bss_conf is invalid. * requested configurations.
*/ */
rt2x00mac_bss_info_changed(rt2x00dev->hw, rt2x00dev->interface.id, ieee80211_iterate_active_interfaces(rt2x00dev->hw,
&bss_conf, BSS_CHANGED_ERP_PREAMBLE); rt2x00lib_intf_scheduled_iter,
rt2x00dev);
} }
/* /*
* Interrupt context handlers. * 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 = struct rt2x00_intf *intf = vif_to_intf(vif);
container_of(work, struct rt2x00_dev, beacon_work);
struct ieee80211_tx_control control;
struct sk_buff *skb;
skb = ieee80211_beacon_get(rt2x00dev->hw, if (vif->type != IEEE80211_IF_TYPE_AP &&
rt2x00dev->interface.id, &control); vif->type != IEEE80211_IF_TYPE_IBSS)
if (!skb)
return; return;
rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, &control); spin_lock(&intf->lock);
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
dev_kfree_skb(skb); spin_unlock(&intf->lock);
} }
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
...@@ -454,7 +483,11 @@ 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)) if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
return; 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); EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
...@@ -1037,6 +1070,10 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) ...@@ -1037,6 +1070,10 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
return retval; return retval;
} }
rt2x00dev->intf_ap_count = 0;
rt2x00dev->intf_sta_count = 0;
rt2x00dev->intf_associated = 0;
__set_bit(DEVICE_STARTED, &rt2x00dev->flags); __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
return 0; return 0;
...@@ -1053,6 +1090,10 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) ...@@ -1053,6 +1090,10 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
*/ */
rt2x00lib_disable_radio(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); __clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
} }
...@@ -1063,6 +1104,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) ...@@ -1063,6 +1104,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
{ {
int retval = -ENOMEM; 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. * Let the driver probe the device to detect the capabilities.
*/ */
...@@ -1075,16 +1122,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) ...@@ -1075,16 +1122,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
/* /*
* Initialize configuration work. * 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->filter_work, rt2x00lib_packetfilter_scheduled);
INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled);
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
/*
* Reset current working type.
*/
rt2x00dev->interface.type = IEEE80211_IF_TYPE_INVALID;
/* /*
* Allocate queue array. * Allocate queue array.
*/ */
...@@ -1203,9 +1244,30 @@ exit: ...@@ -1203,9 +1244,30 @@ exit:
} }
EXPORT_SYMBOL_GPL(rt2x00lib_suspend); 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) int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{ {
struct interface *intf = &rt2x00dev->interface;
int retval; int retval;
NOTICE(rt2x00dev, "Waking up.\n"); NOTICE(rt2x00dev, "Waking up.\n");
...@@ -1235,9 +1297,12 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) ...@@ -1235,9 +1297,12 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
if (!rt2x00dev->hw->conf.radio_enabled) if (!rt2x00dev->hw->conf.radio_enabled)
rt2x00lib_disable_radio(rt2x00dev); rt2x00lib_disable_radio(rt2x00dev);
rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); /*
rt2x00lib_config_bssid(rt2x00dev, intf->bssid); * Iterator over each active interface to
rt2x00lib_config_type(rt2x00dev, intf->type); * reconfigure the hardware.
*/
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_resume_intf, rt2x00dev);
/* /*
* We are ready again to receive requests from mac80211. * We are ready again to receive requests from mac80211.
...@@ -1253,12 +1318,11 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) ...@@ -1253,12 +1318,11 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
ieee80211_start_queues(rt2x00dev->hw); ieee80211_start_queues(rt2x00dev->hw);
/* /*
* When in Master or Ad-hoc mode, * During interface iteration we might have changed the
* restart Beacon transmitting by faking a beacondone event. * delayed_flags, time to handles the event by calling
* the work handler directly.
*/ */
if (intf->type == IEEE80211_IF_TYPE_AP || rt2x00lib_intf_scheduled(&rt2x00dev->intf_work);
intf->type == IEEE80211_IF_TYPE_IBSS)
rt2x00lib_beacondone(rt2x00dev);
return 0; return 0;
......
...@@ -50,9 +50,13 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev); ...@@ -50,9 +50,13 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev);
/* /*
* Configuration handlers. * Configuration handlers.
*/ */
void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); struct rt2x00_intf *intf,
void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); 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, void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
enum antenna rx, enum antenna tx); enum antenna rx, enum antenna tx);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
......
...@@ -52,11 +52,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, ...@@ -52,11 +52,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
skb_put(skb, size); skb_put(skb, size);
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) 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, frag_skb->data, frag_skb->len, control,
(struct ieee80211_cts *)(skb->data)); (struct ieee80211_cts *)(skb->data));
else else
ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, ieee80211_rts_get(rt2x00dev->hw, control->vif,
frag_skb->data, frag_skb->len, control, frag_skb->data, frag_skb->len, control,
(struct ieee80211_rts *)(skb->data)); (struct ieee80211_rts *)(skb->data));
...@@ -162,19 +162,67 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, ...@@ -162,19 +162,67 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf) struct ieee80211_if_init_conf *conf)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; 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 * Don't allow interfaces to be added
* either the device has disappeared or when * the device has disappeared.
* another interface is already present.
*/ */
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || 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; 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) if (conf->type == IEEE80211_IF_TYPE_AP)
memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
memcpy(&intf->mac, 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, ...@@ -184,8 +232,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* has been initialized. Otherwise the device can reset * has been initialized. Otherwise the device can reset
* the MAC registers. * the MAC registers.
*/ */
rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
rt2x00lib_config_type(rt2x00dev, conf->type);
return 0; return 0;
} }
...@@ -195,7 +242,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, ...@@ -195,7 +242,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf) struct ieee80211_if_init_conf *conf)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; 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 * Don't allow interfaces to be remove while
...@@ -203,21 +250,27 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, ...@@ -203,21 +250,27 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* no interface is present. * no interface is present.
*/ */
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || 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; return;
intf->id = NULL; if (conf->type == IEEE80211_IF_TYPE_AP)
intf->type = IEEE80211_IF_TYPE_INVALID; rt2x00dev->intf_ap_count--;
memset(&intf->bssid, 0x00, ETH_ALEN); else
memset(&intf->mac, 0x00, ETH_ALEN); 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 * Make sure the bssid and mac address registers
* are cleared to prevent false ACKing of frames. * are cleared to prevent false ACKing of frames.
*/ */
rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_intf(rt2x00dev, intf,
rt2x00lib_config_bssid(rt2x00dev, intf->bssid); IEEE80211_IF_TYPE_INVALID, NULL, NULL);
rt2x00lib_config_type(rt2x00dev, intf->type);
} }
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
...@@ -262,7 +315,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, ...@@ -262,7 +315,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_if_conf *conf) struct ieee80211_if_conf *conf)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct interface *intf = &rt2x00dev->interface; struct rt2x00_intf *intf = vif_to_intf(vif);
int status; int status;
/* /*
...@@ -272,12 +325,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, ...@@ -272,12 +325,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
return 0; return 0;
/* spin_lock(&intf->lock);
* If the given type does not match the configured type,
* there has been a problem.
*/
if (conf->type != intf->type)
return -EINVAL;
/* /*
* If the interface does not work in master mode, * If the interface does not work in master mode,
...@@ -286,7 +334,9 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, ...@@ -286,7 +334,9 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
*/ */
if (conf->type != IEEE80211_IF_TYPE_AP) if (conf->type != IEEE80211_IF_TYPE_AP)
memcpy(&intf->bssid, conf->bssid, ETH_ALEN); 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. * 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, ...@@ -342,35 +392,35 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
u32 changes) u32 changes)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
int short_preamble; struct rt2x00_intf *intf = vif_to_intf(vif);
int ack_timeout;
int ack_consume_time;
int difs;
int preamble;
/* /*
* 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)) if (changes & BSS_CHANGED_ASSOC) {
return; rt2x00dev->link.count = 0;
short_preamble = bss_conf->use_short_preamble;
preamble = bss_conf->use_short_preamble ?
SHORT_PREAMBLE : PREAMBLE;
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 (short_preamble) if (bss_conf->assoc)
__set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); rt2x00dev->intf_associated++;
else else
__clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); rt2x00dev->intf_associated--;
}
rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, /*
ack_timeout, ack_consume_time); * 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);
spin_lock(&intf->lock);
memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
spin_unlock(&intf->lock);
}
} }
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
......
...@@ -38,20 +38,14 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -38,20 +38,14 @@ int rt2x00pci_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_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif);
struct queue_entry_priv_pci_tx *priv_tx; struct queue_entry_priv_pci_tx *priv_tx;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct data_queue *queue;
struct queue_entry *entry;
/* if (unlikely(!intf->beacon))
* Just in case mac80211 doesn't set this correctly, return -ENOBUFS;
* but we need this queue set for the descriptor
* initialization. priv_tx = intf->beacon->priv_data;
*/
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;
/* /*
* Fill in skb descriptor * Fill in skb descriptor
...@@ -59,17 +53,25 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -59,17 +53,25 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
skbdesc = get_skb_frame_desc(skb); skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc)); memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data; skbdesc->data = skb->data;
skbdesc->data_len = queue->data_size; skbdesc->data_len = skb->len;
skbdesc->desc = priv_tx->desc; skbdesc->desc = priv_tx->desc;
skbdesc->desc_len = queue->desc_size; skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = entry; 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); rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/* /*
* Enable beacon generation. * 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); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
return 0; return 0;
......
...@@ -46,9 +46,6 @@ ...@@ -46,9 +46,6 @@
* queue would be sufficient. Although this is almost one third of * queue would be sufficient. Although this is almost one third of
* the amount the legacy driver allocated, the queues aren't getting * the amount the legacy driver allocated, the queues aren't getting
* filled to the maximum even when working with the maximum rate. * 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 RX_ENTRIES 12
#define TX_ENTRIES 12 #define TX_ENTRIES 12
......
...@@ -271,46 +271,24 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) ...@@ -271,46 +271,24 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
/* /*
* Configuration handlers. * 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,
u32 tmp; struct rt2x00intf_conf *conf,
const unsigned int flags)
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)));
}
static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
{
u32 tmp;
tmp = le32_to_cpu(bssid[1]);
rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
bssid[1] = cpu_to_le32(tmp);
rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
(2 * sizeof(__le32)));
}
static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
const int tsf_sync)
{ {
unsigned int beacon_base;
u32 reg; u32 reg;
if (flags & CONFIG_UPDATE_TYPE) {
/* /*
* Clear current synchronisation setup. * Clear current synchronisation setup.
* For the Beacon base registers we only need to clear * For the Beacon base registers we only need to clear
* the first byte since that byte contains the VALID and OWNER * the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon. * 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, TXRX_CSR9, 0);
rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); rt2x00pci_register_write(rt2x00dev, beacon_base, 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);
/* /*
* Enable synchronisation. * Enable synchronisation.
...@@ -318,13 +296,32 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, ...@@ -318,13 +296,32 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE,
(tsf_sync == TSF_SYNC_BEACON)); (conf->sync == TSF_SYNC_BEACON));
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync); rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
}
if (flags & CONFIG_UPDATE_MAC) {
reg = le32_to_cpu(conf->mac[1]);
rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
conf->mac[1] = cpu_to_le32(reg);
rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2,
conf->mac, sizeof(conf->mac));
}
if (flags & CONFIG_UPDATE_BSSID) {
reg = le32_to_cpu(conf->bssid[1]);
rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
conf->bssid[1] = cpu_to_le32(reg);
rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4,
conf->bssid, sizeof(conf->bssid));
}
} }
static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, static int rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev,
const int short_preamble, const int short_preamble,
const int ack_timeout, const int ack_timeout,
const int ack_consume_time) const int ack_consume_time)
...@@ -339,6 +336,8 @@ static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, ...@@ -339,6 +336,8 @@ static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE, rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!short_preamble); !!short_preamble);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
return 0;
} }
static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
...@@ -667,8 +666,8 @@ static void rt61pci_config_duration(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, 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) if (flags & CONFIG_UPDATE_PHYMODE)
rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
...@@ -815,6 +814,13 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) ...@@ -815,6 +814,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 * Special big-R17 for very short distance
*/ */
...@@ -866,6 +872,8 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) ...@@ -866,6 +872,8 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
return; return;
} }
dynamic_cca_tune:
/* /*
* r17 does not yet exceed upper limit, continue and base * r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count. * the r17 tuning on the false CCA count.
...@@ -1214,6 +1222,17 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) ...@@ -1214,6 +1222,17 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48); rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); 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. * We must clear the error counters.
* These registers are cleared on read, * These registers are cleared on read,
...@@ -2378,25 +2397,20 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -2378,25 +2397,20 @@ static int rt61pci_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_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif);
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct data_queue *queue; unsigned int beacon_base;
struct queue_entry *entry;
/* if (unlikely(!intf->beacon))
* Just in case the ieee80211 doesn't set this, return -ENOBUFS;
* 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);
/* /*
* We need to append the descriptor in front of the * We need to append the descriptor in front of the
* beacon frame. * beacon frame.
*/ */
if (skb_headroom(skb) < queue->desc_size) { if (skb_headroom(skb) < intf->beacon->queue->desc_size) {
if (pskb_expand_head(skb, queue->desc_size, 0, GFP_ATOMIC)) { if (pskb_expand_head(skb, intf->beacon->queue->desc_size,
0, GFP_ATOMIC)) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
return -ENOMEM; return -ENOMEM;
} }
...@@ -2405,29 +2419,36 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -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. * Add the descriptor in front of the skb.
*/ */
skb_push(skb, queue->desc_size); skb_push(skb, intf->beacon->queue->desc_size);
memset(skb->data, 0, queue->desc_size); memset(skb->data, 0, intf->beacon->queue->desc_size);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
*/ */
skbdesc = get_skb_frame_desc(skb); skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc)); memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data + queue->desc_size; skbdesc->data = skb->data + intf->beacon->queue->desc_size;
skbdesc->data_len = queue->data_size; skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
skbdesc->desc = skb->data; skbdesc->desc = skb->data;
skbdesc->desc_len = queue->desc_size; skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = entry; 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); rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/* /*
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * 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); skb->data, skb->len);
rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); rt61pci_kick_tx_queue(rt2x00dev, control->queue);
return 0; return 0;
} }
...@@ -2469,9 +2490,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { ...@@ -2469,9 +2490,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.write_tx_data = rt2x00pci_write_tx_data, .write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt61pci_kick_tx_queue, .kick_tx_queue = rt61pci_kick_tx_queue,
.fill_rxdone = rt61pci_fill_rxdone, .fill_rxdone = rt61pci_fill_rxdone,
.config_mac_addr = rt61pci_config_mac_addr, .config_intf = rt61pci_config_intf,
.config_bssid = rt61pci_config_bssid,
.config_type = rt61pci_config_type,
.config_preamble = rt61pci_config_preamble, .config_preamble = rt61pci_config_preamble,
.config = rt61pci_config, .config = rt61pci_config,
}; };
...@@ -2491,7 +2510,7 @@ static const struct data_queue_desc rt61pci_queue_tx = { ...@@ -2491,7 +2510,7 @@ static const struct data_queue_desc rt61pci_queue_tx = {
}; };
static const struct data_queue_desc rt61pci_queue_bcn = { static const struct data_queue_desc rt61pci_queue_bcn = {
.entry_num = BEACON_ENTRIES, .entry_num = 4 * BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE, .data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE, .desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci_tx),
...@@ -2499,6 +2518,8 @@ static const struct data_queue_desc rt61pci_queue_bcn = { ...@@ -2499,6 +2518,8 @@ static const struct data_queue_desc rt61pci_queue_bcn = {
static const struct rt2x00_ops rt61pci_ops = { static const struct rt2x00_ops rt61pci_ops = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.rx = &rt61pci_queue_rx, .rx = &rt61pci_queue_rx,
......
...@@ -161,7 +161,9 @@ struct hw_pairwise_ta_entry { ...@@ -161,7 +161,9 @@ struct hw_pairwise_ta_entry {
#define HW_BEACON_BASE1 0x2d00 #define HW_BEACON_BASE1 0x2d00
#define HW_BEACON_BASE2 0x2e00 #define HW_BEACON_BASE2 0x2e00
#define HW_BEACON_BASE3 0x2f00 #define HW_BEACON_BASE3 0x2f00
#define HW_BEACON_OFFSET 0x0100
#define HW_BEACON_OFFSET(__index) \
( HW_BEACON_BASE0 + (__index * 0x0100) )
/* /*
* HOST-MCU shared memory. * HOST-MCU shared memory.
...@@ -234,6 +236,11 @@ struct hw_pairwise_ta_entry { ...@@ -234,6 +236,11 @@ struct hw_pairwise_ta_entry {
/* /*
* MAC_CSR3: STA MAC register 1. * 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 0x300c
#define MAC_CSR3_BYTE4 FIELD32(0x000000ff) #define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
...@@ -251,7 +258,14 @@ struct hw_pairwise_ta_entry { ...@@ -251,7 +258,14 @@ struct hw_pairwise_ta_entry {
/* /*
* MAC_CSR5: BSSID register 1. * 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 0x3014
#define MAC_CSR5_BYTE4 FIELD32(0x000000ff) #define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
......
...@@ -281,46 +281,24 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { ...@@ -281,46 +281,24 @@ static const struct rt2x00debug rt73usb_rt2x00debug = {
/* /*
* Configuration handlers. * 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,
u32 tmp; struct rt2x00intf_conf *conf,
const unsigned int flags)
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)));
}
static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
{
u32 tmp;
tmp = le32_to_cpu(bssid[1]);
rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
bssid[1] = cpu_to_le32(tmp);
rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
(2 * sizeof(__le32)));
}
static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
const int tsf_sync)
{ {
unsigned int beacon_base;
u32 reg; u32 reg;
if (flags & CONFIG_UPDATE_TYPE) {
/* /*
* Clear current synchronisation setup. * Clear current synchronisation setup.
* For the Beacon base registers we only need to clear * For the Beacon base registers we only need to clear
* the first byte since that byte contains the VALID and OWNER * the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon. * 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, TXRX_CSR9, 0);
rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); rt73usb_register_write(rt2x00dev, beacon_base, 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);
/* /*
* Enable synchronisation. * Enable synchronisation.
...@@ -328,13 +306,32 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, ...@@ -328,13 +306,32 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg); rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE,
(tsf_sync == TSF_SYNC_BEACON)); (conf->sync == TSF_SYNC_BEACON));
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync); rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
if (flags & CONFIG_UPDATE_MAC) {
reg = le32_to_cpu(conf->mac[1]);
rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
conf->mac[1] = cpu_to_le32(reg);
rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2,
conf->mac, sizeof(conf->mac));
}
if (flags & CONFIG_UPDATE_BSSID) {
reg = le32_to_cpu(conf->bssid[1]);
rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
conf->bssid[1] = cpu_to_le32(reg);
rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4,
conf->bssid, sizeof(conf->bssid));
}
} }
static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, static int rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
const int short_preamble, const int short_preamble,
const int ack_timeout, const int ack_timeout,
const int ack_consume_time) const int ack_consume_time)
...@@ -342,13 +339,11 @@ static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, ...@@ -342,13 +339,11 @@ static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
u32 reg; u32 reg;
/* /*
* When in atomic context, reschedule and let rt2x00lib * When in atomic context, we should let rt2x00lib
* call this function again. * try this configuration again later.
*/ */
if (in_atomic()) { if (in_atomic())
queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); return -EAGAIN;
return;
}
rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg); rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
...@@ -358,6 +353,8 @@ static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, ...@@ -358,6 +353,8 @@ static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE, rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!short_preamble); !!short_preamble);
rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
return 0;
} }
static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
...@@ -617,8 +614,8 @@ static void rt73usb_config_duration(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, 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) if (flags & CONFIG_UPDATE_PHYMODE)
rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
...@@ -765,6 +762,13 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) ...@@ -765,6 +762,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 * Special big-R17 for very short distance
*/ */
...@@ -815,6 +819,8 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) ...@@ -815,6 +819,8 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
return; return;
} }
dynamic_cca_tune:
/* /*
* r17 does not yet exceed upper limit, continue and base * r17 does not yet exceed upper limit, continue and base
* the r17 tuning on the false CCA count. * the r17 tuning on the false CCA count.
...@@ -1020,6 +1026,17 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) ...@@ -1020,6 +1026,17 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0); rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); 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. * We must clear the error counters.
* These registers are cleared on read, * These registers are cleared on read,
...@@ -1988,49 +2005,49 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -1988,49 +2005,49 @@ 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_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif);
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct data_queue *queue; unsigned int beacon_base;
struct queue_entry *entry; unsigned int timeout;
int timeout;
/* if (unlikely(!intf->beacon))
* Just in case the ieee80211 doesn't set this, return -ENOBUFS;
* 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);
/* /*
* Add the descriptor in front of the skb. * Add the descriptor in front of the skb.
*/ */
skb_push(skb, queue->desc_size); skb_push(skb, intf->beacon->queue->desc_size);
memset(skb->data, 0, queue->desc_size); memset(skb->data, 0, intf->beacon->queue->desc_size);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
*/ */
skbdesc = get_skb_frame_desc(skb); skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc)); memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data + queue->desc_size; skbdesc->data = skb->data + intf->beacon->queue->desc_size;
skbdesc->data_len = queue->data_size; skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
skbdesc->desc = skb->data; skbdesc->desc = skb->data;
skbdesc->desc_len = queue->desc_size; skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = entry; 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); rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/* /*
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, USB_VENDOR_REQUEST_OUT, beacon_base, 0,
HW_BEACON_BASE0, 0x0000,
skb->data, skb->len, timeout); skb->data, skb->len, timeout);
rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); rt73usb_kick_tx_queue(rt2x00dev, control->queue);
return 0; return 0;
} }
...@@ -2071,9 +2088,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { ...@@ -2071,9 +2088,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.get_tx_data_len = rt73usb_get_tx_data_len, .get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt73usb_kick_tx_queue, .kick_tx_queue = rt73usb_kick_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone, .fill_rxdone = rt73usb_fill_rxdone,
.config_mac_addr = rt73usb_config_mac_addr, .config_intf = rt73usb_config_intf,
.config_bssid = rt73usb_config_bssid,
.config_type = rt73usb_config_type,
.config_preamble = rt73usb_config_preamble, .config_preamble = rt73usb_config_preamble,
.config = rt73usb_config, .config = rt73usb_config,
}; };
...@@ -2093,7 +2108,7 @@ static const struct data_queue_desc rt73usb_queue_tx = { ...@@ -2093,7 +2108,7 @@ static const struct data_queue_desc rt73usb_queue_tx = {
}; };
static const struct data_queue_desc rt73usb_queue_bcn = { static const struct data_queue_desc rt73usb_queue_bcn = {
.entry_num = BEACON_ENTRIES, .entry_num = 4 * BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE, .data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE, .desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx), .priv_size = sizeof(struct queue_entry_priv_usb_tx),
...@@ -2101,6 +2116,8 @@ static const struct data_queue_desc rt73usb_queue_bcn = { ...@@ -2101,6 +2116,8 @@ static const struct data_queue_desc rt73usb_queue_bcn = {
static const struct rt2x00_ops rt73usb_ops = { static const struct rt2x00_ops rt73usb_ops = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.max_sta_intf = 1,
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.rx = &rt73usb_queue_rx, .rx = &rt73usb_queue_rx,
......
...@@ -114,6 +114,9 @@ struct hw_pairwise_ta_entry { ...@@ -114,6 +114,9 @@ struct hw_pairwise_ta_entry {
#define HW_BEACON_BASE2 0x2600 #define HW_BEACON_BASE2 0x2600
#define HW_BEACON_BASE3 0x2700 #define HW_BEACON_BASE3 0x2700
#define HW_BEACON_OFFSET(__index) \
( HW_BEACON_BASE0 + (__index * 0x0100) )
/* /*
* MAC Control/Status Registers(CSR). * MAC Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.
...@@ -146,6 +149,11 @@ struct hw_pairwise_ta_entry { ...@@ -146,6 +149,11 @@ struct hw_pairwise_ta_entry {
/* /*
* MAC_CSR3: STA MAC register 1. * 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 0x300c
#define MAC_CSR3_BYTE4 FIELD32(0x000000ff) #define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
...@@ -163,7 +171,14 @@ struct hw_pairwise_ta_entry { ...@@ -163,7 +171,14 @@ struct hw_pairwise_ta_entry {
/* /*
* MAC_CSR5: BSSID register 1. * 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 0x3014
#define MAC_CSR5_BYTE4 FIELD32(0x000000ff) #define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment