diff options
Diffstat (limited to 'drivers/net/wireless')
197 files changed, 19785 insertions, 32296 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 714a6ca30ad..fdf5aa8b842 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -146,12 +146,15 @@ config IPW2100 configure your card: <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + + It is recommended that you compile this driver as a module (M) + rather than built-in (Y). This driver requires firmware at device + initialization time, and when built-in this typically happens + before the filesystem is accessible (hence firmware will be + unavailable and initialization will fail). If you do choose to build + this driver into your kernel image, you can avoid this problem by + including the firmware and a firmware loader in an initramfs. - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt>. - The module will be called ipw2100.ko. - config IPW2100_MONITOR bool "Enable promiscuous mode" depends on IPW2100 @@ -201,11 +204,14 @@ config IPW2200 configure your card: <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt>. - The module will be called ipw2200.ko. + + It is recommended that you compile this driver as a module (M) + rather than built-in (Y). This driver requires firmware at device + initialization time, and when built-in this typically happens + before the filesystem is accessible (hence firmware will be + unavailable and initialization will fail). If you do choose to build + this driver into your kernel image, you can avoid this problem by + including the firmware and a firmware loader in an initramfs. config IPW2200_MONITOR bool "Enable promiscuous mode" @@ -265,7 +271,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 select WIRELESS_EXT - select IEEE80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices. @@ -278,7 +283,7 @@ config LIBERTAS_USB config LIBERTAS_CS tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA && EXPERIMENTAL + depends on LIBERTAS && PCMCIA select FW_LOADER ---help--- A driver for Marvell Libertas 8385 CompactFlash devices. @@ -668,90 +673,10 @@ config ADM8211 Thanks to Infineon-ADMtek for their support of this driver. -config P54_COMMON - tristate "Softmac Prism54 support" - depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL - ---help--- - This is common code for isl38xx based cards. - This module does nothing by itself - the USB/PCI frontends - also need to be enabled in order to support any devices. - - These devices require softmac firmware which can be found at - http://prism54.org/ - - If you choose to build a module, it'll be called p54common. - -config P54_USB - tristate "Prism54 USB support" - depends on P54_COMMON && USB - select CRC32 - ---help--- - This driver is for USB isl38xx based wireless cards. - These are USB based adapters found in devices such as: - - 3COM 3CRWE254G72 - SMC 2862W-G - Accton 802.11g WN4501 USB - Siemens Gigaset USB - Netgear WG121 - Netgear WG111 - Medion 40900, Roper Europe - Shuttle PN15, Airvast WM168g, IOGear GWU513 - Linksys WUSB54G - Linksys WUSB54G Portable - DLink DWL-G120 Spinnaker - DLink DWL-G122 - Belkin F5D7050 ver 1000 - Cohiba Proto board - SMC 2862W-G version 2 - U.S. Robotics U5 802.11g Adapter - FUJITSU E-5400 USB D1700 - Sagem XG703A - DLink DWL-G120 Cohiba - Spinnaker Proto board - Linksys WUSB54AG - Inventel UR054G - Spinnaker DUT - - These devices require softmac firmware which can be found at - http://prism54.org/ - - If you choose to build a module, it'll be called p54usb. - -config P54_PCI - tristate "Prism54 PCI support" - depends on P54_COMMON && PCI - ---help--- - This driver is for PCI isl38xx based wireless cards. - This driver supports most devices that are supported by the - fullmac prism54 driver plus many devices which are not - supported by the fullmac driver/firmware. - - This driver requires softmac firmware which can be found at - http://prism54.org/ - - If you choose to build a module, it'll be called p54pci. - -config ATH5K - tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL - ---help--- - This module adds support for wireless adapters based on - Atheros 5xxx chipset. - - Currently the following chip versions are supported: - - MAC: AR5211 AR5212 - PHY: RF5111/2111 RF5112/2112 RF5413/2413 - - This driver uses the kernel's mac80211 subsystem. - - If you choose to build a module, it'll be called ath5k. Say M if - unsure. - +source "drivers/net/wireless/p54/Kconfig" +source "drivers/net/wireless/ath5k/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" -source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 091dfe2e574..70092191fc5 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ -obj-$(CONFIG_BCM43XX) += bcm43xx/ obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ @@ -61,8 +60,6 @@ obj-$(CONFIG_IWL3945) += iwlwifi/ obj-$(CONFIG_IWL4965) += iwlwifi/ obj-$(CONFIG_RT2X00) += rt2x00/ -obj-$(CONFIG_P54_COMMON) += p54common.o -obj-$(CONFIG_P54_USB) += p54usb.o -obj-$(CONFIG_P54_PCI) += p54pci.o +obj-$(CONFIG_P54_COMMON) += p54/ obj-$(CONFIG_ATH5K) += ath5k/ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 79796186713..5c0d2b08275 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -48,6 +48,32 @@ static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { { 0 } }; +static struct ieee80211_rate adm8211_rates[] = { + { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 220, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, /* XX ?? */ +}; + +static const struct ieee80211_channel adm8211_channels[] = { + { .center_freq = 2412}, + { .center_freq = 2417}, + { .center_freq = 2422}, + { .center_freq = 2427}, + { .center_freq = 2432}, + { .center_freq = 2437}, + { .center_freq = 2442}, + { .center_freq = 2447}, + { .center_freq = 2452}, + { .center_freq = 2457}, + { .center_freq = 2462}, + { .center_freq = 2467}, + { .center_freq = 2472}, + { .center_freq = 2484}, +}; + + static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom) { struct adm8211_priv *priv = eeprom->data; @@ -155,17 +181,17 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n", pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max); - priv->modes[0].num_channels = chan_range.max - chan_range.min + 1; - priv->modes[0].channels = priv->channels; + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(adm8211_channels)); - memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels)); + memcpy(priv->channels, adm8211_channels, sizeof(priv->channels)); + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(adm8211_channels); + priv->band.bitrates = adm8211_rates; + priv->band.n_bitrates = ARRAY_SIZE(adm8211_rates); for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++) - if (i >= chan_range.min && i <= chan_range.max) - priv->channels[i - 1].flag = - IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; + if (i < chan_range.min || i > chan_range.max) + priv->channels[i - 1].flags |= IEEE80211_CHAN_DISABLED; switch (priv->eeprom->specific_bbptype) { case ADM8211_BBP_RFMD3000: @@ -347,7 +373,6 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) unsigned int pktlen; struct sk_buff *skb, *newskb; unsigned int limit = priv->rx_ring_size; - static const u8 rate_tbl[] = {10, 20, 55, 110, 220}; u8 rssi, rate; while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) { @@ -425,12 +450,10 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) else rx_status.ssi = 100 - rssi; - if (rate <= 4) - rx_status.rate = rate_tbl[rate]; + rx_status.rate_idx = rate; - rx_status.channel = priv->channel; - rx_status.freq = adm8211_channels[priv->channel - 1].freq; - rx_status.phymode = MODE_IEEE80211B; + rx_status.freq = adm8211_channels[priv->channel - 1].center_freq; + rx_status.band = IEEE80211_BAND_2GHZ; ieee80211_rx_irqsafe(dev, skb, &rx_status); } @@ -465,9 +488,6 @@ do { \ if (stsr & ADM8211_STSR_TCI) adm8211_interrupt_tci(dev); - /*ADM8211_INT(LinkOn);*/ - /*ADM8211_INT(LinkOff);*/ - ADM8211_INT(PCF); ADM8211_INT(BCNTC); ADM8211_INT(GPINT); @@ -477,7 +497,6 @@ do { \ ADM8211_INT(SQL); ADM8211_INT(WEPTD); ADM8211_INT(ATIME); - /*ADM8211_INT(TBTT);*/ ADM8211_INT(TEIS); ADM8211_INT(FBE); ADM8211_INT(REIS); @@ -485,9 +504,6 @@ do { \ ADM8211_INT(RPS); ADM8211_INT(RDU); ADM8211_INT(TUF); - /*ADM8211_INT(TRT);*/ - /*ADM8211_INT(TLT);*/ - /*ADM8211_INT(TDU);*/ ADM8211_INT(TPS); return IRQ_HANDLED; @@ -1054,7 +1070,7 @@ static int adm8211_set_rate(struct ieee80211_hw *dev) if (priv->pdev->revision != ADM8211_REV_BA) { rate_buf[0] = ARRAY_SIZE(adm8211_rates); for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) - rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; + rate_buf[i + 1] = (adm8211_rates[i].bitrate / 5) | 0x80; } else { /* workaround for rev BA specific bug */ rate_buf[0] = 0x04; @@ -1086,7 +1102,7 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) u32 reg; u8 cline; - reg = le32_to_cpu(ADM8211_CSR_READ(PAR)); + reg = ADM8211_CSR_READ(PAR); reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME; reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL); @@ -1303,9 +1319,10 @@ static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct adm8211_priv *priv = dev->priv; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - if (conf->channel != priv->channel) { - priv->channel = conf->channel; + if (channel != priv->channel) { + priv->channel = channel; adm8211_rf_set_channel(dev, priv->channel); } @@ -1678,13 +1695,9 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; - if (control->tx_rate < 0) { - short_preamble = 1; - plcp_signal = -control->tx_rate; - } else { - short_preamble = 0; - plcp_signal = control->tx_rate; - } + short_preamble = !!(control->tx_rate->flags & + IEEE80211_TXCTL_SHORT_PREAMBLE); + plcp_signal = control->tx_rate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; @@ -1880,18 +1893,11 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, SET_IEEE80211_PERM_ADDR(dev, perm_addr); dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); - dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; - /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ dev->channel_change_time = 1000; dev->max_rssi = 100; /* FIXME: find better value */ - priv->modes[0].mode = MODE_IEEE80211B; - /* channel info filled in by adm8211_read_eeprom */ - memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates)); - priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates); - priv->modes[0].rates = priv->rates; - dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ priv->retry_limit = 3; @@ -1917,14 +1923,9 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - priv->channel = priv->modes[0].channels[0].chan; + priv->channel = 1; - err = ieee80211_register_hwmode(dev, &priv->modes[0]); - if (err) { - printk(KERN_ERR "%s (adm8211): Can't register hwmode\n", - pci_name(pdev)); - goto err_free_desc; - } + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; err = ieee80211_register_hw(dev); if (err) { diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index ef326fed42e..8d7c564b3b0 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -534,61 +534,6 @@ struct adm8211_eeprom { u8 cis_data[0]; /* 0x80, 384 bytes */ } __attribute__ ((packed)); -static const struct ieee80211_rate adm8211_rates[] = { - { .rate = 10, - .val = 10, - .val2 = -10, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 20, - .val = 20, - .val2 = -20, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 55, - .val = 55, - .val2 = -55, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 110, - .val = 110, - .val2 = -110, - .flags = IEEE80211_RATE_CCK_2 } -}; - -struct ieee80211_chan_range { - u8 min; - u8 max; -}; - -static const struct ieee80211_channel adm8211_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484}, -}; - struct adm8211_priv { struct pci_dev *pdev; spinlock_t lock; @@ -603,9 +548,8 @@ struct adm8211_priv { unsigned int cur_tx, dirty_tx, cur_rx; struct ieee80211_low_level_stats stats; - struct ieee80211_hw_mode modes[1]; - struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)]; - struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)]; + struct ieee80211_supported_band band; + struct ieee80211_channel channels[14]; int mode; int channel; @@ -643,6 +587,11 @@ struct adm8211_priv { } transceiver_type; }; +struct ieee80211_chan_range { + u8 min; + u8 max; +}; + static const struct ieee80211_chan_range cranges[] = { {1, 11}, /* FCC */ {1, 11}, /* IC */ diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath5k/Kconfig new file mode 100644 index 00000000000..f1f2aea2eab --- /dev/null +++ b/drivers/net/wireless/ath5k/Kconfig @@ -0,0 +1,37 @@ +config ATH5K + tristate "Atheros 5xxx wireless cards support" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + ---help--- + This module adds support for wireless adapters based on + Atheros 5xxx chipset. + + Currently the following chip versions are supported: + + MAC: AR5211 AR5212 + PHY: RF5111/2111 RF5112/2112 RF5413/2413 + + This driver uses the kernel's mac80211 subsystem. + + If you choose to build a module, it'll be called ath5k. Say M if + unsure. + +config ATH5K_DEBUG + bool "Atheros 5xxx debugging" + depends on ATH5K + ---help--- + Atheros 5xxx debugging messages. + + Say Y, if and you will get debug options for ath5k. + To use this, you need to mount debugfs: + + mkdir /debug/ + mount -t debugfs debug /debug/ + + You will get access to files under: + /debug/ath5k/phy0/ + + To enable debug, pass the debug level to the debug module + parameter. For example: + + modprobe ath5k debug=0x00000400 + diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile index 321641f99e1..564ecd0c5d4 100644 --- a/drivers/net/wireless/ath5k/Makefile +++ b/drivers/net/wireless/ath5k/Makefile @@ -1,2 +1,6 @@ -ath5k-objs = base.o hw.o regdom.o initvals.o phy.o debug.o -obj-$(CONFIG_ATH5K) += ath5k.o +ath5k-y += base.o +ath5k-y += hw.o +ath5k-y += initvals.o +ath5k-y += phy.o +ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o +obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 69dea339261..b21830771ea 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -30,7 +30,6 @@ #include <net/mac80211.h> #include "hw.h" -#include "regdom.h" /* PCI IDs */ #define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ @@ -141,7 +140,8 @@ enum ath5k_radio { AR5K_RF5110 = 0, AR5K_RF5111 = 1, AR5K_RF5112 = 2, - AR5K_RF5413 = 3, + AR5K_RF2413 = 3, + AR5K_RF5413 = 4, }; /* @@ -169,12 +169,15 @@ struct ath5k_srev_name { #define AR5K_SREV_VER_AR5212 0x50 #define AR5K_SREV_VER_AR5213 0x55 #define AR5K_SREV_VER_AR5213A 0x59 -#define AR5K_SREV_VER_AR2424 0xa0 -#define AR5K_SREV_VER_AR5424 0xa3 +#define AR5K_SREV_VER_AR2413 0x78 +#define AR5K_SREV_VER_AR2414 0x79 +#define AR5K_SREV_VER_AR2424 0xa0 /* PCI-E */ +#define AR5K_SREV_VER_AR5424 0xa3 /* PCI-E */ #define AR5K_SREV_VER_AR5413 0xa4 #define AR5K_SREV_VER_AR5414 0xa5 -#define AR5K_SREV_VER_AR5416 0xc0 /* ? */ -#define AR5K_SREV_VER_AR5418 0xca +#define AR5K_SREV_VER_AR5416 0xc0 /* PCI-E */ +#define AR5K_SREV_VER_AR5418 0xca /* PCI-E */ +#define AR5K_SREV_VER_AR2425 0xe2 /* PCI-E */ #define AR5K_SREV_RAD_5110 0x00 #define AR5K_SREV_RAD_5111 0x10 @@ -184,8 +187,9 @@ struct ath5k_srev_name { #define AR5K_SREV_RAD_5112A 0x35 #define AR5K_SREV_RAD_2112 0x40 #define AR5K_SREV_RAD_2112A 0x45 +#define AR5K_SREV_RAD_SC0 0x56 /* Found on 2413/2414 */ #define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ -#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */ +#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424-5/5424 */ #define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ /* IEEE defs */ @@ -251,26 +255,31 @@ struct ath5k_srev_name { */ #define MODULATION_TURBO 0x00000080 -enum ath5k_vendor_mode { - MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1, - MODE_ATHEROS_TURBOG +enum ath5k_driver_mode { + AR5K_MODE_11A = 0, + AR5K_MODE_11A_TURBO = 1, + AR5K_MODE_11B = 2, + AR5K_MODE_11G = 3, + AR5K_MODE_11G_TURBO = 4, + AR5K_MODE_XR = 0, + AR5K_MODE_MAX = 5 }; -/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */ -#define NUM_DRIVER_MODES 3 - /* adding this flag to rate_code enables short preamble, see ar5212_reg.h */ #define AR5K_SET_SHORT_PREAMBLE 0x04 -#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2) -#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) +#define HAS_SHPREAMBLE(_ix) \ + (rt->rates[_ix].modulation == IEEE80211_RATE_SHORT_PREAMBLE) +#define SHPREAMBLE_FLAG(_ix) \ + (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) + /****************\ TX DEFINITIONS \****************/ /* - * Tx Descriptor + * TX Status */ struct ath5k_tx_status { u16 ts_seqnum; @@ -418,7 +427,7 @@ enum ath5k_dmasize { \****************/ /* - * Rx Descriptor + * RX Status */ struct ath5k_rx_status { u16 rs_datalen; @@ -449,8 +458,6 @@ struct ath5k_mib_stats { }; - - /**************************\ BEACON TIMERS DEFINITIONS \**************************/ @@ -492,29 +499,23 @@ struct ath5k_beacon_state { #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) - /********************\ COMMON DEFINITIONS \********************/ /* - * Atheros descriptor + * Atheros hardware descriptor + * This is read and written to by the hardware */ struct ath5k_desc { - u32 ds_link; - u32 ds_data; - u32 ds_ctl0; - u32 ds_ctl1; - u32 ds_hw[4]; + u32 ds_link; /* physical address of the next descriptor */ + u32 ds_data; /* physical address of data buffer (skb) */ union { - struct ath5k_rx_status rx; - struct ath5k_tx_status tx; - } ds_us; - -#define ds_rxstat ds_us.rx -#define ds_txstat ds_us.tx - + struct ath5k_hw_5210_tx_desc ds_tx5210; + struct ath5k_hw_5212_tx_desc ds_tx5212; + struct ath5k_hw_all_rx_desc ds_rx; + } ud; } __packed; #define AR5K_RXDESC_INTREQ 0x0020 @@ -560,8 +561,8 @@ struct ath5k_desc { * Used internaly in OpenHAL (ar5211.c/ar5212.c * for reset_tx_queue). Also see struct struct ieee80211_channel. */ -#define IS_CHAN_XR(_c) ((_c.val & CHANNEL_XR) != 0) -#define IS_CHAN_B(_c) ((_c.val & CHANNEL_B) != 0) +#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0) +#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0) /* * The following structure will be used to map 2GHz channels to @@ -584,7 +585,7 @@ struct ath5k_athchan_2ghz { /** * struct ath5k_rate - rate structure - * @valid: is this a valid rate for the current mode + * @valid: is this a valid rate for rate control (remove) * @modulation: respective mac80211 modulation * @rate_kbps: rate in kbit/s * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on @@ -643,47 +644,48 @@ struct ath5k_rate_table { /* * Rate tables... + * TODO: CLEAN THIS !!! */ #define AR5K_RATES_11A { 8, { \ 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 }, \ - { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 }, \ - { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 }, \ - { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 }, \ - { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 }, \ - { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 }, \ - { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 }, \ - { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 4 } } \ + { 1, 0, 6000, 11, 140, 0 }, \ + { 1, 0, 9000, 15, 18, 0 }, \ + { 1, 0, 12000, 10, 152, 2 }, \ + { 1, 0, 18000, 14, 36, 2 }, \ + { 1, 0, 24000, 9, 176, 4 }, \ + { 1, 0, 36000, 13, 72, 4 }, \ + { 1, 0, 48000, 8, 96, 4 }, \ + { 1, 0, 54000, 12, 108, 4 } } \ } #define AR5K_RATES_11B { 4, { \ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ 3, 2, 1, 0, 255, 255, 255, 255 }, { \ - { 1, IEEE80211_RATE_CCK, 1000, 27, 130, 0 }, \ - { 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 }, \ - { 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 }, \ - { 1, IEEE80211_RATE_CCK_2, 11000, 24, 150, 1 } } \ + { 1, 0, 1000, 27, 130, 0 }, \ + { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 132, 1 }, \ + { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 139, 1 }, \ + { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 150, 1 } } \ } #define AR5K_RATES_11G { 12, { \ 255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \ 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ 3, 2, 1, 0, 255, 255, 255, 255 }, { \ - { 1, IEEE80211_RATE_CCK, 1000, 27, 2, 0 }, \ - { 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 }, \ - { 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 }, \ - { 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 }, \ - { 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 }, \ - { 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \ - { 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 }, \ - { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \ - { 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 }, \ - { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \ - { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \ - { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \ + { 1, 0, 1000, 27, 2, 0 }, \ + { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 4, 1 }, \ + { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 11, 1 }, \ + { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 22, 1 }, \ + { 0, 0, 6000, 11, 12, 4 }, \ + { 0, 0, 9000, 15, 18, 4 }, \ + { 1, 0, 12000, 10, 24, 6 }, \ + { 1, 0, 18000, 14, 36, 6 }, \ + { 1, 0, 24000, 9, 48, 8 }, \ + { 1, 0, 36000, 13, 72, 8 }, \ + { 1, 0, 48000, 8, 96, 8 }, \ + { 1, 0, 54000, 12, 108, 8 } } \ } #define AR5K_RATES_TURBO { 8, { \ @@ -708,14 +710,14 @@ struct ath5k_rate_table { { 1, MODULATION_XR, 1000, 2, 139, 1 }, \ { 1, MODULATION_XR, 2000, 6, 150, 2 }, \ { 1, MODULATION_XR, 3000, 1, 150, 3 }, \ - { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 }, \ - { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \ - { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 }, \ - { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \ - { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 }, \ - { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \ - { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \ - { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \ + { 1, 0, 6000, 11, 140, 4 }, \ + { 1, 0, 9000, 15, 18, 4 }, \ + { 1, 0, 12000, 10, 152, 6 }, \ + { 1, 0, 18000, 14, 36, 6 }, \ + { 1, 0, 24000, 9, 176, 8 }, \ + { 1, 0, 36000, 13, 72, 8 }, \ + { 1, 0, 48000, 8, 96, 8 }, \ + { 1, 0, 54000, 12, 108, 8 } } \ } /* @@ -890,12 +892,14 @@ enum ath5k_capability_type { AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */ }; + +/* XXX: we *may* move cap_range stuff to struct wiphy */ struct ath5k_capabilities { /* * Supported PHY modes * (ie. CHANNEL_A, CHANNEL_B, ...) */ - DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES); + DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX); /* * Frequency range (without regulation restrictions) @@ -908,14 +912,6 @@ struct ath5k_capabilities { } cap_range; /* - * Active regulation domain settings - */ - struct { - enum ath5k_regdom reg_current; - enum ath5k_regdom reg_hw; - } cap_regdomain; - - /* * Values stored in the EEPROM (some of them...) */ struct ath5k_eeprom_info cap_eeprom; @@ -963,6 +959,7 @@ struct ath5k_hw { u16 ah_phy_revision; u16 ah_radio_5ghz_revision; u16 ah_radio_2ghz_revision; + u32 ah_phy_spending; enum ath5k_version ah_version; enum ath5k_radio ah_radio; @@ -1038,8 +1035,10 @@ struct ath5k_hw { int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *); - int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *); + int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_tx_status *); + int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_rx_status *); }; /* @@ -1129,8 +1128,6 @@ extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); -/* Regulatory Domain/Channels Setup */ -extern u16 ath5k_get_regdomain(struct ath5k_hw *ah); /* Misc functions */ extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index bef967ce34a..8862d245c82 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -80,7 +80,7 @@ MODULE_AUTHOR("Nick Kossifidis"); MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards."); MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION("0.1.1 (EXPERIMENTAL)"); +MODULE_VERSION("0.5.0 (EXPERIMENTAL)"); /* Known PCI ids */ @@ -118,6 +118,8 @@ static struct ath5k_srev_name srev_names[] = { { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, + { "2413", AR5K_VERSION_VER, AR5K_SREV_VER_AR2413 }, + { "2414", AR5K_VERSION_VER, AR5K_SREV_VER_AR2414 }, { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, @@ -132,6 +134,7 @@ static struct ath5k_srev_name srev_names[] = { { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, + { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC0 }, { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, @@ -240,6 +243,8 @@ static int ath5k_chan_set(struct ath5k_softc *sc, static void ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode); static void ath5k_mode_setup(struct ath5k_softc *sc); +static void ath5k_set_total_hw_rates(struct ath5k_softc *sc); + /* Descriptor setup */ static int ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev); @@ -278,7 +283,8 @@ static int ath5k_rx_start(struct ath5k_softc *sc); static void ath5k_rx_stop(struct ath5k_softc *sc); static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, - struct sk_buff *skb); + struct sk_buff *skb, + struct ath5k_rx_status *rs); static void ath5k_tasklet_rx(unsigned long data); /* Tx handling */ static void ath5k_tx_processq(struct ath5k_softc *sc, @@ -511,35 +517,46 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->ah->ah_mac_srev, sc->ah->ah_phy_revision); - if(!sc->ah->ah_single_chip){ + if (!sc->ah->ah_single_chip) { /* Single chip radio (!RF5111) */ - if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) { + if (sc->ah->ah_radio_5ghz_revision && + !sc->ah->ah_radio_2ghz_revision) { /* No 5GHz support -> report 2GHz radio */ - if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){ + if (!test_bit(AR5K_MODE_11A, + sc->ah->ah_capabilities.cap_mode)) { ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */ - } else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){ + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* No 2GHz support (5110 and some + * 5Ghz only cards) -> report 5Ghz radio */ + } else if (!test_bit(AR5K_MODE_11B, + sc->ah->ah_capabilities.cap_mode)) { ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); /* Multiband radio */ } else { ATH5K_INFO(sc, "RF%s multiband radio found" " (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); } } - /* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */ - else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){ + /* Multi chip radio (RF5111 - RF2111) -> + * report both 2GHz/5GHz radios */ + else if (sc->ah->ah_radio_5ghz_revision && + sc->ah->ah_radio_2ghz_revision){ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision), - sc->ah->ah_radio_2ghz_revision); + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_2ghz_revision), + sc->ah->ah_radio_2ghz_revision); } } @@ -693,11 +710,14 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err; } + /* Set *_rates so we can map hw rate index */ + ath5k_set_total_hw_rates(sc); + /* NB: setup here so ath5k_rate_update is happy */ - if (test_bit(MODE_IEEE80211A, ah->ah_modes)) - ath5k_setcurmode(sc, MODE_IEEE80211A); + if (test_bit(AR5K_MODE_11A, ah->ah_modes)) + ath5k_setcurmode(sc, AR5K_MODE_11A); else - ath5k_setcurmode(sc, MODE_IEEE80211B); + ath5k_setcurmode(sc, AR5K_MODE_11B); /* * Allocate tx+rx descriptors and populate the lists. @@ -837,12 +857,9 @@ ath5k_copy_rates(struct ieee80211_rate *rates, return 0; for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) { - if (!rt->rates[i].valid) - continue; - rates->rate = rt->rates[i].rate_kbps / 100; - rates->val = rt->rates[i].rate_code; - rates->flags = rt->rates[i].modulation; - rates++; + rates[count].bitrate = rt->rates[i].rate_kbps / 100; + rates[count].hw_value = rt->rates[i].rate_code; + rates[count].flags = rt->rates[i].modulation; count++; max--; } @@ -856,43 +873,22 @@ ath5k_copy_channels(struct ath5k_hw *ah, unsigned int mode, unsigned int max) { - static const struct { unsigned int mode, mask, chan; } map[] = { - [MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A }, - [MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T }, - [MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B }, - [MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G }, - [MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG }, - }; - static const struct ath5k_regchannel chans_2ghz[] = - IEEE80211_CHANNELS_2GHZ; - static const struct ath5k_regchannel chans_5ghz[] = - IEEE80211_CHANNELS_5GHZ; - const struct ath5k_regchannel *chans; - enum ath5k_regdom dmn; - unsigned int i, count, size, chfreq, all, f, ch; + unsigned int i, count, size, chfreq, freq, ch; if (!test_bit(mode, ah->ah_modes)) return 0; - all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1; - switch (mode) { - case MODE_IEEE80211A: - case MODE_ATHEROS_TURBO: + case AR5K_MODE_11A: + case AR5K_MODE_11A_TURBO: /* 1..220, but 2GHz frequencies are filtered by check_channel */ - size = all ? 220 : ARRAY_SIZE(chans_5ghz); - chans = chans_5ghz; - dmn = ath5k_regdom2flag(ah->ah_regdomain, - IEEE80211_CHANNELS_5GHZ_MIN); + size = 220 ; chfreq = CHANNEL_5GHZ; break; - case MODE_IEEE80211B: - case MODE_IEEE80211G: - case MODE_ATHEROS_TURBOG: - size = all ? 26 : ARRAY_SIZE(chans_2ghz); - chans = chans_2ghz; - dmn = ath5k_regdom2flag(ah->ah_regdomain, - IEEE80211_CHANNELS_2GHZ_MIN); + case AR5K_MODE_11B: + case AR5K_MODE_11G: + case AR5K_MODE_11G_TURBO: + size = 26; chfreq = CHANNEL_2GHZ; break; default: @@ -901,25 +897,31 @@ ath5k_copy_channels(struct ath5k_hw *ah, } for (i = 0, count = 0; i < size && max > 0; i++) { - ch = all ? i + 1 : chans[i].chan; - f = ath5k_ieee2mhz(ch); - /* Check if channel is supported by the chipset */ - if (!ath5k_channel_ok(ah, f, chfreq)) - continue; + ch = i + 1 ; + freq = ath5k_ieee2mhz(ch); - /* Match regulation domain */ - if (!all && !(IEEE80211_DMN(chans[i].domain) & - IEEE80211_DMN(dmn))) + /* Check if channel is supported by the chipset */ + if (!ath5k_channel_ok(ah, freq, chfreq)) continue; - if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode) - continue; + /* Write channel info and increment counter */ + channels[count].center_freq = freq; + channels[count].band = (chfreq == CHANNEL_2GHZ) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + switch (mode) { + case AR5K_MODE_11A: + case AR5K_MODE_11G: + channels[count].hw_value = chfreq | CHANNEL_OFDM; + break; + case AR5K_MODE_11A_TURBO: + case AR5K_MODE_11G_TURBO: + channels[count].hw_value = chfreq | + CHANNEL_OFDM | CHANNEL_TURBO; + break; + case AR5K_MODE_11B: + channels[count].hw_value = CHANNEL_B; + } - /* Write channel and increment counter */ - channels->chan = ch; - channels->freq = f; - channels->val = map[mode].chan; - channels++; count++; max--; } @@ -927,95 +929,78 @@ ath5k_copy_channels(struct ath5k_hw *ah, return count; } -/* Only tries to register modes our EEPROM says it can support */ -#define REGISTER_MODE(m) do { \ - ret = ath5k_register_mode(hw, m); \ - if (ret) \ - return ret; \ -} while (0) \ - -static inline int -ath5k_register_mode(struct ieee80211_hw *hw, u8 m) -{ - struct ath5k_softc *sc = hw->priv; - struct ieee80211_hw_mode *modes = sc->modes; - unsigned int i; - int ret; - - if (!test_bit(m, sc->ah->ah_capabilities.cap_mode)) - return 0; - - for (i = 0; i < NUM_DRIVER_MODES; i++) { - if (modes[i].mode != m || !modes[i].num_channels) - continue; - ret = ieee80211_register_hwmode(hw, &modes[i]); - if (ret) { - ATH5K_ERR(sc, "can't register hwmode %u\n", m); - return ret; - } - return 0; - } - BUG(); -} - static int ath5k_getchannels(struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - struct ieee80211_hw_mode *modes = sc->modes; - unsigned int i, max_r, max_c; - int ret; - - BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3); + struct ieee80211_supported_band *sbands = sc->sbands; + const struct ath5k_rate_table *hw_rates; + unsigned int max_r, max_c, count_r, count_c; + int mode2g = AR5K_MODE_11G; - /* The order here does not matter */ - modes[0].mode = MODE_IEEE80211G; - modes[1].mode = MODE_IEEE80211B; - modes[2].mode = MODE_IEEE80211A; + BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); max_r = ARRAY_SIZE(sc->rates); max_c = ARRAY_SIZE(sc->channels); + count_r = count_c = 0; + + /* 2GHz band */ + if (!test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { + mode2g = AR5K_MODE_11B; + if (!test_bit(AR5K_MODE_11B, + sc->ah->ah_capabilities.cap_mode)) + mode2g = -1; + } - for (i = 0; i < NUM_DRIVER_MODES; i++) { - struct ieee80211_hw_mode *mode = &modes[i]; - const struct ath5k_rate_table *hw_rates; + if (mode2g > 0) { + struct ieee80211_supported_band *sband = + &sbands[IEEE80211_BAND_2GHZ]; - if (i == 0) { - modes[0].rates = sc->rates; - modes->channels = sc->channels; - } else { - struct ieee80211_hw_mode *prev_mode = &modes[i-1]; - int prev_num_r = prev_mode->num_rates; - int prev_num_c = prev_mode->num_channels; - mode->rates = &prev_mode->rates[prev_num_r]; - mode->channels = &prev_mode->channels[prev_num_c]; - } + sband->bitrates = sc->rates; + sband->channels = sc->channels; + + sband->band = IEEE80211_BAND_2GHZ; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + mode2g, max_c); + + hw_rates = ath5k_hw_get_rate_table(ah, mode2g); + sband->n_bitrates = ath5k_copy_rates(sband->bitrates, + hw_rates, max_r); + + count_c = sband->n_channels; + count_r = sband->n_bitrates; + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + + max_r -= count_r; + max_c -= count_c; - hw_rates = ath5k_hw_get_rate_table(ah, mode->mode); - mode->num_rates = ath5k_copy_rates(mode->rates, hw_rates, - max_r); - mode->num_channels = ath5k_copy_channels(ah, mode->channels, - mode->mode, max_c); - max_r -= mode->num_rates; - max_c -= mode->num_channels; } - /* We try to register all modes this driver supports. We don't bother - * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts - * for that as per mac80211. Then, REGISTER_MODE() will will actually - * check the eeprom reading for more reliable capability information. - * Order matters here as per mac80211's latest preference. This will - * all hopefullly soon go away. */ + /* 5GHz band */ - REGISTER_MODE(MODE_IEEE80211G); - if (ah->ah_version != AR5K_AR5212) - REGISTER_MODE(MODE_IEEE80211B); - REGISTER_MODE(MODE_IEEE80211A); + if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { + struct ieee80211_supported_band *sband = + &sbands[IEEE80211_BAND_5GHZ]; - ath5k_debug_dump_modes(sc, modes); + sband->bitrates = &sc->rates[count_r]; + sband->channels = &sc->channels[count_c]; - return ret; + sband->band = IEEE80211_BAND_5GHZ; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11A, max_c); + + hw_rates = ath5k_hw_get_rate_table(ah, AR5K_MODE_11A); + sband->n_bitrates = ath5k_copy_rates(sband->bitrates, + hw_rates, max_r); + + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } + + ath5k_debug_dump_bands(sc); + + return 0; } /* @@ -1030,11 +1015,15 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) struct ath5k_hw *ah = sc->ah; int ret; - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n", - sc->curchan->chan, sc->curchan->freq, - chan->chan, chan->freq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", + sc->curchan->center_freq, chan->center_freq); + + if (chan->center_freq != sc->curchan->center_freq || + chan->hw_value != sc->curchan->hw_value) { + + sc->curchan = chan; + sc->curband = &sc->sbands[chan->band]; - if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) { /* * To switch channels clear any pending DMA operations; * wait long enough for the RX fifo to drain, reset the @@ -1044,13 +1033,13 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) ath5k_hw_set_intr(ah, 0); /* disable interrupts */ ath5k_txq_cleanup(sc); /* clear pending tx frames */ ath5k_rx_stop(sc); /* turn off frame recv */ - ret = ath5k_hw_reset(ah, sc->opmode, chan, true); + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); if (ret) { - ATH5K_ERR(sc, "%s: unable to reset channel %u " - "(%u Mhz)\n", __func__, chan->chan, chan->freq); + ATH5K_ERR(sc, "%s: unable to reset channel " + "(%u Mhz)\n", __func__, chan->center_freq); return ret; } - sc->curchan = chan; + ath5k_hw_set_txpower_limit(sc->ah, 0); /* @@ -1081,6 +1070,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) return 0; } +/* + * TODO: CLEAN THIS !!! + */ static void ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) { @@ -1121,10 +1113,6 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) continue; } sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; - if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation == - IEEE80211_RATE_OFDM) - sc->hwmap[i].txflags |= - IEEE80211_RADIOTAP_F_SHORTPRE; /* receive frames include FCS */ sc->hwmap[i].rxflags = sc->hwmap[i].txflags | IEEE80211_RADIOTAP_F_FCS; @@ -1142,6 +1130,12 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) } sc->curmode = mode; + + if (mode == AR5K_MODE_11A) { + sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; + } else { + sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; + } } static void @@ -1164,6 +1158,72 @@ ath5k_mode_setup(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); } +/* + * Match the hw provided rate index (through descriptors) + * to an index for sc->curband->bitrates, so it can be used + * by the stack. + * + * This one is a little bit tricky but i think i'm right + * about this... + * + * We have 4 rate tables in the following order: + * XR (4 rates) + * 802.11a (8 rates) + * 802.11b (4 rates) + * 802.11g (12 rates) + * that make the hw rate table. + * + * Lets take a 5211 for example that supports a and b modes only. + * First comes the 802.11a table and then 802.11b (total 12 rates). + * When hw returns eg. 11 it points to the last 802.11b rate (11Mbit), + * if it returns 2 it points to the second 802.11a rate etc. + * + * Same goes for 5212 who has xr/a/b/g support (total 28 rates). + * First comes the XR table, then 802.11a, 802.11b and 802.11g. + * When hw returns eg. 27 it points to the last 802.11g rate (54Mbits) etc + */ +static void +ath5k_set_total_hw_rates(struct ath5k_softc *sc) { + + struct ath5k_hw *ah = sc->ah; + + if (test_bit(AR5K_MODE_11A, ah->ah_modes)) + sc->a_rates = 8; + + if (test_bit(AR5K_MODE_11B, ah->ah_modes)) + sc->b_rates = 4; + + if (test_bit(AR5K_MODE_11G, ah->ah_modes)) + sc->g_rates = 12; + + /* XXX: Need to see what what happens when + xr disable bits in eeprom are set */ + if (ah->ah_version >= AR5K_AR5212) + sc->xr_rates = 4; + +} + +static inline int +ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) { + + int mac80211_rix; + + if(sc->curband->band == IEEE80211_BAND_2GHZ) { + /* We setup a g ratetable for both b/g modes */ + mac80211_rix = + hw_rix - sc->b_rates - sc->a_rates - sc->xr_rates; + } else { + mac80211_rix = hw_rix - sc->xr_rates; + } + + /* Something went wrong, fallback to basic rate for this band */ + if ((mac80211_rix >= sc->curband->n_bitrates) || + (mac80211_rix <= 0 )) + mac80211_rix = 1; + + return mac80211_rix; +} + @@ -1268,7 +1328,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0); + (sc->power_level * 2), ctl->tx_rate->hw_value, + ctl->retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1503,8 +1564,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) */ spin_lock_bh(&txq->lock); list_for_each_entry_safe(bf, bf0, &txq->q, list) { - ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah, - bf->desc)); + ath5k_debug_printtxbuf(sc, bf); ath5k_txbuf_free(sc, bf); @@ -1629,20 +1689,20 @@ ath5k_rx_stop(struct ath5k_softc *sc) static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, - struct sk_buff *skb) + struct sk_buff *skb, struct ath5k_rx_status *rs) { struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); - if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && - ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID) + if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && + rs->rs_keyix != AR5K_RXKEYIX_INVALID) return RX_FLAG_DECRYPTED; /* Apparently when a default key is used to decrypt the packet the hw does not set the index used to decrypt. In such cases get the index from the packet. */ if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && - !(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && + !(rs->rs_status & AR5K_RXERR_DECRYPT) && skb->len >= hlen + 4) { keyix = skb->data[hlen + 3] >> 6; @@ -1655,28 +1715,62 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, static void -ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb) +ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, + struct ieee80211_rx_status *rxs) { + u64 tsf, bc_tstamp; u32 hw_tu; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) == + if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && - (mgmt->frame_control & IEEE80211_FCTL_STYPE) == + (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON && - mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS && + le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { /* - * Received an IBSS beacon with the same BSSID. Hardware might - * have updated the TSF, check if we need to update timers. + * Received an IBSS beacon with the same BSSID. Hardware *must* + * have updated the local TSF. We have to work around various + * hardware bugs, though... */ - hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah)); - if (hw_tu >= sc->nexttbtt) { - ath5k_beacon_update_timers(sc, - mgmt->u.beacon.timestamp); + tsf = ath5k_hw_get_tsf64(sc->ah); + bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); + hw_tu = TSF_TO_TU(tsf); + + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", + (unsigned long long)bc_tstamp, + (unsigned long long)rxs->mactime, + (unsigned long long)(rxs->mactime - bc_tstamp), + (unsigned long long)tsf); + + /* + * Sometimes the HW will give us a wrong tstamp in the rx + * status, causing the timestamp extension to go wrong. + * (This seems to happen especially with beacon frames bigger + * than 78 byte (incl. FCS)) + * But we know that the receive timestamp must be later than the + * timestamp of the beacon since HW must have synced to that. + * + * NOTE: here we assume mactime to be after the frame was + * received, not like mac80211 which defines it at the start. + */ + if (bc_tstamp > rxs->mactime) { ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, - "detected HW merge from received beacon\n"); + "fixing mactime from %llx to %llx\n", + (unsigned long long)rxs->mactime, + (unsigned long long)tsf); + rxs->mactime = tsf; } + + /* + * Local TSF might have moved higher than our beacon timers, + * in that case we have to update them to continue sending + * beacons. This also takes care of synchronizing beacon sending + * times with other stations. + */ + if (hw_tu >= sc->nexttbtt) + ath5k_beacon_update_timers(sc, bc_tstamp); } } @@ -1685,12 +1779,11 @@ static void ath5k_tasklet_rx(unsigned long data) { struct ieee80211_rx_status rxs = {}; + struct ath5k_rx_status rs = {}; struct sk_buff *skb; struct ath5k_softc *sc = (void *)data; struct ath5k_buf *bf; struct ath5k_desc *ds; - u16 len; - u8 stat; int ret; int hdrlen; int pad; @@ -1713,7 +1806,7 @@ ath5k_tasklet_rx(unsigned long data) if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ break; - ret = sc->ah->ah_proc_rx_desc(sc->ah, ds); + ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); if (unlikely(ret == -EINPROGRESS)) break; else if (unlikely(ret)) { @@ -1722,16 +1815,15 @@ ath5k_tasklet_rx(unsigned long data) return; } - if (unlikely(ds->ds_rxstat.rs_more)) { + if (unlikely(rs.rs_more)) { ATH5K_WARN(sc, "unsupported jumbo\n"); goto next; } - stat = ds->ds_rxstat.rs_status; - if (unlikely(stat)) { - if (stat & AR5K_RXERR_PHY) + if (unlikely(rs.rs_status)) { + if (rs.rs_status & AR5K_RXERR_PHY) goto next; - if (stat & AR5K_RXERR_DECRYPT) { + if (rs.rs_status & AR5K_RXERR_DECRYPT) { /* * Decrypt error. If the error occurred * because there was no hardware key, then @@ -1742,30 +1834,29 @@ ath5k_tasklet_rx(unsigned long data) * * XXX do key cache faulting */ - if (ds->ds_rxstat.rs_keyix == - AR5K_RXKEYIX_INVALID && - !(stat & AR5K_RXERR_CRC)) + if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && + !(rs.rs_status & AR5K_RXERR_CRC)) goto accept; } - if (stat & AR5K_RXERR_MIC) { + if (rs.rs_status & AR5K_RXERR_MIC) { rxs.flag |= RX_FLAG_MMIC_ERROR; goto accept; } /* let crypto-error packets fall through in MNTR */ - if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || + if ((rs.rs_status & + ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || sc->opmode != IEEE80211_IF_TYPE_MNTR) goto next; } accept: - len = ds->ds_rxstat.rs_datalen; - pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, + rs.rs_datalen, PCI_DMA_FROMDEVICE); pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, PCI_DMA_FROMDEVICE); bf->skb = NULL; - skb_put(skb, len); + skb_put(skb, rs.rs_datalen); /* * the hardware adds a padding to 4 byte boundaries between @@ -1787,13 +1878,23 @@ accept: * 15bit only. that means TSF extension has to be done within * 32768usec (about 32ms). it might be necessary to move this to * the interrupt handler, like it is done in madwifi. + * + * Unfortunately we don't know when the hardware takes the rx + * timestamp (beginning of phy frame, data frame, end of rx?). + * The only thing we know is that it is hardware specific... + * On AR5213 it seems the rx timestamp is at the end of the + * frame, but i'm not sure. + * + * NOTE: mac80211 defines mactime at the beginning of the first + * data symbol. Since we don't have any time references it's + * impossible to comply to that. This affects IBSS merge only + * right now, so it's not too bad... */ - rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp); + rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); rxs.flag |= RX_FLAG_TSFT; - rxs.freq = sc->curchan->freq; - rxs.channel = sc->curchan->chan; - rxs.phymode = sc->curmode; + rxs.freq = sc->curchan->center_freq; + rxs.band = sc->curband->band; /* * signal quality: @@ -1803,25 +1904,25 @@ accept: /* noise floor in dBm, from the last noise calibration */ rxs.noise = sc->ah->ah_noise_floor; /* signal level in dBm */ - rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi; + rxs.ssi = rxs.noise + rs.rs_rssi; /* * "signal" is actually displayed as Link Quality by iwconfig * we provide a percentage based on rssi (assuming max rssi 64) */ - rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64; + rxs.signal = rs.rs_rssi * 100 / 64; - rxs.antenna = ds->ds_rxstat.rs_antenna; - rxs.rate = ds->ds_rxstat.rs_rate; - rxs.flag |= ath5k_rx_decrypted(sc, ds, skb); + rxs.antenna = rs.rs_antenna; + rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); + rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ if (sc->opmode == IEEE80211_IF_TYPE_IBSS) - ath5k_check_ibss_hw_merge(sc, skb); + ath5k_check_ibss_tsf(sc, skb, &rxs); __ieee80211_rx(sc->hw, skb, &rxs); - sc->led_rxrate = ds->ds_rxstat.rs_rate; + sc->led_rxrate = rs.rs_rate; ath5k_led_event(sc, ATH_LED_RX); next: list_move_tail(&bf->list, &sc->rxbuf); @@ -1840,6 +1941,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) { struct ieee80211_tx_status txs = {}; + struct ath5k_tx_status ts = {}; struct ath5k_buf *bf, *bf0; struct ath5k_desc *ds; struct sk_buff *skb; @@ -1852,7 +1954,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) /* TODO only one segment */ pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, sc->desc_len, PCI_DMA_FROMDEVICE); - ret = sc->ah->ah_proc_tx_desc(sc->ah, ds); + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); if (unlikely(ret == -EINPROGRESS)) break; else if (unlikely(ret)) { @@ -1867,17 +1969,16 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) PCI_DMA_TODEVICE); txs.control = bf->ctl; - txs.retry_count = ds->ds_txstat.ts_shortretry + - ds->ds_txstat.ts_longretry / 6; - if (unlikely(ds->ds_txstat.ts_status)) { + txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; - if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY) + if (ts.ts_status & AR5K_TXERR_XRETRY) txs.excessive_retries = 1; - else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT) + else if (ts.ts_status & AR5K_TXERR_FILT) txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; } else { txs.flags |= IEEE80211_TX_STATUS_ACK; - txs.ack_signal = ds->ds_txstat.ts_rssi; + txs.ack_signal = ts.ts_rssi; } ieee80211_tx_status(sc->hw, skb, &txs); @@ -1958,8 +2059,9 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ds->ds_data = bf->skbaddr; ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), - AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1, - AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); + AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), + ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, + antenna, flags, 0, 0); if (ret) goto err_unmap; @@ -2050,7 +2152,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) * beacon timer registers. * * This is called in a variety of situations, e.g. when a beacon is received, - * when a HW merge has been detected, but also when an new IBSS is created or + * when a TSF update has been detected, but also when an new IBSS is created or * when we otherwise know we have to update the timers, but we keep it in this * function to have it all together in one place. */ @@ -2150,7 +2252,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) * another AP to associate with. * * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA - * interrupts to detect HW merges only. + * interrupts to detect TSF updates only. * * AP mode is missing. */ @@ -2170,7 +2272,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) * hardware send the beacons automatically. We have to load it * only once here. * We use the SWBA interrupt only to keep track of the beacon - * timers in order to detect HW merges (automatic TSF updates). + * timers in order to detect automatic TSF updates. */ ath5k_beaconq_config(sc); @@ -2211,7 +2313,8 @@ ath5k_init(struct ath5k_softc *sc) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - sc->curchan = sc->hw->conf.chan; + sc->curchan = sc->hw->conf.channel; + sc->curband = &sc->sbands[sc->curchan->band]; ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false); if (ret) { ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret); @@ -2382,8 +2485,8 @@ ath5k_intr(int irq, void *dev_id) * * In IBSS mode we use this interrupt just to * keep track of the next TBTT (target beacon - * transmission time) in order to detect hardware - * merges (TSF updates). + * transmission time) in order to detect wether + * automatic TSF updates happened. */ if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { /* XXX: only if VEOL suppported */ @@ -2448,7 +2551,8 @@ ath5k_calibrate(unsigned long data) struct ath5k_hw *ah = sc->ah; ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", - sc->curchan->chan, sc->curchan->val); + ieee80211_frequency_to_channel(sc->curchan->center_freq), + sc->curchan->hw_value); if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) { /* @@ -2460,7 +2564,8 @@ ath5k_calibrate(unsigned long data) } if (ath5k_hw_phy_calibrate(ah, sc->curchan)) ATH5K_ERR(sc, "calibration of channel %u failed\n", - sc->curchan->chan); + ieee80211_frequency_to_channel( + sc->curchan->center_freq)); mod_timer(&sc->calib_tim, round_jiffies(jiffies + msecs_to_jiffies(ath5k_calinterval * 1000))); @@ -2558,7 +2663,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ctl->tx_rate; + sc->led_txrate = ctl->tx_rate->hw_value; spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { @@ -2597,11 +2702,6 @@ ath5k_reset(struct ieee80211_hw *hw) int ret; ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); - /* - * Convert to a hw channel description with the flags - * constrained to reflect the current operating mode. - */ - sc->curchan = hw->conf.chan; ath5k_hw_set_intr(ah, 0); ath5k_txq_cleanup(sc); @@ -2692,6 +2792,9 @@ end: mutex_unlock(&sc->lock); } +/* + * TODO: Phy disable/diversity etc + */ static int ath5k_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) @@ -2699,9 +2802,9 @@ ath5k_config(struct ieee80211_hw *hw, struct ath5k_softc *sc = hw->priv; sc->bintval = conf->beacon_int; - ath5k_setcurmode(sc, conf->phymode); + sc->power_level = conf->power_level; - return ath5k_chan_set(sc, conf->chan); + return ath5k_chan_set(sc, conf->channel); } static int @@ -2869,7 +2972,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch(key->alg) { case ALG_WEP: - break; + /* XXX: fix hardware encryption, its not working. For now + * allow software encryption */ + /* break; */ case ALG_TKIP: case ALG_CCMP: return -EOPNOTSUPP; diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 8287ae787f1..3a975589301 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -83,7 +83,7 @@ struct ath5k_txq { #if CHAN_DEBUG #define ATH_CHAN_MAX (26+26+26+200+200) #else -#define ATH_CHAN_MAX (14+14+14+252+20) /* XXX what's the max? */ +#define ATH_CHAN_MAX (14+14+14+252+20) #endif /* Software Carrier, keeps track of the driver state @@ -95,15 +95,22 @@ struct ath5k_softc { struct ieee80211_tx_queue_stats tx_stats; struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ - struct ieee80211_hw_mode modes[NUM_DRIVER_MODES]; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels[ATH_CHAN_MAX]; - struct ieee80211_rate rates[AR5K_MAX_RATES * NUM_DRIVER_MODES]; + struct ieee80211_rate rates[AR5K_MAX_RATES * IEEE80211_NUM_BANDS]; enum ieee80211_if_types opmode; struct ath5k_hw *ah; /* Atheros HW */ -#if ATH5K_DEBUG + struct ieee80211_supported_band *curband; + + u8 a_rates; + u8 b_rates; + u8 g_rates; + u8 xr_rates; + +#ifdef CONFIG_ATH5K_DEBUG struct ath5k_dbg_info debug; /* debug info */ -#endif +#endif /* CONFIG_ATH5K_DEBUG */ struct ath5k_buf *bufptr; /* allocated buffer ptr */ struct ath5k_desc *desc; /* TX/RX descriptors */ @@ -169,6 +176,7 @@ struct ath5k_softc { unsigned int nexttbtt; /* next beacon time in TU */ struct timer_list calib_tim; /* calibration timer */ + int power_level; /* Requested tx power in dbm */ }; #define ath5k_hw_hasbssidmask(_ah) \ diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c index bb581ef6d1e..41d5fa34b54 100644 --- a/drivers/net/wireless/ath5k/debug.c +++ b/drivers/net/wireless/ath5k/debug.c @@ -65,7 +65,7 @@ static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); -#if ATH5K_DEBUG +#ifdef CONFIG_ATH5K_DEBUG #include <linux/seq_file.h> #include "reg.h" @@ -200,7 +200,8 @@ static ssize_t read_file_tsf(struct file *file, char __user *user_buf, { struct ath5k_softc *sc = file->private_data; char buf[100]; - snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah)); + snprintf(buf, sizeof(buf), "0x%016llx\n", + (unsigned long long)ath5k_hw_get_tsf64(sc->ah)); return simple_read_from_buffer(user_buf, count, ppos, buf, 19); } @@ -271,7 +272,8 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf, tsf = ath5k_hw_get_tsf64(sc->ah); len += snprintf(buf+len, sizeof(buf)-len, - "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf)); + "TSF\t\t0x%016llx\tTU: %08x\n", + (unsigned long long)tsf, TSF_TO_TU(tsf)); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -340,7 +342,7 @@ static struct { { ATH5K_DEBUG_LED, "led", "LED mamagement" }, { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, - { ATH5K_DEBUG_DUMPMODES, "dumpmodes", "dump modes" }, + { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, }; @@ -452,43 +454,63 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) /* functions used in other places */ void -ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes) +ath5k_debug_dump_bands(struct ath5k_softc *sc) { - unsigned int m, i; + unsigned int b, i; - if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES))) + if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPBANDS))) return; - for (m = 0; m < NUM_DRIVER_MODES; m++) { - printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m, - modes[m].num_channels, modes[m].num_rates); + BUG_ON(!sc->sbands); + + for (b = 0; b < IEEE80211_NUM_BANDS; b++) { + struct ieee80211_supported_band *band = &sc->sbands[b]; + char bname[5]; + switch (band->band) { + case IEEE80211_BAND_2GHZ: + strcpy(bname, "2 GHz"); + break; + case IEEE80211_BAND_5GHZ: + strcpy(bname, "5 GHz"); + break; + default: + printk(KERN_DEBUG "Band not supported: %d\n", + band->band); + return; + } + printk(KERN_DEBUG "Band %s: channels %d, rates %d\n", bname, + band->n_channels, band->n_bitrates); printk(KERN_DEBUG " channels:\n"); - for (i = 0; i < modes[m].num_channels; i++) + for (i = 0; i < band->n_channels; i++) printk(KERN_DEBUG " %3d %d %.4x %.4x\n", - modes[m].channels[i].chan, - modes[m].channels[i].freq, - modes[m].channels[i].val, - modes[m].channels[i].flag); + ieee80211_frequency_to_channel( + band->channels[i].center_freq), + band->channels[i].center_freq, + band->channels[i].hw_value, + band->channels[i].flags); printk(KERN_DEBUG " rates:\n"); - for (i = 0; i < modes[m].num_rates; i++) + for (i = 0; i < band->n_bitrates; i++) printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", - modes[m].rates[i].rate, - modes[m].rates[i].val, - modes[m].rates[i].flags, - modes[m].rates[i].val2); + band->bitrates[i].bitrate, + band->bitrates[i].hw_value, + band->bitrates[i].flags, + band->bitrates[i].hw_value_short); } } static inline void -ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done) +ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, + struct ath5k_rx_status *rs) { struct ath5k_desc *ds = bf->desc; + struct ath5k_hw_all_rx_desc *rd = &ds->ud.ds_rx; printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", ds, (unsigned long long)bf->daddr, - ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, - ds->ds_hw[0], ds->ds_hw[1], - !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); + ds->ds_link, ds->ds_data, + rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, + rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, + !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); } void @@ -496,6 +518,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) { struct ath5k_desc *ds; struct ath5k_buf *bf; + struct ath5k_rx_status rs = {}; int status; if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) @@ -507,9 +530,9 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) spin_lock_bh(&sc->rxbuflock); list_for_each_entry(bf, &sc->rxbuf, list) { ds = bf->desc; - status = ah->ah_proc_rx_desc(ah, ds); + status = ah->ah_proc_rx_desc(ah, ds, &rs); if (!status) - ath5k_debug_printrxbuf(bf, status == 0); + ath5k_debug_printrxbuf(bf, status == 0, &rs); } spin_unlock_bh(&sc->rxbuflock); } @@ -533,19 +556,24 @@ ath5k_debug_dump_skb(struct ath5k_softc *sc, } void -ath5k_debug_printtxbuf(struct ath5k_softc *sc, - struct ath5k_buf *bf, int done) +ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_desc *ds = bf->desc; + struct ath5k_hw_5212_tx_desc *td = &ds->ud.ds_tx5212; + struct ath5k_tx_status ts = {}; + int done; if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) return; + done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); + printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, - ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, - ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3], - !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'); + ds->ds_data, td->tx_ctl.tx_control_0, td->tx_ctl.tx_control_1, + td->tx_ctl.tx_control_2, td->tx_ctl.tx_control_3, + td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, + done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); } -#endif /* if ATH5K_DEBUG */ +#endif /* ifdef CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h index c4fd8c43df0..2cf8d18b10e 100644 --- a/drivers/net/wireless/ath5k/debug.h +++ b/drivers/net/wireless/ath5k/debug.h @@ -61,11 +61,6 @@ #ifndef _ATH5K_DEBUG_H #define _ATH5K_DEBUG_H -/* set this to 1 for debugging output */ -#ifndef ATH5K_DEBUG -#define ATH5K_DEBUG 0 -#endif - struct ath5k_softc; struct ath5k_hw; struct ieee80211_hw_mode; @@ -96,7 +91,7 @@ struct ath5k_dbg_info { * @ATH5K_DEBUG_LED: led management * @ATH5K_DEBUG_DUMP_RX: print received skb content * @ATH5K_DEBUG_DUMP_TX: print transmit skb content - * @ATH5K_DEBUG_DUMPMODES: dump modes + * @ATH5K_DEBUG_DUMPBANDS: dump bands * @ATH5K_DEBUG_TRACE: trace function calls * @ATH5K_DEBUG_ANY: show at any debug level * @@ -118,12 +113,12 @@ enum ath5k_debug_level { ATH5K_DEBUG_LED = 0x00000080, ATH5K_DEBUG_DUMP_RX = 0x00000100, ATH5K_DEBUG_DUMP_TX = 0x00000200, - ATH5K_DEBUG_DUMPMODES = 0x00000400, + ATH5K_DEBUG_DUMPBANDS = 0x00000400, ATH5K_DEBUG_TRACE = 0x00001000, ATH5K_DEBUG_ANY = 0xffffffff }; -#if ATH5K_DEBUG +#ifdef CONFIG_ATH5K_DEBUG #define ATH5K_TRACE(_sc) do { \ if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \ @@ -158,20 +153,20 @@ void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); void -ath5k_debug_dump_modes(struct ath5k_softc *sc, - struct ieee80211_hw_mode *modes); +ath5k_debug_dump_bands(struct ath5k_softc *sc); void ath5k_debug_dump_skb(struct ath5k_softc *sc, struct sk_buff *skb, const char *prefix, int tx); void -ath5k_debug_printtxbuf(struct ath5k_softc *sc, - struct ath5k_buf *bf, int done); +ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); #else /* no debugging */ -#define ATH5K_TRACE(_sc) /* empty */ +#include <linux/compiler.h> + +#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc)) static inline void __attribute__ ((format (printf, 3, 4))) ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} @@ -196,17 +191,15 @@ static inline void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} static inline void -ath5k_debug_dump_modes(struct ath5k_softc *sc, - struct ieee80211_hw_mode *modes) {} +ath5k_debug_dump_bands(struct ath5k_softc *sc) {} static inline void ath5k_debug_dump_skb(struct ath5k_softc *sc, struct sk_buff *skb, const char *prefix, int tx) {} static inline void -ath5k_debug_printtxbuf(struct ath5k_softc *sc, - struct ath5k_buf *bf, int done) {} +ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {} -#endif /* if ATH5K_DEBUG */ +#endif /* ifdef CONFIG_ATH5K_DEBUG */ #endif /* ifndef _ATH5K_DEBUG_H */ diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 01757436353..ff579a22362 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -1,4 +1,4 @@ - /* +/* * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> * Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org> @@ -48,14 +48,18 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); -static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *); +static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_tx_status *); static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); -static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *); -static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *); -static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *); +static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_tx_status *); +static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_rx_status *); +static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *, + struct ath5k_rx_status *); static int ath5k_hw_get_capabilities(struct ath5k_hw *); static int ath5k_eeprom_init(struct ath5k_hw *); @@ -81,12 +85,12 @@ static int ath5k_hw_disable_pspoll(struct ath5k_hw *); static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) { - return turbo == true ? (usec * 80) : (usec * 40); + return turbo ? (usec * 80) : (usec * 40); } static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) { - return turbo == true ? (clock / 80) : (clock / 40); + return turbo ? (clock / 80) : (clock / 40); } /* @@ -100,7 +104,7 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { data = ath5k_hw_reg_read(ah, reg); - if ((is_set == true) && (data & flag)) + if (is_set && (data & flag)) break; else if ((data & flag) == val) break; @@ -140,9 +144,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) * HW information */ - /* Get reg domain from eeprom */ - ath5k_get_regdomain(ah); - ah->ah_op_mode = IEEE80211_IF_TYPE_STA; ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; ah->ah_turbo = false; @@ -177,9 +178,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) } if (ah->ah_version == AR5K_AR5212) - ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status; + ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; else if (ah->ah_version <= AR5K_AR5211) - ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status; + ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; /* Bring device out of sleep and reset it's units */ ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true); @@ -211,7 +212,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Identify single chip solutions */ if((srev <= AR5K_SREV_VER_AR5414) && - (srev >= AR5K_SREV_VER_AR2424)) { + (srev >= AR5K_SREV_VER_AR2413)) { ah->ah_single_chip = true; } else { ah->ah_single_chip = false; @@ -226,10 +227,33 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ah->ah_radio = AR5K_RF5110; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { ah->ah_radio = AR5K_RF5111; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { + ah->ah_radio = AR5K_RF5112; + + if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; + } else { + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; + } + + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { + ah->ah_radio = AR5K_RF2413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; } else { + ah->ah_radio = AR5K_RF5413; + + if (ah->ah_mac_srev <= AR5K_SREV_VER_AR5424 && + ah->ah_mac_srev >= AR5K_SREV_VER_AR2424) + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424; + else if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2425) + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; + else + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; + + } ah->ah_phy = AR5K_PHY(0); @@ -280,7 +304,8 @@ err: */ static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) { - u32 turbo, mode, clock; + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 turbo, mode, clock, bus_flags; int ret; turbo = 0; @@ -357,9 +382,15 @@ static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) AR5K_PHY_TURBO); } - /* ...reset chipset and PCI device */ - if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah, - AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) { + /* reseting PCI on PCI-E cards results card to hang + * and always return 0xffff... so we ingore that flag + * for PCI-E cards */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + /* Reset chipset */ + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + if (ret) { ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n"); return -EIO; } @@ -405,15 +436,15 @@ const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, /* Get rate tables */ switch (mode) { - case MODE_IEEE80211A: + case AR5K_MODE_11A: return &ath5k_rt_11a; - case MODE_ATHEROS_TURBO: + case AR5K_MODE_11A_TURBO: return &ath5k_rt_turbo; - case MODE_IEEE80211B: + case AR5K_MODE_11B: return &ath5k_rt_11b; - case MODE_IEEE80211G: + case AR5K_MODE_11G: return &ath5k_rt_11g; - case MODE_ATHEROS_TURBOG: + case AR5K_MODE_11G_TURBO: return &ath5k_rt_xr; } @@ -459,15 +490,15 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, ds_coef_exp, ds_coef_man, clock; if (!(ah->ah_version == AR5K_AR5212) || - !(channel->val & CHANNEL_OFDM)) + !(channel->hw_value & CHANNEL_OFDM)) BUG(); /* Seems there are two PLLs, one for baseband sampling and one * for tuning. Tuning basebands are 40 MHz or 80MHz when in * turbo. */ - clock = channel->val & CHANNEL_TURBO ? 80 : 40; + clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40; coef_scaled = ((5 * (clock << 24)) / 2) / - channel->freq; + channel->center_freq; for (coef_exp = 31; coef_exp > 0; coef_exp--) if ((coef_scaled >> coef_exp) & 0x1) @@ -494,8 +525,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, * ath5k_hw_write_rate_duration - set rate duration during hw resets * * @ah: the &struct ath5k_hw - * @driver_mode: one of enum ieee80211_phymode or our one of our own - * vendor modes + * @mode: one of enum ath5k_driver_mode * * Write the rate duration table for the current mode upon hw reset. This * is a helper for ath5k_hw_reset(). It seems all this is doing is setting @@ -506,19 +536,20 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, * */ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, - unsigned int driver_mode) + unsigned int mode) { struct ath5k_softc *sc = ah->ah_sc; const struct ath5k_rate_table *rt; + struct ieee80211_rate srate = {}; unsigned int i; /* Get rate table for the current operating mode */ - rt = ath5k_hw_get_rate_table(ah, - driver_mode); + rt = ath5k_hw_get_rate_table(ah, mode); /* Write rate duration table */ for (i = 0; i < rt->rate_count; i++) { const struct ath5k_rate *rate, *control_rate; + u32 reg; u16 tx_time; @@ -528,14 +559,16 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, /* Set ACK timeout */ reg = AR5K_RATE_DUR(rate->rate_code); + srate.bitrate = control_rate->rate_kbps/100; + /* An ACK frame consists of 10 bytes. If you add the FCS, * which ieee80211_generic_frame_duration() adds, * its 14 bytes. Note we use the control rate and not the * actual rate for this rate. See mac80211 tx.c * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ - tx_time = ieee80211_generic_frame_duration(sc->hw, - sc->vif, 10, control_rate->rate_kbps/100); + tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, + sc->vif, 10, &srate)); ath5k_hw_reg_write(ah, tx_time, reg); @@ -568,8 +601,9 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 data, s_seq, s_ant, s_led[3]; - unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1; + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 data, s_seq, s_ant, s_led[3], dma_size; + unsigned int i, mode, freq, ee_mode, ant[2]; int ret; ATH5K_TRACE(ah->ah_sc); @@ -585,7 +619,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, */ /*DCU/Antenna selection not available on 5210*/ if (ah->ah_version != AR5K_AR5210) { - if (change_channel == true) { + if (change_channel) { /* Seq number for queue 0 -do this for all queues ? */ s_seq = ath5k_hw_reg_read(ah, AR5K_QUEUE_DFS_SEQNUM(0)); @@ -599,12 +633,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); - if (change_channel == true && ah->ah_rf_banks != NULL) + if (change_channel && ah->ah_rf_banks != NULL) ath5k_hw_get_rf_gain(ah); /*Wakeup the device*/ - ret = ath5k_hw_nic_wakeup(ah, channel->val, false); + ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); if (ret) return ret; @@ -620,43 +654,39 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, if (ah->ah_version != AR5K_AR5210) { if (ah->ah_radio != AR5K_RF5111 && ah->ah_radio != AR5K_RF5112 && - ah->ah_radio != AR5K_RF5413) { + ah->ah_radio != AR5K_RF5413 && + ah->ah_radio != AR5K_RF2413) { ATH5K_ERR(ah->ah_sc, "invalid phy radio: %u\n", ah->ah_radio); return -EINVAL; } - switch (channel->val & CHANNEL_MODES) { + switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: - mode = AR5K_INI_VAL_11A; + mode = AR5K_MODE_11A; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; - driver_mode = MODE_IEEE80211A; break; case CHANNEL_G: - mode = AR5K_INI_VAL_11G; + mode = AR5K_MODE_11G; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11G; - driver_mode = MODE_IEEE80211G; break; case CHANNEL_B: - mode = AR5K_INI_VAL_11B; + mode = AR5K_MODE_11B; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11B; - driver_mode = MODE_IEEE80211B; break; case CHANNEL_T: - mode = AR5K_INI_VAL_11A_TURBO; + mode = AR5K_MODE_11A_TURBO; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; - driver_mode = MODE_ATHEROS_TURBO; break; /*Is this ok on 5211 too ?*/ case CHANNEL_TG: - mode = AR5K_INI_VAL_11G_TURBO; + mode = AR5K_MODE_11G_TURBO; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11G; - driver_mode = MODE_ATHEROS_TURBOG; break; case CHANNEL_XR: if (ah->ah_version == AR5K_AR5211) { @@ -664,14 +694,13 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, "XR mode not available on 5211"); return -EINVAL; } - mode = AR5K_INI_VAL_XR; + mode = AR5K_MODE_XR; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; - driver_mode = MODE_IEEE80211A; break; default: ATH5K_ERR(ah->ah_sc, - "invalid channel: %d\n", channel->freq); + "invalid channel: %d\n", channel->center_freq); return -EINVAL; } @@ -701,15 +730,26 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /* * Write some more initial register settings */ - if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */ + if (ah->ah_version == AR5K_AR5212) { ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11)); - if (channel->val == CHANNEL_G) - ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */ + if (channel->hw_value == CHANNEL_G) + if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) + ath5k_hw_reg_write(ah, 0x00f80d80, + AR5K_PHY(83)); + else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) + ath5k_hw_reg_write(ah, 0x00380140, + AR5K_PHY(83)); + else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) + ath5k_hw_reg_write(ah, 0x00fc0ec0, + AR5K_PHY(83)); + else /* 2425 */ + ath5k_hw_reg_write(ah, 0x00fc0fc0, + AR5K_PHY(83)); else - ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83)); + ath5k_hw_reg_write(ah, 0x00000000, + AR5K_PHY(83)); - ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */ ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); ath5k_hw_reg_write(ah, 0x0000000f, 0x8060); ath5k_hw_reg_write(ah, 0x00000000, 0xa254); @@ -722,7 +762,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, AR5K_SREV_RAD_5112A) { ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, AR5K_PHY_CCKTXCTL); - if (channel->val & CHANNEL_5GHZ) + if (channel->hw_value & CHANNEL_5GHZ) data = 0xffb81020; else data = 0xffb80d20; @@ -742,7 +782,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, * mac80211 are integrated */ if (ah->ah_version == AR5K_AR5212 && ah->ah_sc->vif != NULL) - ath5k_hw_write_rate_duration(ah, driver_mode); + ath5k_hw_write_rate_duration(ah, mode); /* * Write RF registers @@ -758,7 +798,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /* Write OFDM timings on 5212*/ if (ah->ah_version == AR5K_AR5212 && - channel->val & CHANNEL_OFDM) { + channel->hw_value & CHANNEL_OFDM) { ret = ath5k_hw_write_ofdm_timings(ah, channel); if (ret) return ret; @@ -767,7 +807,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /*Enable/disable 802.11b mode on 5111 (enable 2111 frequency converter + CCK)*/ if (ah->ah_radio == AR5K_RF5111) { - if (driver_mode == MODE_IEEE80211B) + if (mode == AR5K_MODE_11B) AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_B_MODE); else @@ -885,13 +925,24 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /* * Set Rx/Tx DMA Configuration - *(passing dma size not available on 5210) + * + * Set maximum DMA size (512) except for PCI-E cards since + * it causes rx overruns and tx errors (tested on 5424 but since + * rx overruns also occur on 5416/5418 with madwifi we set 128 + * for all PCI-E cards to be safe). + * + * In dumps this is 128 for allchips. + * + * XXX: need to check 5210 for this + * TODO: Check out tx triger level, it's always 64 on dumps but I + * guess we can tweak it and see how it goes ;-) */ + dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; if (ah->ah_version != AR5K_AR5210) { - AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR, - AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE); - AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW, - AR5K_DMASIZE_512B); + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_SDMAMR, dma_size); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, + AR5K_RXCFG_SDMAMW, dma_size); } /* @@ -905,7 +956,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, if (ah->ah_version != AR5K_AR5210) { data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & AR5K_PHY_RX_DELAY_M; - data = (channel->val & CHANNEL_CCK) ? + data = (channel->hw_value & CHANNEL_CCK) ? ((data << 2) / 22) : (data / 10); udelay(100 + data); @@ -922,11 +973,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL, 0, false)) { ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", - channel->freq); + channel->center_freq); return -EAGAIN; } - ret = ath5k_hw_noise_floor_calibration(ah, channel->freq); + ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); if (ret) return ret; @@ -934,7 +985,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /* A and G modes can use QAM modulation which requires enabling * I and Q calibration. Don't bother in B mode. */ - if (!(driver_mode == MODE_IEEE80211B)) { + if (!(mode == AR5K_MODE_11B)) { ah->ah_calibration = true; AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); @@ -981,6 +1032,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /* * Set the 32MHz reference clock on 5212 phy clock sleep register + * + * TODO: Find out how to switch to external 32Khz clock to save power */ if (ah->ah_version == AR5K_AR5212) { ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); @@ -988,9 +1041,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); - ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ? - AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112, - AR5K_PHY_SPENDING); + ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); + } + + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); + ath5k_hw_reg_write(ah, 0x00003210, 0x811c); + ath5k_hw_reg_write(ah, 0x00000052, 0x8108); + if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413) + ath5k_hw_reg_write(ah, 0x00000004, 0x8120); } /* @@ -1065,7 +1124,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; /* fallthrough */ case AR5K_PM_NETWORK_SLEEP: - if (set_chip == true) + if (set_chip) ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE | sleep_duration, AR5K_SLEEP_CTL); @@ -1074,7 +1133,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, break; case AR5K_PM_FULL_SLEEP: - if (set_chip == true) + if (set_chip) ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, AR5K_SLEEP_CTL); @@ -1082,7 +1141,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, break; case AR5K_PM_AWAKE: - if (set_chip == false) + if (!set_chip) goto commit; ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, @@ -1389,7 +1448,7 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), AR5K_TXCFG_TXFULL); - if (increase == false) { + if (!increase) { if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) goto done; } else @@ -1592,9 +1651,10 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) /* * Write to eeprom - currently disabled, use at your own risk */ +#if 0 static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data) { -#if 0 + u32 status, timeout; ATH5K_TRACE(ah->ah_sc); @@ -1636,10 +1696,11 @@ static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data) } udelay(15); } -#endif + ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!"); return -EIO; } +#endif /* * Translate binary channel representation in EEPROM to frequency @@ -2045,50 +2106,6 @@ static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) } /* - * Read/Write regulatory domain - */ -static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write, - enum ath5k_regdom *regdomain) -{ - u16 ee_regdomain; - - /* Read current value */ - if (write != true) { - ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain; - *regdomain = ath5k_regdom_to_ieee(ee_regdomain); - return true; - } - - ee_regdomain = ath5k_regdom_from_ieee(*regdomain); - - /* Try to write a new value */ - if (ah->ah_capabilities.cap_eeprom.ee_protect & - AR5K_EEPROM_PROTECT_WR_128_191) - return false; - if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0) - return false; - - ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain; - - return true; -} - -/* - * Use the above to write a new regulatory domain - */ -int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain) -{ - enum ath5k_regdom ieee_regdomain; - - ieee_regdomain = ath5k_regdom_to_ieee(regdomain); - - if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true) - return 0; - - return -EIO; -} - -/* * Fill the capabilities struct */ static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) @@ -2110,8 +2127,8 @@ static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) ah->ah_capabilities.cap_range.range_2ghz_max = 0; /* Set supported modes */ - __set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode); - __set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode); } else { /* * XXX The tranceiver supports frequencies from 4920 to 6100GHz @@ -2133,12 +2150,12 @@ static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) ah->ah_capabilities.cap_range.range_5ghz_max = 6100; /* Set supported modes */ - __set_bit(MODE_IEEE80211A, + __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); - __set_bit(MODE_ATHEROS_TURBO, + __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode); if (ah->ah_version == AR5K_AR5212) - __set_bit(MODE_ATHEROS_TURBOG, + __set_bit(AR5K_MODE_11G_TURBO, ah->ah_capabilities.cap_mode); } @@ -2150,11 +2167,11 @@ static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) ah->ah_capabilities.cap_range.range_2ghz_max = 2732; if (AR5K_EEPROM_HDR_11B(ee_header)) - __set_bit(MODE_IEEE80211B, + __set_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode); if (AR5K_EEPROM_HDR_11G(ee_header)) - __set_bit(MODE_IEEE80211G, + __set_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode); } } @@ -2279,8 +2296,8 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set simple BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1); + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); } /* @@ -2425,6 +2442,8 @@ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); + + /* TODO: ANI Support */ } /* @@ -2434,6 +2453,8 @@ void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); + + /* TODO: ANI Support */ } /* @@ -3186,19 +3207,19 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) return 0; /* Set Slot time */ - ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + ath5k_hw_reg_write(ah, ah->ah_turbo ? AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, AR5K_SLOT_TIME); /* Set ACK_CTS timeout */ - ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + ath5k_hw_reg_write(ah, ah->ah_turbo ? AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); /* Set Transmit Latency */ - ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + ath5k_hw_reg_write(ah, ah->ah_turbo ? AR5K_INIT_TRANSMIT_LATENCY_TURBO : AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); /* Set IFS0 */ - if (ah->ah_turbo == true) + if (ah->ah_turbo) ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + (ah->ah_aifs + tq->tqi_aifs) * AR5K_INIT_SLOT_TIME_TURBO) << @@ -3211,16 +3232,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_INIT_SIFS, AR5K_IFS0); /* Set IFS1 */ - ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + ath5k_hw_reg_write(ah, ah->ah_turbo ? AR5K_INIT_PROTO_TIME_CNTRL_TURBO : AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); /* Set PHY register 0x9844 (??) */ - ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + ath5k_hw_reg_write(ah, ah->ah_turbo ? (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 : (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C, AR5K_PHY(17)); /* Set Frame Control Register */ - ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + ath5k_hw_reg_write(ah, ah->ah_turbo ? (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT | 0x2020) : (AR5K_PHY_FRAME_CTL_INI | 0x1020), @@ -3259,7 +3280,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) /* * Calculate and set retry limits */ - if (ah->ah_software_retry == true) { + if (ah->ah_software_retry) { /* XXX Need to test this */ retry_lg = ah->ah_limit_tx_retries; retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? @@ -3507,10 +3528,10 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int rtscts_rate, unsigned int rtscts_duration) { u32 frame_type; - struct ath5k_hw_2w_tx_desc *tx_desc; + struct ath5k_hw_2w_tx_ctl *tx_ctl; unsigned int frame_len; - tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; + tx_ctl = &desc->ud.ds_tx5210.tx_ctl; /* * Validate input @@ -3529,12 +3550,8 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, return -EINVAL; } - /* Clear status descriptor */ - memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status)); - - /* Initialize control descriptor */ - tx_desc->tx_control_0 = 0; - tx_desc->tx_control_1 = 0; + /* Clear descriptor */ + memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); /* Setup control descriptor */ @@ -3546,7 +3563,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; + tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ @@ -3557,7 +3574,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; + tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; /* * Verify and set header length @@ -3566,7 +3583,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, if (ah->ah_version == AR5K_AR5210) { if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) return -EINVAL; - tx_desc->tx_control_0 |= + tx_ctl->tx_control_0 |= AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); } @@ -3582,19 +3599,19 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, frame_type = type /*<< 2 ?*/; } - tx_desc->tx_control_0 |= + tx_ctl->tx_control_0 |= AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); } else { - tx_desc->tx_control_0 |= + tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_desc->tx_control_1 |= + tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); } #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) \ - tx_desc->tx_control_##_c |= \ + tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag _TX_FLAGS(0, CLRDMASK); @@ -3609,9 +3626,9 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { - tx_desc->tx_control_0 |= + tx_ctl->tx_control_0 |= AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_desc->tx_control_1 |= + tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); } @@ -3621,7 +3638,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, */ if ((ah->ah_version == AR5K_AR5210) && (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) - tx_desc->tx_control_1 |= rtscts_duration & + tx_ctl->tx_control_1 |= rtscts_duration & AR5K_2W_TX_DESC_CTL1_RTS_DURATION; return 0; @@ -3637,13 +3654,11 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { - struct ath5k_hw_4w_tx_desc *tx_desc; - struct ath5k_hw_tx_status *tx_status; + struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; ATH5K_TRACE(ah->ah_sc); - tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; - tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* * Validate input @@ -3662,14 +3677,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, return -EINVAL; } - /* Clear status descriptor */ - memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status)); - - /* Initialize control descriptor */ - tx_desc->tx_control_0 = 0; - tx_desc->tx_control_1 = 0; - tx_desc->tx_control_2 = 0; - tx_desc->tx_control_3 = 0; + /* Clear descriptor */ + memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); /* Setup control descriptor */ @@ -3681,7 +3690,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ @@ -3692,20 +3701,20 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; - tx_desc->tx_control_0 |= + tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_desc->tx_control_1 |= AR5K_REG_SM(type, + tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, + tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); - tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) \ - tx_desc->tx_control_##_c |= \ + tx_ctl->tx_control_##_c |= \ AR5K_4W_TX_DESC_CTL##_c##_##_flag _TX_FLAGS(0, CLRDMASK); @@ -3721,8 +3730,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { - tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_desc->tx_control_1 |= AR5K_REG_SM(key_index, + tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); } @@ -3733,9 +3742,9 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; - tx_desc->tx_control_2 |= rtscts_duration & + tx_ctl->tx_control_2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; - tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } @@ -3750,7 +3759,7 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) { - struct ath5k_hw_4w_tx_desc *tx_desc; + struct ath5k_hw_4w_tx_ctl *tx_ctl; /* * Rates can be 0 as long as the retry count is 0 too. @@ -3767,14 +3776,14 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, } if (ah->ah_version == AR5K_AR5212) { - tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; #define _XTX_TRIES(_n) \ if (tx_tries##_n) { \ - tx_desc->tx_control_2 |= \ + tx_ctl->tx_control_2 |= \ AR5K_REG_SM(tx_tries##_n, \ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ - tx_desc->tx_control_3 |= \ + tx_ctl->tx_control_3 |= \ AR5K_REG_SM(tx_rate##_n, \ AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ } @@ -3795,13 +3804,15 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, * Proccess the tx status descriptor on 5210/5211 */ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc) + struct ath5k_desc *desc, struct ath5k_tx_status *ts) { + struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - struct ath5k_hw_2w_tx_desc *tx_desc; - tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; - tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0]; + ATH5K_TRACE(ah->ah_sc); + + tx_ctl = &desc->ud.ds_tx5210.tx_ctl; + tx_status = &desc->ud.ds_tx5210.tx_stat; /* No frame has been send or error */ if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) @@ -3810,32 +3821,32 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, /* * Get descriptor status */ - desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - /*TODO: desc->ds_us.tx.ts_virtcol + test*/ - desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + /*TODO: ts->ts_virtcol + test*/ + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_SEQ_NUM); - desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - desc->ds_us.tx.ts_antenna = 1; - desc->ds_us.tx.ts_status = 0; - desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0, + ts->ts_antenna = 1; + ts->ts_status = 0; + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) - desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; + ts->ts_status |= AR5K_TXERR_XRETRY; if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) - desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; + ts->ts_status |= AR5K_TXERR_FIFO; if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) - desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; + ts->ts_status |= AR5K_TXERR_FILT; } return 0; @@ -3845,14 +3856,15 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, * Proccess a tx descriptor on 5212 */ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc) + struct ath5k_desc *desc, struct ath5k_tx_status *ts) { + struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - struct ath5k_hw_4w_tx_desc *tx_desc; ATH5K_TRACE(ah->ah_sc); - tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; - tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; + + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + tx_status = &desc->ud.ds_tx5212.tx_stat; /* No frame has been send or error */ if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) @@ -3861,42 +3873,42 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, /* * Get descriptor status */ - desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_SEQ_NUM); - desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 & + ts->ts_antenna = (tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; - desc->ds_us.tx.ts_status = 0; + ts->ts_status = 0; switch (AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { case 0: - desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 & + ts->ts_rate = tx_ctl->tx_control_3 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; break; case 1: - desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, + ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); break; case 2: - desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, + ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); break; case 3: - desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, + ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); break; } @@ -3904,13 +3916,13 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) - desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; + ts->ts_status |= AR5K_TXERR_XRETRY; if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) - desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; + ts->ts_status |= AR5K_TXERR_FIFO; if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) - desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; + ts->ts_status |= AR5K_TXERR_FILT; } return 0; @@ -3926,31 +3938,27 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags) { - struct ath5k_rx_desc *rx_desc; + struct ath5k_hw_rx_ctl *rx_ctl; ATH5K_TRACE(ah->ah_sc); - rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0; + rx_ctl = &desc->ud.ds_rx.rx_ctl; /* - *Clear ds_hw + * Clear the descriptor * If we don't clean the status descriptor, * while scanning we get too many results, * most of them virtual, after some secs * of scanning system hangs. M.F. */ - memset(desc->ds_hw, 0, sizeof(desc->ds_hw)); - - /*Initialize rx descriptor*/ - rx_desc->rx_control_0 = 0; - rx_desc->rx_control_1 = 0; + memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); /* Setup descriptor */ - rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; - if (unlikely(rx_desc->rx_control_1 != size)) + rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; + if (unlikely(rx_ctl->rx_control_1 != size)) return -EINVAL; if (flags & AR5K_RXDESC_INTREQ) - rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; + rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; return 0; } @@ -3958,67 +3966,68 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* * Proccess the rx status descriptor on 5210/5211 */ -static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc) +static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) { - struct ath5k_hw_old_rx_status *rx_status; + struct ath5k_hw_rx_status *rx_status; - rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0]; + rx_status = &desc->ud.ds_rx.u.rx_stat; /* No frame received / not ready */ - if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE) + if (unlikely((rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE) == 0)) return -EINPROGRESS; /* * Frame receive status */ - desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & - AR5K_OLD_RX_DESC_STATUS0_DATA_LEN; - desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL); - desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE); - desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & - AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA; - desc->ds_us.rx.rs_more = rx_status->rx_status_0 & - AR5K_OLD_RX_DESC_STATUS0_MORE; - desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - desc->ds_us.rx.rs_status = 0; + rs->rs_datalen = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); + rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); + rs->rs_antenna = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA; + rs->rs_more = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_MORE; + /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ + rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + rs->rs_status = 0; /* * Key table status */ - if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID) - desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX); + if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); else - desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; + rs->rs_keyix = AR5K_RXKEYIX_INVALID; /* * Receive/descriptor errors */ - if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK) - == 0) { - if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR) - desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; + if ((rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; if (rx_status->rx_status_1 & - AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN) - desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO; + AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) + rs->rs_status |= AR5K_RXERR_FIFO; if (rx_status->rx_status_1 & - AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) { - desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; - desc->ds_us.rx.rs_phyerr = - AR5K_REG_MS(rx_status->rx_status_1, - AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR); + AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; + rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); } if (rx_status->rx_status_1 & - AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) - desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; + AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; } return 0; @@ -4027,71 +4036,72 @@ static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah, /* * Proccess the rx status descriptor on 5212 */ -static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc) +static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) { - struct ath5k_hw_new_rx_status *rx_status; + struct ath5k_hw_rx_status *rx_status; struct ath5k_hw_rx_error *rx_err; ATH5K_TRACE(ah->ah_sc); - rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0]; + rx_status = &desc->ud.ds_rx.u.rx_stat; /* Overlay on error */ - rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0]; + rx_err = &desc->ud.ds_rx.u.rx_err; /* No frame received / not ready */ - if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE) + if (unlikely((rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE) == 0)) return -EINPROGRESS; /* * Frame receive status */ - desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & - AR5K_NEW_RX_DESC_STATUS0_DATA_LEN; - desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL); - desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE); - desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & - AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA; - desc->ds_us.rx.rs_more = rx_status->rx_status_0 & - AR5K_NEW_RX_DESC_STATUS0_MORE; - desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - desc->ds_us.rx.rs_status = 0; + rs->rs_datalen = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); + rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); + rs->rs_antenna = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA; + rs->rs_more = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_MORE; + rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + rs->rs_status = 0; /* * Key table status */ - if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID) - desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX); + if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); else - desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; + rs->rs_keyix = AR5K_RXKEYIX_INVALID; /* * Receive/descriptor errors */ if ((rx_status->rx_status_1 & - AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { - if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR) - desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; + AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; if (rx_status->rx_status_1 & - AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) { - desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; - desc->ds_us.rx.rs_phyerr = - AR5K_REG_MS(rx_err->rx_error_1, - AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); + AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; + rs->rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1, + AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); } if (rx_status->rx_status_1 & - AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) - desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; + AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; - if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR) - desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC; + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + rs->rs_status |= AR5K_RXERR_MIC; } return 0; @@ -4250,35 +4260,6 @@ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, } -/*********************************\ - Regulatory Domain/Channels Setup -\*********************************/ - -u16 ath5k_get_regdomain(struct ath5k_hw *ah) -{ - u16 regdomain; - enum ath5k_regdom ieee_regdomain; -#ifdef COUNTRYCODE - u16 code; -#endif - - ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain); - ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain; - -#ifdef COUNTRYCODE - /* - * Get the regulation domain by country code. This will ignore - * the settings found in the EEPROM. - */ - code = ieee80211_name2countrycode(COUNTRYCODE); - ieee_regdomain = ieee80211_countrycode2regdomain(code); -#endif - - regdomain = ath5k_regdom_from_ieee(ieee_regdomain); - ah->ah_capabilities.cap_regdomain.reg_current = regdomain; - - return regdomain; -} /****************\ diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h index d9a7c0973f5..64fca8dcb38 100644 --- a/drivers/net/wireless/ath5k/hw.h +++ b/drivers/net/wireless/ath5k/hw.h @@ -173,7 +173,10 @@ struct ath5k_eeprom_info { * (rX: reserved fields possibily used by future versions of the ar5k chipset) */ -struct ath5k_rx_desc { +/* + * common hardware RX control descriptor + */ +struct ath5k_hw_rx_ctl { u32 rx_control_0; /* RX control word 0 */ #define AR5K_DESC_RX_CTL0 0x00000000 @@ -185,69 +188,63 @@ struct ath5k_rx_desc { } __packed; /* - * 5210/5211 rx status descriptor + * common hardware RX status descriptor + * 5210/11 and 5212 differ only in the flags defined below */ -struct ath5k_hw_old_rx_status { +struct ath5k_hw_rx_status { u32 rx_status_0; /* RX status word 0 */ - -#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN 0x00000fff -#define AR5K_OLD_RX_DESC_STATUS0_MORE 0x00001000 -#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 -#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 -#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 -#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 -#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 - u32 rx_status_1; /* RX status word 1 */ - -#define AR5K_OLD_RX_DESC_STATUS1_DONE 0x00000001 -#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 -#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR 0x00000004 -#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 -#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 -#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 -#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S 5 -#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 -#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 -#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 -#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 } __packed; +/* 5210/5211 */ +#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff +#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 +#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 +#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 +#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 +#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 +#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 +#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 + +/* 5212 */ +#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff +#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 +#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 +#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 +#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 +#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 +#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 +#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 +#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 +#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 + /* - * 5212 rx status descriptor + * common hardware RX error descriptor */ -struct ath5k_hw_new_rx_status { - u32 rx_status_0; /* RX status word 0 */ - -#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN 0x00000fff -#define AR5K_NEW_RX_DESC_STATUS0_MORE 0x00001000 -#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 -#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 -#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 -#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 -#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 -#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 - - u32 rx_status_1; /* RX status word 1 */ - -#define AR5K_NEW_RX_DESC_STATUS1_DONE 0x00000001 -#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 -#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR 0x00000004 -#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 -#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR 0x00000010 -#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR 0x00000020 -#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 -#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 -#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 -#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 -} __packed; - struct ath5k_hw_rx_error { u32 rx_error_0; /* RX error word 0 */ @@ -268,7 +265,10 @@ struct ath5k_hw_rx_error { #define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 #define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 -struct ath5k_hw_2w_tx_desc { +/* + * 5210/5211 hardware 2-word TX control descriptor + */ +struct ath5k_hw_2w_tx_ctl { u32 tx_control_0; /* TX control word 0 */ #define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff @@ -314,9 +314,9 @@ struct ath5k_hw_2w_tx_desc { #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 /* - * 5212 4-word tx control descriptor + * 5212 hardware 4-word TX control descriptor */ -struct ath5k_hw_4w_tx_desc { +struct ath5k_hw_4w_tx_ctl { u32 tx_control_0; /* TX control word 0 */ #define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff @@ -374,7 +374,7 @@ struct ath5k_hw_4w_tx_desc { } __packed; /* - * Common tx status descriptor + * Common TX status descriptor */ struct ath5k_hw_tx_status { u32 tx_status_0; /* TX status word 0 */ @@ -415,6 +415,34 @@ struct ath5k_hw_tx_status { /* + * 5210/5211 hardware TX descriptor + */ +struct ath5k_hw_5210_tx_desc { + struct ath5k_hw_2w_tx_ctl tx_ctl; + struct ath5k_hw_tx_status tx_stat; +} __packed; + +/* + * 5212 hardware TX descriptor + */ +struct ath5k_hw_5212_tx_desc { + struct ath5k_hw_4w_tx_ctl tx_ctl; + struct ath5k_hw_tx_status tx_stat; +} __packed; + +/* + * common hardware RX descriptor + */ +struct ath5k_hw_all_rx_desc { + struct ath5k_hw_rx_ctl rx_ctl; + union { + struct ath5k_hw_rx_status rx_stat; + struct ath5k_hw_rx_error rx_err; + } u; +} __packed; + + +/* * AR5K REGISTER ACCESS */ diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index 2c22f1d4ee6..fdbab2f0817 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -678,8 +678,8 @@ static const struct ath5k_ini ar5212_ini[] = { { AR5K_PHY(644), 0x00806333 }, { AR5K_PHY(645), 0x00106c10 }, { AR5K_PHY(646), 0x009c4060 }, - /*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */ { AR5K_PHY(647), 0x1483800a }, + /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413 */ { AR5K_PHY(648), 0x01831061 }, { AR5K_PHY(649), 0x00000400 }, /*{ AR5K_PHY(650), 0x000001b5 },*/ @@ -1081,6 +1081,207 @@ static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, }; +/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */ +/* XXX: No dumps for turbog yet, so turbog is the same with g here with some + * minor tweaking based on dumps from other chips */ +static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { + { AR5K_TXCFG, + /* b g gTurbo */ + { 0x00000015, 0x00000015, 0x00000015 } }, + { AR5K_USEC_5211, + { 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY(10), + { 0x05020000, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY(13), + { 0x00000e00, 0x00000e00, 0x00000e00 } }, + { AR5K_PHY(14), + { 0x0000000a, 0x0000000a, 0x0000000a } }, + { AR5K_PHY(18), + { 0x001a6a64, 0x001a6a64, 0x001a6a64 } }, + { AR5K_PHY(20), + { 0x0de8b0da, 0x0c98b0da, 0x0c98b0da } }, + { AR5K_PHY_SIG, + { 0x7ee80d2e, 0x7ec80d2e, 0x7ec80d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3137665e, 0x3139605e, 0x3139605e } }, + { AR5K_PHY(27), + { 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(642), + { 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x0042c140, 0x0042c140, 0x0042c140 } }, + { 0xa21c, + { 0x1863800a, 0x1883800a, 0x1883800a } }, + { AR5K_DCU_FP, + { 0x000003e0, 0x000003e0, 0x000003e0 } }, + { 0x8060, + { 0x0000000f, 0x0000000f, 0x0000000f } }, + { 0x8118, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x811c, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8120, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8124, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8128, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x812c, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8130, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8134, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8138, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x813c, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8140, + { 0x800000a8, 0x800000a8, 0x800000a8 } }, + { 0x8144, + { 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_AGC, + { 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(11), + { 0x0000a000, 0x0000a000, 0x0000a000 } }, + { AR5K_PHY(15), + { 0x00200400, 0x00200400, 0x00200400 } }, + { AR5K_PHY(19), + { 0x1284233c, 0x1284233c, 0x1284233c } }, + { AR5K_PHY_SCR, + { 0x0000001f, 0x0000001f, 0x0000001f } }, + { AR5K_PHY_SLMT, + { 0x00000080, 0x00000080, 0x00000080 } }, + { AR5K_PHY_SCAL, + { 0x0000000e, 0x0000000e, 0x0000000e } }, + { AR5K_PHY(86), + { 0x000000ff, 0x000000ff, 0x000000ff } }, + { AR5K_PHY(96), + { 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(97), + { 0x02800000, 0x02800000, 0x02800000 } }, + { AR5K_PHY(104), + { 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(120), + { 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(121), + { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } }, + { AR5K_PHY(122), + { 0x3c466478, 0x3c466478, 0x3c466478 } }, + { AR5K_PHY(123), + { 0x000000aa, 0x000000aa, 0x000000aa } }, + { AR5K_PHY_SCLOCK, + { 0x0000000c, 0x0000000c, 0x0000000c } }, + { AR5K_PHY_SDELAY, + { 0x000000ff, 0x000000ff, 0x000000ff } }, + { AR5K_PHY_SPENDING, + { 0x00000014, 0x00000014, 0x00000014 } }, + { 0xa228, + { 0x000009b5, 0x000009b5, 0x000009b5 } }, + { 0xa23c, + { 0x93c889af, 0x93c889af, 0x93c889af } }, + { 0xa24c, + { 0x00000001, 0x00000001, 0x00000001 } }, + { 0xa250, + { 0x0000a000, 0x0000a000, 0x0000a000 } }, + { 0xa254, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa258, + { 0x0cc75380, 0x0cc75380, 0x0cc75380 } }, + { 0xa25c, + { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } }, + { 0xa260, + { 0x5f690f01, 0x5f690f01, 0x5f690f01 } }, + { 0xa264, + { 0x00418a11, 0x00418a11, 0x00418a11 } }, + { 0xa268, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa26c, + { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } }, + { 0xa270, + { 0x00820820, 0x00820820, 0x00820820 } }, + { 0xa274, + { 0x001b7caa, 0x001b7caa, 0x001b7caa } }, + { 0xa278, + { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } }, + { 0xa27c, + { 0x051701ce, 0x051701ce, 0x051701ce } }, + { 0xa300, + { 0x18010000, 0x18010000, 0x18010000 } }, + { 0xa304, + { 0x30032602, 0x30032602, 0x30032602 } }, + { 0xa308, + { 0x48073e06, 0x48073e06, 0x48073e06 } }, + { 0xa30c, + { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } }, + { 0xa310, + { 0x641a600f, 0x641a600f, 0x641a600f } }, + { 0xa314, + { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } }, + { 0xa318, + { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } }, + { 0xa31c, + { 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } }, + { 0xa320, + { 0x9d4f970f, 0x9d4f970f, 0x9d4f970f } }, + { 0xa324, + { 0xa5cfa18f, 0xa5cfa18f, 0xa5cfa18f } }, + { 0xa328, + { 0xb55faf1f, 0xb55faf1f, 0xb55faf1f } }, + { 0xa32c, + { 0xbddfb99f, 0xbddfb99f, 0xbddfb99f } }, + { 0xa330, + { 0xcd7fc73f, 0xcd7fc73f, 0xcd7fc73f } }, + { 0xa334, + { 0xd5ffd1bf, 0xd5ffd1bf, 0xd5ffd1bf } }, + { 0xa338, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa33c, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa340, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa344, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa348, + { 0x3fffffff, 0x3fffffff, 0x3fffffff } }, + { 0xa34c, + { 0x3fffffff, 0x3fffffff, 0x3fffffff } }, + { 0xa350, + { 0x3fffffff, 0x3fffffff, 0x3fffffff } }, + { 0xa354, + { 0x0003ffff, 0x0003ffff, 0x0003ffff } }, + { 0xa358, + { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } }, + { 0xa35c, + { 0x066c420f, 0x066c420f, 0x066c420f } }, + { 0xa360, + { 0x0f282207, 0x0f282207, 0x0f282207 } }, + { 0xa364, + { 0x17601685, 0x17601685, 0x17601685 } }, + { 0xa368, + { 0x1f801104, 0x1f801104, 0x1f801104 } }, + { 0xa36c, + { 0x37a00c03, 0x37a00c03, 0x37a00c03 } }, + { 0xa370, + { 0x3fc40883, 0x3fc40883, 0x3fc40883 } }, + { 0xa374, + { 0x57c00803, 0x57c00803, 0x57c00803 } }, + { 0xa378, + { 0x5fd80682, 0x5fd80682, 0x5fd80682 } }, + { 0xa37c, + { 0x7fe00482, 0x7fe00482, 0x7fe00482 } }, + { 0xa380, + { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } }, + { 0xa384, + { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, +}; + /* * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) @@ -1290,35 +1491,65 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) /* Second set of mode-specific settings */ if (ah->ah_radio == AR5K_RF5111){ + ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5111_ini_mode_end), ar5212_rf5111_ini_mode_end, mode); + /* Baseband gain table */ ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), rf5111_ini_bbgain, change_channel); + } else if (ah->ah_radio == AR5K_RF5112){ + ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5112_ini_mode_end), ar5212_rf5112_ini_mode_end, mode); - /* Baseband gain table */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, change_channel); + } else if (ah->ah_radio == AR5K_RF5413){ + ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5413_ini_mode_end), rf5413_ini_mode_end, mode); + + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + + } else if (ah->ah_radio == AR5K_RF2413) { + + if (mode < 2) { + ATH5K_ERR(ah->ah_sc, + "unsupported channel mode: %d\n", mode); + return -EINVAL; + } + mode = mode - 2; + + /* Override a setting from ar5212_ini */ + ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648)); + + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf2413_ini_mode_end), + rf2413_ini_mode_end, mode); + /* Baseband gain table */ ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, change_channel); + } /* For AR5211 */ } else if (ah->ah_version == AR5K_AR5211) { - if(mode > 2){ /* AR5K_INI_VAL_11B */ - ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode); + /* AR5K_MODE_11B */ + if (mode > 2) { + ATH5K_ERR(ah->ah_sc, + "unsupported channel mode: %d\n", mode); return -EINVAL; } diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index b9594179714..890ecce8bed 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -666,6 +666,75 @@ static const struct ath5k_ini_rf rfregs_5413[] = { { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, }; +/* RF2413/2414 mode-specific init registers */ +static const struct ath5k_ini_rf rfregs_2413[] = { + { 1, AR5K_RF_BUFFER_CONTROL_4, + { 0x00000020, 0x00000020, 0x00000020 } }, + { 2, AR5K_RF_BUFFER_CONTROL_3, + { 0x02001408, 0x02001408, 0x02001408 } }, + { 3, AR5K_RF_BUFFER_CONTROL_6, + { 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, AR5K_RF_BUFFER, + { 0xf0000000, 0xf0000000, 0xf0000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x03000000, 0x03000000, 0x03000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x40400000, 0x40400000, 0x40400000 } }, + { 6, AR5K_RF_BUFFER, + { 0x65050000, 0x65050000, 0x65050000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00420000, 0x00420000, 0x00420000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00b50000, 0x00b50000, 0x00b50000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00030000, 0x00030000, 0x00030000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00f70000, 0x00f70000, 0x00f70000 } }, + { 6, AR5K_RF_BUFFER, + { 0x009d0000, 0x009d0000, 0x009d0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00220000, 0x00220000, 0x00220000 } }, + { 6, AR5K_RF_BUFFER, + { 0x04220000, 0x04220000, 0x04220000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00230018, 0x00230018, 0x00230018 } }, + { 6, AR5K_RF_BUFFER, + { 0x00280050, 0x00280050, 0x00280050 } }, + { 6, AR5K_RF_BUFFER, + { 0x005000c3, 0x005000c3, 0x005000c3 } }, + { 6, AR5K_RF_BUFFER, + { 0x0004007f, 0x0004007f, 0x0004007f } }, + { 6, AR5K_RF_BUFFER, + { 0x00000458, 0x00000458, 0x00000458 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x0000c000, 0x0000c000, 0x0000c000 } }, + { 6, AR5K_RF_BUFFER_CONTROL_5, + { 0x00400230, 0x00400230, 0x00400230 } }, + { 7, AR5K_RF_BUFFER, + { 0x00006400, 0x00006400, 0x00006400 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000800, 0x00000800, 0x00000800 } }, + { 7, AR5K_RF_BUFFER_CONTROL_2, + { 0x0000000e, 0x0000000e, 0x0000000e } }, +}; /* Initial RF Gain settings for RF5112 */ static const struct ath5k_ini_rfgain rfgain_5112[] = { @@ -805,6 +874,74 @@ static const struct ath5k_ini_rfgain rfgain_5413[] = { { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, }; +/* Initial RF Gain settings for RF2413 */ +static const struct ath5k_ini_rfgain rfgain_2413[] = { + { AR5K_RF_GAIN(0), { 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000181 } }, + { AR5K_RF_GAIN(4), { 0x000001c1 } }, + { AR5K_RF_GAIN(5), { 0x00000001 } }, + { AR5K_RF_GAIN(6), { 0x00000041 } }, + { AR5K_RF_GAIN(7), { 0x00000081 } }, + { AR5K_RF_GAIN(8), { 0x00000168 } }, + { AR5K_RF_GAIN(9), { 0x000001a8 } }, + { AR5K_RF_GAIN(10), { 0x000001e8 } }, + { AR5K_RF_GAIN(11), { 0x00000028 } }, + { AR5K_RF_GAIN(12), { 0x00000068 } }, + { AR5K_RF_GAIN(13), { 0x00000189 } }, + { AR5K_RF_GAIN(14), { 0x000001c9 } }, + { AR5K_RF_GAIN(15), { 0x00000009 } }, + { AR5K_RF_GAIN(16), { 0x00000049 } }, + { AR5K_RF_GAIN(17), { 0x00000089 } }, + { AR5K_RF_GAIN(18), { 0x00000190 } }, + { AR5K_RF_GAIN(19), { 0x000001d0 } }, + { AR5K_RF_GAIN(20), { 0x00000010 } }, + { AR5K_RF_GAIN(21), { 0x00000050 } }, + { AR5K_RF_GAIN(22), { 0x00000090 } }, + { AR5K_RF_GAIN(23), { 0x00000191 } }, + { AR5K_RF_GAIN(24), { 0x000001d1 } }, + { AR5K_RF_GAIN(25), { 0x00000011 } }, + { AR5K_RF_GAIN(26), { 0x00000051 } }, + { AR5K_RF_GAIN(27), { 0x00000091 } }, + { AR5K_RF_GAIN(28), { 0x00000178 } }, + { AR5K_RF_GAIN(29), { 0x000001b8 } }, + { AR5K_RF_GAIN(30), { 0x000001f8 } }, + { AR5K_RF_GAIN(31), { 0x00000038 } }, + { AR5K_RF_GAIN(32), { 0x00000078 } }, + { AR5K_RF_GAIN(33), { 0x00000199 } }, + { AR5K_RF_GAIN(34), { 0x000001d9 } }, + { AR5K_RF_GAIN(35), { 0x00000019 } }, + { AR5K_RF_GAIN(36), { 0x00000059 } }, + { AR5K_RF_GAIN(37), { 0x00000099 } }, + { AR5K_RF_GAIN(38), { 0x000000d9 } }, + { AR5K_RF_GAIN(39), { 0x000000f9 } }, + { AR5K_RF_GAIN(40), { 0x000000f9 } }, + { AR5K_RF_GAIN(41), { 0x000000f9 } }, + { AR5K_RF_GAIN(42), { 0x000000f9 } }, + { AR5K_RF_GAIN(43), { 0x000000f9 } }, + { AR5K_RF_GAIN(44), { 0x000000f9 } }, + { AR5K_RF_GAIN(45), { 0x000000f9 } }, + { AR5K_RF_GAIN(46), { 0x000000f9 } }, + { AR5K_RF_GAIN(47), { 0x000000f9 } }, + { AR5K_RF_GAIN(48), { 0x000000f9 } }, + { AR5K_RF_GAIN(49), { 0x000000f9 } }, + { AR5K_RF_GAIN(50), { 0x000000f9 } }, + { AR5K_RF_GAIN(51), { 0x000000f9 } }, + { AR5K_RF_GAIN(52), { 0x000000f9 } }, + { AR5K_RF_GAIN(53), { 0x000000f9 } }, + { AR5K_RF_GAIN(54), { 0x000000f9 } }, + { AR5K_RF_GAIN(55), { 0x000000f9 } }, + { AR5K_RF_GAIN(56), { 0x000000f9 } }, + { AR5K_RF_GAIN(57), { 0x000000f9 } }, + { AR5K_RF_GAIN(58), { 0x000000f9 } }, + { AR5K_RF_GAIN(59), { 0x000000f9 } }, + { AR5K_RF_GAIN(60), { 0x000000f9 } }, + { AR5K_RF_GAIN(61), { 0x000000f9 } }, + { AR5K_RF_GAIN(62), { 0x000000f9 } }, + { AR5K_RF_GAIN(63), { 0x000000f9 } }, +}; + static const struct ath5k_gain_opt rfgain_opt_5112 = { 1, 8, @@ -844,14 +981,14 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, entry = ((first - 1) / 8) + offset; position = (first - 1) % 8; - if (set == true) + if (set) data = ath5k_hw_bitswap(reg, bits); for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) { last = (position + left > 8) ? 8 : position + left; mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8); - if (set == true) { + if (set) { rf[entry] &= ~mask; rf[entry] |= ((data << position) << (col * 8)) & mask; data >>= (8 - position); @@ -864,7 +1001,7 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, left -= 8 - position; } - data = set == true ? 1 : ath5k_hw_bitswap(data, bits); + data = set ? 1 : ath5k_hw_bitswap(data, bits); return data; } @@ -955,7 +1092,6 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) go = &rfgain_opt_5111; break; case AR5K_RF5112: - case AR5K_RF5413: /* ??? */ go = &rfgain_opt_5112; break; default: @@ -1018,7 +1154,7 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, int obdb = -1, bank = -1; u32 ee_mode; - AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); + AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX); rf = ah->ah_rf_banks; @@ -1038,8 +1174,8 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, } /* Modify bank 0 */ - if (channel->val & CHANNEL_2GHZ) { - if (channel->val & CHANNEL_CCK) + if (channel->hw_value & CHANNEL_2GHZ) { + if (channel->hw_value & CHANNEL_CCK) ee_mode = AR5K_EEPROM_MODE_11B; else ee_mode = AR5K_EEPROM_MODE_11G; @@ -1058,10 +1194,10 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, } else { /* For 11a, Turbo and XR */ ee_mode = AR5K_EEPROM_MODE_11A; - obdb = channel->freq >= 5725 ? 3 : - (channel->freq >= 5500 ? 2 : - (channel->freq >= 5260 ? 1 : - (channel->freq > 4000 ? 0 : -1))); + obdb = channel->center_freq >= 5725 ? 3 : + (channel->center_freq >= 5500 ? 2 : + (channel->center_freq >= 5260 ? 1 : + (channel->center_freq > 4000 ? 0 : -1))); if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ee->ee_pwd_84, 1, 51, 3, true)) @@ -1119,12 +1255,12 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, int obdb = -1, bank = -1; u32 ee_mode; - AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); + AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX); rf = ah->ah_rf_banks; if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A - && !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){ + && !test_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode)) { rf_ini = rfregs_2112a; rf_size = ARRAY_SIZE(rfregs_5112a); if (mode < 2) { @@ -1156,8 +1292,8 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, } /* Modify bank 6 */ - if (channel->val & CHANNEL_2GHZ) { - if (channel->val & CHANNEL_OFDM) + if (channel->hw_value & CHANNEL_2GHZ) { + if (channel->hw_value & CHANNEL_OFDM) ee_mode = AR5K_EEPROM_MODE_11G; else ee_mode = AR5K_EEPROM_MODE_11B; @@ -1173,10 +1309,13 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, } else { /* For 11a, Turbo and XR */ ee_mode = AR5K_EEPROM_MODE_11A; - obdb = channel->freq >= 5725 ? 3 : - (channel->freq >= 5500 ? 2 : - (channel->freq >= 5260 ? 1 : - (channel->freq > 4000 ? 0 : -1))); + obdb = channel->center_freq >= 5725 ? 3 : + (channel->center_freq >= 5500 ? 2 : + (channel->center_freq >= 5260 ? 1 : + (channel->center_freq > 4000 ? 0 : -1))); + + if (obdb == -1) + return -EINVAL; if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], ee->ee_ob[ee_mode][obdb], 3, 279, 0, true)) @@ -1219,12 +1358,25 @@ static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah, unsigned int rf_size, i; int bank = -1; - AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); + AR5K_ASSERT_ENTRY(mode, AR5K_MODE_MAX); rf = ah->ah_rf_banks; - rf_ini = rfregs_5413; - rf_size = ARRAY_SIZE(rfregs_5413); + if (ah->ah_radio == AR5K_RF5413) { + rf_ini = rfregs_5413; + rf_size = ARRAY_SIZE(rfregs_5413); + } else if (ah->ah_radio == AR5K_RF2413) { + rf_ini = rfregs_2413; + rf_size = ARRAY_SIZE(rfregs_2413); + if (mode < 2) { + ATH5K_ERR(ah->ah_sc, + "invalid channel mode: %i\n", mode); + return -EINVAL; + } + mode = mode - 2; + } else { + return -EINVAL; + } /* Copy values to modify them */ for (i = 0; i < rf_size; i++) { @@ -1283,6 +1435,10 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, ah->ah_rf_banks_size = sizeof(rfregs_5413); func = ath5k_hw_rf5413_rfregs; break; + case AR5K_RF2413: + ah->ah_rf_banks_size = sizeof(rfregs_2413); + func = ath5k_hw_rf5413_rfregs; + break; default: return -EINVAL; } @@ -1321,6 +1477,11 @@ int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq) ath5k_rfg = rfgain_5413; size = ARRAY_SIZE(rfgain_5413); break; + case AR5K_RF2413: + ath5k_rfg = rfgain_2413; + size = ARRAY_SIZE(rfgain_2413); + freq = 0; /* only 2Ghz */ + break; default: return -EINVAL; } @@ -1395,7 +1556,6 @@ int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah) ah->ah_gain.g_active = 1; break; case AR5K_RF5112: - case AR5K_RF5413: /* ??? */ ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; ah->ah_gain.g_step = &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx]; @@ -1445,9 +1605,10 @@ static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) * newer chipsets like the AR5212A who have a completely * different RF/PHY part. */ - athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) | - (1 << 6) | 0x1; - + athchan = (ath5k_hw_bitswap( + (ieee80211_frequency_to_channel( + channel->center_freq) - 24) / 2, 5) + << 1) | (1 << 6) | 0x1; return athchan; } @@ -1506,7 +1667,8 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct ath5k_athchan_2ghz ath5k_channel_2ghz; - unsigned int ath5k_channel = channel->chan; + unsigned int ath5k_channel = + ieee80211_frequency_to_channel(channel->center_freq); u32 data0, data1, clock; int ret; @@ -1515,10 +1677,11 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, */ data0 = data1 = 0; - if (channel->val & CHANNEL_2GHZ) { + if (channel->hw_value & CHANNEL_2GHZ) { /* Map 2GHz channel to 5GHz Atheros channel ID */ - ret = ath5k_hw_rf5111_chan2athchan(channel->chan, - &ath5k_channel_2ghz); + ret = ath5k_hw_rf5111_chan2athchan( + ieee80211_frequency_to_channel(channel->center_freq), + &ath5k_channel_2ghz); if (ret) return ret; @@ -1555,7 +1718,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, u16 c; data = data0 = data1 = data2 = 0; - c = channel->freq; + c = channel->center_freq; /* * Set the channel on the RF5112 or newer @@ -1599,19 +1762,17 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { int ret; - /* - * Check bounds supported by the PHY - * (don't care about regulation restrictions at this point) - */ - if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min || - channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) && - (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min || - channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) { + * Check bounds supported by the PHY (we don't care about regultory + * restrictions at this point). Note: hw_value already has the band + * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok() + * of the band by that */ + if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) { ATH5K_ERR(ah->ah_sc, - "channel out of supported range (%u MHz)\n", - channel->freq); - return -EINVAL; + "channel frequency (%u MHz) out of supported " + "band range\n", + channel->center_freq); + return -EINVAL; } /* @@ -1632,9 +1793,9 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) if (ret) return ret; - ah->ah_current_channel.freq = channel->freq; - ah->ah_current_channel.val = channel->val; - ah->ah_turbo = channel->val == CHANNEL_T ? true : false; + ah->ah_current_channel.center_freq = channel->center_freq; + ah->ah_current_channel.hw_value = channel->hw_value; + ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; return 0; } @@ -1797,11 +1958,11 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, if (ret) { ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", - channel->freq); + channel->center_freq); return ret; } - ret = ath5k_hw_noise_floor_calibration(ah, channel->freq); + ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); if (ret) return ret; @@ -1825,7 +1986,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; ATH5K_TRACE(ah->ah_sc); - if (ah->ah_calibration == false || + if (!ah->ah_calibration || ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) goto done; @@ -1848,10 +2009,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); done: - ath5k_hw_noise_floor_calibration(ah, channel->freq); + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* Request RF gain */ - if (channel->val & CHANNEL_5GHZ) { + if (channel->hw_value & CHANNEL_5GHZ) { ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max, AR5K_PHY_PAPD_PROBE_TXPOWER) | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); @@ -2015,6 +2176,15 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, return -EINVAL; } + /* + * RF2413 for some reason can't + * transmit anything if we call + * this funtion, so we skip it + * until we fix txpower. + */ + if (ah->ah_radio == AR5K_RF2413) + return 0; + /* Reset TX power values */ memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); ah->ah_txpower.txp_tpc = tpc; @@ -2048,7 +2218,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); - if (ah->ah_txpower.txp_tpc == true) + if (ah->ah_txpower.txp_tpc) ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); else diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 2f41c839860..30629b3e37c 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -1923,7 +1923,9 @@ after DFS is enabled */ #define AR5K_PHY_SDELAY_32MHZ 0x000000ff #define AR5K_PHY_SPENDING 0x99f8 #define AR5K_PHY_SPENDING_RF5111 0x00000018 -#define AR5K_PHY_SPENDING_RF5112 0x00000014 +#define AR5K_PHY_SPENDING_RF5112 0x00000014 /* <- i 've only seen this on 2425 dumps ! */ +#define AR5K_PHY_SPENDING_RF5112A 0x0000000e /* but since i only have 5112A-based chips */ +#define AR5K_PHY_SPENDING_RF5424 0x00000012 /* to test it might be also for old 5112. */ /* * Misc PHY/radio registers [5110 - 5111] diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 63ec7a70ee7..ef2da4023d6 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -66,6 +66,7 @@ #include <linux/device.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/jiffies.h> #include <net/ieee80211.h> #include "atmel.h" @@ -516,7 +517,7 @@ struct atmel_private { SITE_SURVEY_IN_PROGRESS, SITE_SURVEY_COMPLETED } site_survey_state; - time_t last_survey; + unsigned long last_survey; int station_was_associated, station_is_associated; int fast_scan; @@ -2283,7 +2284,7 @@ static int atmel_set_scan(struct net_device *dev, return -EAGAIN; /* Timeout old surveys. */ - if ((jiffies - priv->last_survey) > (20 * HZ)) + if (time_after(jiffies, priv->last_survey + 20 * HZ)) priv->site_survey_state = SITE_SURVEY_IDLE; priv->last_survey = jiffies; diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 8bc4bc4c330..f51b2d9b085 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -62,6 +62,14 @@ config B43_PCMCIA If unsure, say N. +# Data transfers to the device via PIO +# This is only needed on PCMCIA devices. All others can do DMA properly. +config B43_PIO + bool + depends on B43 && (B43_PCMCIA || B43_FORCE_PIO) + select SSB_BLOCKIO + default y + config B43_NPHY bool "Pre IEEE 802.11n support (BROKEN)" depends on B43 && EXPERIMENTAL && BROKEN @@ -94,3 +102,13 @@ config B43_DEBUG Say Y, if you want to find out why the driver does not work for you. + +config B43_FORCE_PIO + bool "Force usage of PIO instead of DMA" + depends on B43 && B43_DEBUG + ---help--- + This will disable DMA and always enable PIO instead. + + Say N! + This is only for debugging the PIO engine code. You do + _NOT_ want to enable this. diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index ac1329dba04..8c52b0b9862 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,13 +1,14 @@ b43-y += main.o b43-y += tables.o -b43-y += tables_nphy.o +b43-$(CONFIG_B43_NPHY) += tables_nphy.o b43-y += phy.o -b43-y += nphy.o +b43-$(CONFIG_B43_NPHY) += nphy.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o b43-y += wa.o b43-y += dma.o +b43-$(CONFIG_B43_PIO) += pio.o b43-$(CONFIG_B43_RFKILL) += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f13346ba9dd..eff2a158a41 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -75,6 +75,23 @@ #define B43_MMIO_DMA64_BASE4 0x300 #define B43_MMIO_DMA64_BASE5 0x340 +/* PIO on core rev < 11 */ +#define B43_MMIO_PIO_BASE0 0x300 +#define B43_MMIO_PIO_BASE1 0x310 +#define B43_MMIO_PIO_BASE2 0x320 +#define B43_MMIO_PIO_BASE3 0x330 +#define B43_MMIO_PIO_BASE4 0x340 +#define B43_MMIO_PIO_BASE5 0x350 +#define B43_MMIO_PIO_BASE6 0x360 +#define B43_MMIO_PIO_BASE7 0x370 +/* PIO on core rev >= 11 */ +#define B43_MMIO_PIO11_BASE0 0x200 +#define B43_MMIO_PIO11_BASE1 0x240 +#define B43_MMIO_PIO11_BASE2 0x280 +#define B43_MMIO_PIO11_BASE3 0x2C0 +#define B43_MMIO_PIO11_BASE4 0x300 +#define B43_MMIO_PIO11_BASE5 0x340 + #define B43_MMIO_PHY_VER 0x3E0 #define B43_MMIO_PHY_RADIO 0x3E2 #define B43_MMIO_PHY0 0x3E6 @@ -94,11 +111,14 @@ #define B43_MMIO_GPIO_MASK 0x49E #define B43_MMIO_TSF_CFP_START_LOW 0x604 #define B43_MMIO_TSF_CFP_START_HIGH 0x606 +#define B43_MMIO_TSF_CFP_PRETBTT 0x612 #define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */ #define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */ #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ #define B43_MMIO_RNG 0x65A +#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ +#define B43_MMIO_IFSCTL_USE_EDCF 0x0004 #define B43_MMIO_POWERUP_DELAY 0x6A8 /* SPROM boardflags_lo values */ @@ -144,7 +164,8 @@ enum { #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ #define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */ -#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */ +#define B43_SHM_SH_HOSTFMI 0x0060 /* Hostflags for ucode options (middle) */ +#define B43_SHM_SH_HOSTFHI 0x0062 /* Hostflags for ucode options (high) */ #define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */ #define B43_SHM_SH_RADAR 0x0066 /* Radar register */ #define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */ @@ -232,31 +253,41 @@ enum { #define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) /* HostFlags. See b43_hf_read/write() */ -#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */ -#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */ -#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */ -#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */ -#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */ -#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */ -#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */ -#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */ -#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */ -#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */ -#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */ -#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */ -#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */ -#define B43_HF_RADARW 0x00002000 /* Radar workaround */ -#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */ -#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */ -#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */ -#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */ -#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */ -#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */ -#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */ -#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */ -#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */ -#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */ -#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */ +#define B43_HF_ANTDIVHELP 0x000000000001ULL /* ucode antenna div helper */ +#define B43_HF_SYMW 0x000000000002ULL /* G-PHY SYM workaround */ +#define B43_HF_RXPULLW 0x000000000004ULL /* RX pullup workaround */ +#define B43_HF_CCKBOOST 0x000000000008ULL /* 4dB CCK power boost (exclusive with OFDM boost) */ +#define B43_HF_BTCOEX 0x000000000010ULL /* Bluetooth coexistance */ +#define B43_HF_GDCW 0x000000000020ULL /* G-PHY DC canceller filter bw workaround */ +#define B43_HF_OFDMPABOOST 0x000000000040ULL /* Enable PA gain boost for OFDM */ +#define B43_HF_ACPR 0x000000000080ULL /* Disable for Japan, channel 14 */ +#define B43_HF_EDCF 0x000000000100ULL /* on if WME and MAC suspended */ +#define B43_HF_TSSIRPSMW 0x000000000200ULL /* TSSI reset PSM ucode workaround */ +#define B43_HF_20IN40IQW 0x000000000200ULL /* 20 in 40 MHz I/Q workaround (rev >= 13 only) */ +#define B43_HF_DSCRQ 0x000000000400ULL /* Disable slow clock request in ucode */ +#define B43_HF_ACIW 0x000000000800ULL /* ACI workaround: shift bits by 2 on PHY CRS */ +#define B43_HF_2060W 0x000000001000ULL /* 2060 radio workaround */ +#define B43_HF_RADARW 0x000000002000ULL /* Radar workaround */ +#define B43_HF_USEDEFKEYS 0x000000004000ULL /* Enable use of default keys */ +#define B43_HF_AFTERBURNER 0x000000008000ULL /* Afterburner enabled */ +#define B43_HF_BT4PRIOCOEX 0x000000010000ULL /* Bluetooth 4-priority coexistance */ +#define B43_HF_FWKUP 0x000000020000ULL /* Fast wake-up ucode */ +#define B43_HF_VCORECALC 0x000000040000ULL /* Force VCO recalculation when powering up synthpu */ +#define B43_HF_PCISCW 0x000000080000ULL /* PCI slow clock workaround */ +#define B43_HF_4318TSSI 0x000000200000ULL /* 4318 TSSI */ +#define B43_HF_FBCMCFIFO 0x000000400000ULL /* Flush bcast/mcast FIFO immediately */ +#define B43_HF_HWPCTL 0x000000800000ULL /* Enable hardwarre power control */ +#define B43_HF_BTCOEXALT 0x000001000000ULL /* Bluetooth coexistance in alternate pins */ +#define B43_HF_TXBTCHECK 0x000002000000ULL /* Bluetooth check during transmission */ +#define B43_HF_SKCFPUP 0x000004000000ULL /* Skip CFP update */ +#define B43_HF_N40W 0x000008000000ULL /* N PHY 40 MHz workaround (rev >= 13 only) */ +#define B43_HF_ANTSEL 0x000020000000ULL /* Antenna selection (for testing antenna div.) */ +#define B43_HF_BT3COEXT 0x000020000000ULL /* Bluetooth 3-wire coexistence (rev >= 13 only) */ +#define B43_HF_BTCANT 0x000040000000ULL /* Bluetooth coexistence (antenna mode) (rev >= 13 only) */ +#define B43_HF_ANTSELEN 0x000100000000ULL /* Antenna selection enabled (rev >= 13 only) */ +#define B43_HF_ANTSELMODE 0x000200000000ULL /* Antenna selection mode (rev >= 13 only) */ +#define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */ +#define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */ /* MacFilter offsets. */ #define B43_MACFILTER_SELF 0x0000 @@ -380,7 +411,6 @@ enum { #define B43_IRQ_ALL 0xFFFFFFFF #define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \ - B43_IRQ_BEACON | \ B43_IRQ_TBTT_INDI | \ B43_IRQ_ATIM_END | \ B43_IRQ_PMQ | \ @@ -429,7 +459,6 @@ enum { }; struct b43_dmaring; -struct b43_pioqueue; /* The firmware file header */ #define B43_FW_TYPE_UCODE 'u' @@ -458,20 +487,13 @@ struct b43_iv { } __attribute__((__packed__)); -#define B43_PHYMODE(phytype) (1 << (phytype)) -#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A) -#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B) -#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G) - struct b43_phy { - /* Possible PHYMODEs on this PHY */ - u8 possible_phymodes; + /* Band support flags. */ + bool supports_2ghz; + bool supports_5ghz; + /* GMODE bit enabled? */ bool gmode; - /* Possible ieee80211 subsystem hwmodes for this PHY. - * Which mode is selected, depends on thr GMODE enabled bit */ -#define B43_MAX_PHYHWMODES 2 - struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES]; /* Analog Type */ u8 analog; @@ -583,15 +605,27 @@ struct b43_phy { /* Data structures for DMA transmission, per 80211 core. */ struct b43_dma { - struct b43_dmaring *tx_ring0; - struct b43_dmaring *tx_ring1; - struct b43_dmaring *tx_ring2; - struct b43_dmaring *tx_ring3; - struct b43_dmaring *tx_ring4; - struct b43_dmaring *tx_ring5; - - struct b43_dmaring *rx_ring0; - struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */ + struct b43_dmaring *tx_ring_AC_BK; /* Background */ + struct b43_dmaring *tx_ring_AC_BE; /* Best Effort */ + struct b43_dmaring *tx_ring_AC_VI; /* Video */ + struct b43_dmaring *tx_ring_AC_VO; /* Voice */ + struct b43_dmaring *tx_ring_mcast; /* Multicast */ + + struct b43_dmaring *rx_ring; +}; + +struct b43_pio_txqueue; +struct b43_pio_rxqueue; + +/* Data structures for PIO transmission, per 80211 core. */ +struct b43_pio { + struct b43_pio_txqueue *tx_queue_AC_BK; /* Background */ + struct b43_pio_txqueue *tx_queue_AC_BE; /* Best Effort */ + struct b43_pio_txqueue *tx_queue_AC_VI; /* Video */ + struct b43_pio_txqueue *tx_queue_AC_VO; /* Voice */ + struct b43_pio_txqueue *tx_queue_mcast; /* Multicast */ + + struct b43_pio_rxqueue *rx_queue; }; /* Context information for a noise calculation (Link Quality). */ @@ -617,6 +651,35 @@ struct b43_key { u8 algorithm; }; +/* SHM offsets to the QOS data structures for the 4 different queues. */ +#define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \ + (B43_NR_QOSPARAMS * sizeof(u16) * (queue))) +#define B43_QOS_BACKGROUND B43_QOS_PARAMS(0) +#define B43_QOS_BESTEFFORT B43_QOS_PARAMS(1) +#define B43_QOS_VIDEO B43_QOS_PARAMS(2) +#define B43_QOS_VOICE B43_QOS_PARAMS(3) + +/* QOS parameter hardware data structure offsets. */ +#define B43_NR_QOSPARAMS 22 +enum { + B43_QOSPARAM_TXOP = 0, + B43_QOSPARAM_CWMIN, + B43_QOSPARAM_CWMAX, + B43_QOSPARAM_CWCUR, + B43_QOSPARAM_AIFS, + B43_QOSPARAM_BSLOTS, + B43_QOSPARAM_REGGAP, + B43_QOSPARAM_STATUS, +}; + +/* QOS parameters for a queue. */ +struct b43_qos_params { + /* The QOS parameters */ + struct ieee80211_tx_queue_params p; + /* Does this need to get uploaded to hardware? */ + bool need_hw_update; +}; + struct b43_wldev; /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ @@ -667,8 +730,16 @@ struct b43_wl { /* The beacon we are currently using (AP or IBSS mode). * This beacon stuff is protected by the irq_lock. */ struct sk_buff *current_beacon; + struct ieee80211_tx_control beacon_txctl; bool beacon0_uploaded; bool beacon1_uploaded; + struct work_struct beacon_update_trigger; + + /* The current QOS parameters for the 4 queues. + * This is protected by the irq_lock. */ + struct b43_qos_params qos_params[4]; + /* Workqueue for updating QOS parameters in hardware. */ + struct work_struct qos_update_work; }; /* In-memory representation of a cached microcode file. */ @@ -727,7 +798,6 @@ struct b43_wldev { bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ - bool short_preamble; /* TRUE, if short preamble is enabled. */ bool short_slot; /* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ @@ -735,8 +805,15 @@ struct b43_wldev { /* PHY/Radio device. */ struct b43_phy phy; - /* DMA engines. */ - struct b43_dma dma; + union { + /* DMA engines. */ + struct b43_dma dma; + /* PIO engines. */ + struct b43_pio pio; + }; + /* Use b43_using_pio_transfers() to check whether we are using + * DMA or PIO data transfers. */ + bool __using_pio_transfers; /* Various statistics about the physical device. */ struct b43_stats stats; @@ -820,6 +897,22 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) ssb_write32(dev->dev, offset, value); } +static inline bool b43_using_pio_transfers(struct b43_wldev *dev) +{ +#ifdef CONFIG_B43_PIO + return dev->__using_pio_transfers; +#else + return 0; +#endif +} + +#ifdef CONFIG_B43_FORCE_PIO +# define B43_FORCE_PIO 1 +#else +# define B43_FORCE_PIO 0 +#endif + + /* Message printing */ void b43info(struct b43_wl *wl, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 948eb1fe916..f1b983cb9c1 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -38,6 +38,7 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/etherdevice.h> +#include <asm/div64.h> /* 32bit DMA ops. */ @@ -291,52 +292,6 @@ static inline int request_slot(struct b43_dmaring *ring) return slot; } -/* Mac80211-queue to b43-ring mapping */ -static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, - int queue_priority) -{ - struct b43_dmaring *ring; - -/*FIXME: For now we always run on TX-ring-1 */ - return dev->dma.tx_ring1; - - /* 0 = highest priority */ - switch (queue_priority) { - default: - B43_WARN_ON(1); - /* fallthrough */ - case 0: - ring = dev->dma.tx_ring3; - break; - case 1: - ring = dev->dma.tx_ring2; - break; - case 2: - ring = dev->dma.tx_ring1; - break; - case 3: - ring = dev->dma.tx_ring0; - break; - } - - return ring; -} - -/* b43-ring to mac80211-queue mapping */ -static inline int txring_to_priority(struct b43_dmaring *ring) -{ - static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; - unsigned int index; - -/*FIXME: have only one queue, for now */ - return 0; - - index = ring->index; - if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) - index = 0; - return idx_to_prio[index]; -} - static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx) { static const u16 map64[] = { @@ -595,7 +550,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, struct b43_dmadesc_meta *meta, gfp_t gfp_flags) { struct b43_rxhdr_fw4 *rxhdr; - struct b43_hwtxstatus *txstat; dma_addr_t dmaaddr; struct sk_buff *skb; @@ -631,8 +585,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, rxhdr = (struct b43_rxhdr_fw4 *)(skb->data); rxhdr->frame_len = 0; - txstat = (struct b43_hwtxstatus *)(skb->data); - txstat->cookie = 0; return 0; } @@ -821,6 +773,18 @@ static u64 supported_dma_mask(struct b43_wldev *dev) return DMA_30BIT_MASK; } +static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask) +{ + if (dmamask == DMA_30BIT_MASK) + return B43_DMA_30BIT; + if (dmamask == DMA_32BIT_MASK) + return B43_DMA_32BIT; + if (dmamask == DMA_64BIT_MASK) + return B43_DMA_64BIT; + B43_WARN_ON(1); + return B43_DMA_30BIT; +} + /* Main initialization function. */ static struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, @@ -936,16 +900,52 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto out; } +#define divide(a, b) ({ \ + typeof(a) __a = a; \ + do_div(__a, b); \ + __a; \ + }) + +#define modulo(a, b) ({ \ + typeof(a) __a = a; \ + do_div(__a, b); \ + }) + /* Main cleanup function. */ -static void b43_destroy_dmaring(struct b43_dmaring *ring) +static void b43_destroy_dmaring(struct b43_dmaring *ring, + const char *ringname) { if (!ring) return; - b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n", - (unsigned int)(ring->type), - ring->mmio_base, - (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); +#ifdef CONFIG_B43_DEBUG + { + /* Print some statistics. */ + u64 failed_packets = ring->nr_failed_tx_packets; + u64 succeed_packets = ring->nr_succeed_tx_packets; + u64 nr_packets = failed_packets + succeed_packets; + u64 permille_failed = 0, average_tries = 0; + + if (nr_packets) + permille_failed = divide(failed_packets * 1000, nr_packets); + if (nr_packets) + average_tries = divide(ring->nr_total_packet_tries * 100, nr_packets); + + b43dbg(ring->dev->wl, "DMA-%u %s: " + "Used slots %d/%d, Failed frames %llu/%llu = %llu.%01llu%%, " + "Average tries %llu.%02llu\n", + (unsigned int)(ring->type), ringname, + ring->max_used_slots, + ring->nr_slots, + (unsigned long long)failed_packets, + (unsigned long long)nr_packets, + (unsigned long long)divide(permille_failed, 10), + (unsigned long long)modulo(permille_failed, 10), + (unsigned long long)divide(average_tries, 100), + (unsigned long long)modulo(average_tries, 100)); + } +#endif /* DEBUG */ + /* Device IRQs are disabled prior entering this function, * so no need to take care of concurrency with rx handler stuff. */ @@ -958,51 +958,36 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring) kfree(ring); } +#define destroy_ring(dma, ring) do { \ + b43_destroy_dmaring((dma)->ring, __stringify(ring)); \ + (dma)->ring = NULL; \ + } while (0) + void b43_dma_free(struct b43_wldev *dev) { - struct b43_dma *dma = &dev->dma; + struct b43_dma *dma; - b43_destroy_dmaring(dma->rx_ring3); - dma->rx_ring3 = NULL; - b43_destroy_dmaring(dma->rx_ring0); - dma->rx_ring0 = NULL; - - b43_destroy_dmaring(dma->tx_ring5); - dma->tx_ring5 = NULL; - b43_destroy_dmaring(dma->tx_ring4); - dma->tx_ring4 = NULL; - b43_destroy_dmaring(dma->tx_ring3); - dma->tx_ring3 = NULL; - b43_destroy_dmaring(dma->tx_ring2); - dma->tx_ring2 = NULL; - b43_destroy_dmaring(dma->tx_ring1); - dma->tx_ring1 = NULL; - b43_destroy_dmaring(dma->tx_ring0); - dma->tx_ring0 = NULL; + if (b43_using_pio_transfers(dev)) + return; + dma = &dev->dma; + + destroy_ring(dma, rx_ring); + destroy_ring(dma, tx_ring_AC_BK); + destroy_ring(dma, tx_ring_AC_BE); + destroy_ring(dma, tx_ring_AC_VI); + destroy_ring(dma, tx_ring_AC_VO); + destroy_ring(dma, tx_ring_mcast); } int b43_dma_init(struct b43_wldev *dev) { struct b43_dma *dma = &dev->dma; - struct b43_dmaring *ring; int err; u64 dmamask; enum b43_dmatype type; dmamask = supported_dma_mask(dev); - switch (dmamask) { - default: - B43_WARN_ON(1); - case DMA_30BIT_MASK: - type = B43_DMA_30BIT; - break; - case DMA_32BIT_MASK: - type = B43_DMA_32BIT; - break; - case DMA_64BIT_MASK: - type = B43_DMA_64BIT; - break; - } + type = dma_mask_to_engine_type(dmamask); err = ssb_dma_set_mask(dev->dev, dmamask); if (err) { b43err(dev->wl, "The machine/kernel does not support " @@ -1014,83 +999,57 @@ int b43_dma_init(struct b43_wldev *dev) err = -ENOMEM; /* setup TX DMA channels. */ - ring = b43_setup_dmaring(dev, 0, 1, type); - if (!ring) + dma->tx_ring_AC_BK = b43_setup_dmaring(dev, 0, 1, type); + if (!dma->tx_ring_AC_BK) goto out; - dma->tx_ring0 = ring; - ring = b43_setup_dmaring(dev, 1, 1, type); - if (!ring) - goto err_destroy_tx0; - dma->tx_ring1 = ring; + dma->tx_ring_AC_BE = b43_setup_dmaring(dev, 1, 1, type); + if (!dma->tx_ring_AC_BE) + goto err_destroy_bk; - ring = b43_setup_dmaring(dev, 2, 1, type); - if (!ring) - goto err_destroy_tx1; - dma->tx_ring2 = ring; + dma->tx_ring_AC_VI = b43_setup_dmaring(dev, 2, 1, type); + if (!dma->tx_ring_AC_VI) + goto err_destroy_be; - ring = b43_setup_dmaring(dev, 3, 1, type); - if (!ring) - goto err_destroy_tx2; - dma->tx_ring3 = ring; + dma->tx_ring_AC_VO = b43_setup_dmaring(dev, 3, 1, type); + if (!dma->tx_ring_AC_VO) + goto err_destroy_vi; - ring = b43_setup_dmaring(dev, 4, 1, type); - if (!ring) - goto err_destroy_tx3; - dma->tx_ring4 = ring; + dma->tx_ring_mcast = b43_setup_dmaring(dev, 4, 1, type); + if (!dma->tx_ring_mcast) + goto err_destroy_vo; - ring = b43_setup_dmaring(dev, 5, 1, type); - if (!ring) - goto err_destroy_tx4; - dma->tx_ring5 = ring; + /* setup RX DMA channel. */ + dma->rx_ring = b43_setup_dmaring(dev, 0, 0, type); + if (!dma->rx_ring) + goto err_destroy_mcast; - /* setup RX DMA channels. */ - ring = b43_setup_dmaring(dev, 0, 0, type); - if (!ring) - goto err_destroy_tx5; - dma->rx_ring0 = ring; - - if (dev->dev->id.revision < 5) { - ring = b43_setup_dmaring(dev, 3, 0, type); - if (!ring) - goto err_destroy_rx0; - dma->rx_ring3 = ring; - } + /* No support for the TX status DMA ring. */ + B43_WARN_ON(dev->dev->id.revision < 5); b43dbg(dev->wl, "%u-bit DMA initialized\n", (unsigned int)type); err = 0; - out: +out: return err; - err_destroy_rx0: - b43_destroy_dmaring(dma->rx_ring0); - dma->rx_ring0 = NULL; - err_destroy_tx5: - b43_destroy_dmaring(dma->tx_ring5); - dma->tx_ring5 = NULL; - err_destroy_tx4: - b43_destroy_dmaring(dma->tx_ring4); - dma->tx_ring4 = NULL; - err_destroy_tx3: - b43_destroy_dmaring(dma->tx_ring3); - dma->tx_ring3 = NULL; - err_destroy_tx2: - b43_destroy_dmaring(dma->tx_ring2); - dma->tx_ring2 = NULL; - err_destroy_tx1: - b43_destroy_dmaring(dma->tx_ring1); - dma->tx_ring1 = NULL; - err_destroy_tx0: - b43_destroy_dmaring(dma->tx_ring0); - dma->tx_ring0 = NULL; - goto out; +err_destroy_mcast: + destroy_ring(dma, tx_ring_mcast); +err_destroy_vo: + destroy_ring(dma, tx_ring_AC_VO); +err_destroy_vi: + destroy_ring(dma, tx_ring_AC_VI); +err_destroy_be: + destroy_ring(dma, tx_ring_AC_BE); +err_destroy_bk: + destroy_ring(dma, tx_ring_AC_BK); + return err; } /* Generate a cookie for the TX header. */ static u16 generate_cookie(struct b43_dmaring *ring, int slot) { - u16 cookie = 0x1000; + u16 cookie; /* Use the upper 4 bits of the cookie as * DMA controller ID and store the slot number @@ -1100,30 +1059,9 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot) * It can also not be 0xFFFF because that is special * for multicast frames. */ - switch (ring->index) { - case 0: - cookie = 0x1000; - break; - case 1: - cookie = 0x2000; - break; - case 2: - cookie = 0x3000; - break; - case 3: - cookie = 0x4000; - break; - case 4: - cookie = 0x5000; - break; - case 5: - cookie = 0x6000; - break; - default: - B43_WARN_ON(1); - } + cookie = (((u16)ring->index + 1) << 12); B43_WARN_ON(slot & ~0x0FFF); - cookie |= (u16) slot; + cookie |= (u16)slot; return cookie; } @@ -1137,22 +1075,19 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) switch (cookie & 0xF000) { case 0x1000: - ring = dma->tx_ring0; + ring = dma->tx_ring_AC_BK; break; case 0x2000: - ring = dma->tx_ring1; + ring = dma->tx_ring_AC_BE; break; case 0x3000: - ring = dma->tx_ring2; + ring = dma->tx_ring_AC_VI; break; case 0x4000: - ring = dma->tx_ring3; + ring = dma->tx_ring_AC_VO; break; case 0x5000: - ring = dma->tx_ring4; - break; - case 0x6000: - ring = dma->tx_ring5; + ring = dma->tx_ring_mcast; break; default: B43_WARN_ON(1); @@ -1179,7 +1114,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, size_t hdrsize = b43_txhdr_size(ring->dev); #define SLOTS_PER_PACKET 2 - B43_WARN_ON(skb_shinfo(skb)->nr_frags); old_top_slot = ring->current_slot; old_used_slots = ring->used_slots; @@ -1284,6 +1218,37 @@ static inline int should_inject_overflow(struct b43_dmaring *ring) return 0; } +/* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ +static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, + u8 queue_prio) +{ + struct b43_dmaring *ring; + + if (b43_modparam_qos) { + /* 0 = highest priority */ + switch (queue_prio) { + default: + B43_WARN_ON(1); + /* fallthrough */ + case 0: + ring = dev->dma.tx_ring_AC_VO; + break; + case 1: + ring = dev->dma.tx_ring_AC_VI; + break; + case 2: + ring = dev->dma.tx_ring_AC_BE; + break; + case 3: + ring = dev->dma.tx_ring_AC_BK; + break; + } + } else + ring = dev->dma.tx_ring_AC_BE; + + return ring; +} + int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { @@ -1292,21 +1257,16 @@ int b43_dma_tx(struct b43_wldev *dev, int err = 0; unsigned long flags; - if (unlikely(skb->len < 2 + 2 + 6)) { - /* Too short, this can't be a valid frame. */ - return -EINVAL; - } - hdr = (struct ieee80211_hdr *)skb->data; if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { /* The multicast ring will be sent after the DTIM */ - ring = dev->dma.tx_ring4; + ring = dev->dma.tx_ring_mcast; /* Set the more-data bit. Ucode will clear it on * the last frame for us. */ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = priority_to_txring(dev, ctl->queue); + ring = select_ring_by_priority(dev, ctl->queue); } spin_lock_irqsave(&ring->lock, flags); @@ -1321,6 +1281,11 @@ int b43_dma_tx(struct b43_wldev *dev, * That would be a mac80211 bug. */ B43_WARN_ON(ring->stopped); + /* Assign the queue number to the ring (if not already done before) + * so TX status handling can use it. The queue to ring mapping is + * static, so we don't need to store it per frame. */ + ring->queue_prio = ctl->queue; + err = dma_tx_fragment(ring, skb, ctl); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key @@ -1337,7 +1302,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); + ieee80211_stop_queue(dev->wl->hw, ctl->queue); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1358,6 +1323,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; int slot; + bool frame_succeed; ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) @@ -1384,18 +1350,15 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, * status of the transmission. * Some fields of txstat are already filled in dma_tx(). */ - if (status->acked) { - meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; - } else { - if (!(meta->txstat.control.flags - & IEEE80211_TXCTL_NO_ACK)) - meta->txstat.excessive_retries = 1; - } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - meta->txstat.retry_count = 0; - } else - meta->txstat.retry_count = status->frame_count - 1; + frame_succeed = b43_fill_txstatus_report( + &(meta->txstat), status); +#ifdef CONFIG_B43_DEBUG + if (frame_succeed) + ring->nr_succeed_tx_packets++; + else + ring->nr_failed_tx_packets++; + ring->nr_total_packet_tries += status->frame_count; +#endif /* DEBUG */ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, &(meta->txstat)); /* skb is freed by ieee80211_tx_status_irqsafe() */ @@ -1417,7 +1380,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, dev->stats.last_tx = jiffies; if (ring->stopped) { B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); - ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); + ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); ring->stopped = 0; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); @@ -1438,7 +1401,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, for (i = 0; i < nr_queues; i++) { data = &(stats->data[i]); - ring = priority_to_txring(dev, i); + ring = select_ring_by_priority(dev, i); spin_lock_irqsave(&ring->lock, flags); data->len = ring->used_slots / SLOTS_PER_PACKET; @@ -1464,25 +1427,6 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); skb = meta->skb; - if (ring->index == 3) { - /* We received an xmit status. */ - struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data; - int i = 0; - - while (hw->cookie == 0) { - if (i > 100) - break; - i++; - udelay(2); - barrier(); - } - b43_handle_hwtxstatus(ring->dev, hw); - /* recycle the descriptor buffer. */ - sync_descbuffer_for_device(ring, meta->dmaaddr, - ring->rx_buffersize); - - return; - } rxhdr = (struct b43_rxhdr_fw4 *)skb->data; len = le16_to_cpu(rxhdr->frame_len); if (len == 0) { @@ -1539,7 +1483,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) skb_pull(skb, ring->frameoffset); b43_rx(ring->dev, skb, rxhdr); - drop: +drop: return; } @@ -1585,21 +1529,55 @@ static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) void b43_dma_tx_suspend(struct b43_wldev *dev) { b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); - b43_dma_tx_suspend_ring(dev->dma.tx_ring0); - b43_dma_tx_suspend_ring(dev->dma.tx_ring1); - b43_dma_tx_suspend_ring(dev->dma.tx_ring2); - b43_dma_tx_suspend_ring(dev->dma.tx_ring3); - b43_dma_tx_suspend_ring(dev->dma.tx_ring4); - b43_dma_tx_suspend_ring(dev->dma.tx_ring5); + b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BK); + b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BE); + b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VI); + b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VO); + b43_dma_tx_suspend_ring(dev->dma.tx_ring_mcast); } void b43_dma_tx_resume(struct b43_wldev *dev) { - b43_dma_tx_resume_ring(dev->dma.tx_ring5); - b43_dma_tx_resume_ring(dev->dma.tx_ring4); - b43_dma_tx_resume_ring(dev->dma.tx_ring3); - b43_dma_tx_resume_ring(dev->dma.tx_ring2); - b43_dma_tx_resume_ring(dev->dma.tx_ring1); - b43_dma_tx_resume_ring(dev->dma.tx_ring0); + b43_dma_tx_resume_ring(dev->dma.tx_ring_mcast); + b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VO); + b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VI); + b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BE); + b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BK); b43_power_saving_ctl_bits(dev, 0); } + +#ifdef CONFIG_B43_PIO +static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type, + u16 mmio_base, bool enable) +{ + u32 ctl; + + if (type == B43_DMA_64BIT) { + ctl = b43_read32(dev, mmio_base + B43_DMA64_RXCTL); + ctl &= ~B43_DMA64_RXDIRECTFIFO; + if (enable) + ctl |= B43_DMA64_RXDIRECTFIFO; + b43_write32(dev, mmio_base + B43_DMA64_RXCTL, ctl); + } else { + ctl = b43_read32(dev, mmio_base + B43_DMA32_RXCTL); + ctl &= ~B43_DMA32_RXDIRECTFIFO; + if (enable) + ctl |= B43_DMA32_RXDIRECTFIFO; + b43_write32(dev, mmio_base + B43_DMA32_RXCTL, ctl); + } +} + +/* Enable/Disable Direct FIFO Receive Mode (PIO) on a RX engine. + * This is called from PIO code, so DMA structures are not available. */ +void b43_dma_direct_fifo_rx(struct b43_wldev *dev, + unsigned int engine_index, bool enable) +{ + enum b43_dmatype type; + u16 mmio_base; + + type = dma_mask_to_engine_type(supported_dma_mask(dev)); + + mmio_base = b43_dmacontroller_base(type, engine_index); + direct_fifo_rx(dev, type, mmio_base, enable); +} +#endif /* CONFIG_B43_PIO */ diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index c0d6b69e650..20acf885dba 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -245,6 +245,9 @@ struct b43_dmaring { enum b43_dmatype type; /* Boolean. Is this ring stopped at ieee80211 level? */ bool stopped; + /* The QOS priority assigned to this ring. Only used for TX rings. + * This is the mac80211 "queue" value. */ + u8 queue_prio; /* Lock, only used for TX. */ spinlock_t lock; struct b43_wldev *dev; @@ -253,7 +256,13 @@ struct b43_dmaring { int max_used_slots; /* Last time we injected a ring overflow. */ unsigned long last_injected_overflow; -#endif /* CONFIG_B43_DEBUG */ + /* Statistics: Number of successfully transmitted packets */ + u64 nr_succeed_tx_packets; + /* Statistics: Number of failed TX packets */ + u64 nr_failed_tx_packets; + /* Statistics: Total number of TX plus all retries. */ + u64 nr_total_packet_tries; +#endif /* CONFIG_B43_DEBUG */ }; static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) @@ -282,4 +291,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, void b43_dma_rx(struct b43_dmaring *ring); +void b43_dma_direct_fifo_rx(struct b43_wldev *dev, + unsigned int engine_index, bool enable); + #endif /* B43_DMA_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c73a75b24cd..345c34bdae9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -46,7 +46,9 @@ #include "main.h" #include "debugfs.h" #include "phy.h" +#include "nphy.h" #include "dma.h" +#include "pio.h" #include "sysfs.h" #include "xmit.h" #include "lo.h" @@ -78,6 +80,11 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +int b43_modparam_qos = 1; +module_param_named(qos, b43_modparam_qos, int, 0444); +MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); + + static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), @@ -96,25 +103,29 @@ MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl); * data in there. This data is the same for all devices, so we don't * get concurrency issues */ #define RATETAB_ENT(_rateid, _flags) \ - { \ - .rate = B43_RATE_TO_BASE100KBPS(_rateid), \ - .val = (_rateid), \ - .val2 = (_rateid), \ - .flags = (_flags), \ + { \ + .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ } + +/* + * NOTE: When changing this, sync with xmit.c's + * b43_plcp_get_bitrate_idx_* functions! + */ static struct ieee80211_rate __b43_ratetable[] = { - RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK), - RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_CCK_RATE_1MB, 0), + RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_OFDM_RATE_6MB, 0), + RATETAB_ENT(B43_OFDM_RATE_9MB, 0), + RATETAB_ENT(B43_OFDM_RATE_12MB, 0), + RATETAB_ENT(B43_OFDM_RATE_18MB, 0), + RATETAB_ENT(B43_OFDM_RATE_24MB, 0), + RATETAB_ENT(B43_OFDM_RATE_36MB, 0), + RATETAB_ENT(B43_OFDM_RATE_48MB, 0), + RATETAB_ENT(B43_OFDM_RATE_54MB, 0), }; #define b43_a_ratetable (__b43_ratetable + 4) @@ -124,53 +135,144 @@ static struct ieee80211_rate __b43_ratetable[] = { #define b43_g_ratetable (__b43_ratetable + 0) #define b43_g_ratetable_size 12 -#define CHANTAB_ENT(_chanid, _freq) \ - { \ - .chan = (_chanid), \ - .freq = (_freq), \ - .val = (_chanid), \ - .flag = IEEE80211_CHAN_W_SCAN | \ - IEEE80211_CHAN_W_ACTIVE_SCAN | \ - IEEE80211_CHAN_W_IBSS, \ - .power_level = 0xFF, \ - .antenna_max = 0xFF, \ - } +#define CHAN4G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} static struct ieee80211_channel b43_2ghz_chantable[] = { - CHANTAB_ENT(1, 2412), - CHANTAB_ENT(2, 2417), - CHANTAB_ENT(3, 2422), - CHANTAB_ENT(4, 2427), - CHANTAB_ENT(5, 2432), - CHANTAB_ENT(6, 2437), - CHANTAB_ENT(7, 2442), - CHANTAB_ENT(8, 2447), - CHANTAB_ENT(9, 2452), - CHANTAB_ENT(10, 2457), - CHANTAB_ENT(11, 2462), - CHANTAB_ENT(12, 2467), - CHANTAB_ENT(13, 2472), - CHANTAB_ENT(14, 2484), + CHAN4G(1, 2412, 0), + CHAN4G(2, 2417, 0), + CHAN4G(3, 2422, 0), + CHAN4G(4, 2427, 0), + CHAN4G(5, 2432, 0), + CHAN4G(6, 2437, 0), + CHAN4G(7, 2442, 0), + CHAN4G(8, 2447, 0), + CHAN4G(9, 2452, 0), + CHAN4G(10, 2457, 0), + CHAN4G(11, 2462, 0), + CHAN4G(12, 2467, 0), + CHAN4G(13, 2472, 0), + CHAN4G(14, 2484, 0), }; -#define b43_2ghz_chantable_size ARRAY_SIZE(b43_2ghz_chantable) - -#if 0 -static struct ieee80211_channel b43_5ghz_chantable[] = { - CHANTAB_ENT(36, 5180), - CHANTAB_ENT(40, 5200), - CHANTAB_ENT(44, 5220), - CHANTAB_ENT(48, 5240), - CHANTAB_ENT(52, 5260), - CHANTAB_ENT(56, 5280), - CHANTAB_ENT(60, 5300), - CHANTAB_ENT(64, 5320), - CHANTAB_ENT(149, 5745), - CHANTAB_ENT(153, 5765), - CHANTAB_ENT(157, 5785), - CHANTAB_ENT(161, 5805), - CHANTAB_ENT(165, 5825), +#undef CHAN4G + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} +static struct ieee80211_channel b43_5ghz_nphy_chantable[] = { + CHAN5G(32, 0), CHAN5G(34, 0), + CHAN5G(36, 0), CHAN5G(38, 0), + CHAN5G(40, 0), CHAN5G(42, 0), + CHAN5G(44, 0), CHAN5G(46, 0), + CHAN5G(48, 0), CHAN5G(50, 0), + CHAN5G(52, 0), CHAN5G(54, 0), + CHAN5G(56, 0), CHAN5G(58, 0), + CHAN5G(60, 0), CHAN5G(62, 0), + CHAN5G(64, 0), CHAN5G(66, 0), + CHAN5G(68, 0), CHAN5G(70, 0), + CHAN5G(72, 0), CHAN5G(74, 0), + CHAN5G(76, 0), CHAN5G(78, 0), + CHAN5G(80, 0), CHAN5G(82, 0), + CHAN5G(84, 0), CHAN5G(86, 0), + CHAN5G(88, 0), CHAN5G(90, 0), + CHAN5G(92, 0), CHAN5G(94, 0), + CHAN5G(96, 0), CHAN5G(98, 0), + CHAN5G(100, 0), CHAN5G(102, 0), + CHAN5G(104, 0), CHAN5G(106, 0), + CHAN5G(108, 0), CHAN5G(110, 0), + CHAN5G(112, 0), CHAN5G(114, 0), + CHAN5G(116, 0), CHAN5G(118, 0), + CHAN5G(120, 0), CHAN5G(122, 0), + CHAN5G(124, 0), CHAN5G(126, 0), + CHAN5G(128, 0), CHAN5G(130, 0), + CHAN5G(132, 0), CHAN5G(134, 0), + CHAN5G(136, 0), CHAN5G(138, 0), + CHAN5G(140, 0), CHAN5G(142, 0), + CHAN5G(144, 0), CHAN5G(145, 0), + CHAN5G(146, 0), CHAN5G(147, 0), + CHAN5G(148, 0), CHAN5G(149, 0), + CHAN5G(150, 0), CHAN5G(151, 0), + CHAN5G(152, 0), CHAN5G(153, 0), + CHAN5G(154, 0), CHAN5G(155, 0), + CHAN5G(156, 0), CHAN5G(157, 0), + CHAN5G(158, 0), CHAN5G(159, 0), + CHAN5G(160, 0), CHAN5G(161, 0), + CHAN5G(162, 0), CHAN5G(163, 0), + CHAN5G(164, 0), CHAN5G(165, 0), + CHAN5G(166, 0), CHAN5G(168, 0), + CHAN5G(170, 0), CHAN5G(172, 0), + CHAN5G(174, 0), CHAN5G(176, 0), + CHAN5G(178, 0), CHAN5G(180, 0), + CHAN5G(182, 0), CHAN5G(184, 0), + CHAN5G(186, 0), CHAN5G(188, 0), + CHAN5G(190, 0), CHAN5G(192, 0), + CHAN5G(194, 0), CHAN5G(196, 0), + CHAN5G(198, 0), CHAN5G(200, 0), + CHAN5G(202, 0), CHAN5G(204, 0), + CHAN5G(206, 0), CHAN5G(208, 0), + CHAN5G(210, 0), CHAN5G(212, 0), + CHAN5G(214, 0), CHAN5G(216, 0), + CHAN5G(218, 0), CHAN5G(220, 0), + CHAN5G(222, 0), CHAN5G(224, 0), + CHAN5G(226, 0), CHAN5G(228, 0), +}; + +static struct ieee80211_channel b43_5ghz_aphy_chantable[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; +#undef CHAN5G + +static struct ieee80211_supported_band b43_band_5GHz_nphy = { + .band = IEEE80211_BAND_5GHZ, + .channels = b43_5ghz_nphy_chantable, + .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable), + .bitrates = b43_a_ratetable, + .n_bitrates = b43_a_ratetable_size, +}; + +static struct ieee80211_supported_band b43_band_5GHz_aphy = { + .band = IEEE80211_BAND_5GHZ, + .channels = b43_5ghz_aphy_chantable, + .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable), + .bitrates = b43_a_ratetable, + .n_bitrates = b43_a_ratetable_size, +}; + +static struct ieee80211_supported_band b43_band_2GHz = { + .band = IEEE80211_BAND_2GHZ, + .channels = b43_2ghz_chantable, + .n_channels = ARRAY_SIZE(b43_2ghz_chantable), + .bitrates = b43_g_ratetable, + .n_bitrates = b43_g_ratetable_size, }; -#define b43_5ghz_chantable_size ARRAY_SIZE(b43_5ghz_chantable) -#endif static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); @@ -370,24 +472,30 @@ out: } /* Read HostFlags */ -u32 b43_hf_read(struct b43_wldev * dev) +u64 b43_hf_read(struct b43_wldev * dev) { - u32 ret; + u64 ret; ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI); ret <<= 16; + ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI); + ret <<= 16; ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO); return ret; } /* Write HostFlags */ -void b43_hf_write(struct b43_wldev *dev, u32 value) +void b43_hf_write(struct b43_wldev *dev, u64 value) { - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF)); - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16)); + u16 lo, mi, hi; + + lo = (value & 0x00000000FFFFULL); + mi = (value & 0x0000FFFF0000ULL) >> 16; + hi = (value & 0xFFFF00000000ULL) >> 32; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); } void b43_tsf_read(struct b43_wldev *dev, u64 * tsf) @@ -912,7 +1020,18 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) /* Turn the Analog ON/OFF */ static void b43_switch_analog(struct b43_wldev *dev, int on) { - b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); + switch (dev->phy.type) { + case B43_PHYTYPE_A: + case B43_PHYTYPE_G: + b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); + break; + case B43_PHYTYPE_N: + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, + on ? 0 : 0x7FFF); + break; + default: + B43_WARN_ON(1); + } } void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) @@ -1162,22 +1281,107 @@ static void b43_write_template_common(struct b43_wldev *dev, size + sizeof(struct b43_plcp_hdr6)); } +/* Check if the use of the antenna that ieee80211 told us to + * use is possible. This will fall back to DEFAULT. + * "antenna_nr" is the antenna identifier we got from ieee80211. */ +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, + u8 antenna_nr) +{ + u8 antenna_mask; + + if (antenna_nr == 0) { + /* Zero means "use default antenna". That's always OK. */ + return 0; + } + + /* Get the mask of available antennas. */ + if (dev->phy.gmode) + antenna_mask = dev->dev->bus->sprom.ant_available_bg; + else + antenna_mask = dev->dev->bus->sprom.ant_available_a; + + if (!(antenna_mask & (1 << (antenna_nr - 1)))) { + /* This antenna is not available. Fall back to default. */ + return 0; + } + + return antenna_nr; +} + +static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) +{ + antenna = b43_ieee80211_antenna_sanitize(dev, antenna); + switch (antenna) { + case 0: /* default/diversity */ + return B43_ANTENNA_DEFAULT; + case 1: /* Antenna 0 */ + return B43_ANTENNA0; + case 2: /* Antenna 1 */ + return B43_ANTENNA1; + case 3: /* Antenna 2 */ + return B43_ANTENNA2; + case 4: /* Antenna 3 */ + return B43_ANTENNA3; + default: + return B43_ANTENNA_DEFAULT; + } +} + +/* Convert a b43 antenna number value to the PHY TX control value. */ +static u16 b43_antenna_to_phyctl(int antenna) +{ + switch (antenna) { + case B43_ANTENNA0: + return B43_TXH_PHY_ANT0; + case B43_ANTENNA1: + return B43_TXH_PHY_ANT1; + case B43_ANTENNA2: + return B43_TXH_PHY_ANT2; + case B43_ANTENNA3: + return B43_TXH_PHY_ANT3; + case B43_ANTENNA_AUTO: + return B43_TXH_PHY_ANT01AUTO; + } + B43_WARN_ON(1); + return 0; +} + static void b43_write_beacon_template(struct b43_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset) { unsigned int i, len, variable_len; const struct ieee80211_mgmt *bcn; const u8 *ie; bool tim_found = 0; + unsigned int rate; + u16 ctl; + int antenna; bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); + rate = dev->wl->beacon_txctl.tx_rate->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); + /* Write the PHY TX control parameters. */ + antenna = b43_antenna_from_ieee80211(dev, + dev->wl->beacon_txctl.antenna_sel_tx); + antenna = b43_antenna_to_phyctl(antenna); + ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); + /* We can't send beacons with short preamble. Would get PHY errors. */ + ctl &= ~B43_TXH_PHY_SHORTPRMBL; + ctl &= ~B43_TXH_PHY_ANT; + ctl &= ~B43_TXH_PHY_ENC; + ctl |= antenna; + if (b43_is_cck_rate(rate)) + ctl |= B43_TXH_PHY_ENC_CCK; + else + ctl |= B43_TXH_PHY_ENC_OFDM; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl); + /* Find the position of the TIM and the DTIM_period value * and write them to SHM. */ ie = bcn->u.beacon.variable; @@ -1218,21 +1422,23 @@ static void b43_write_beacon_template(struct b43_wldev *dev, b43warn(dev->wl, "Did not find a valid TIM IE in " "the beacon template packet. AP or IBSS operation " "may be broken.\n"); - } + } else + b43dbg(dev->wl, "Updated beacon template\n"); } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, - u16 shm_offset, u16 size, u8 rate) + u16 shm_offset, u16 size, + struct ieee80211_rate *rate) { struct b43_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; - b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, size, - B43_RATE_TO_BASE100KBPS(rate)); + rate); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); @@ -1247,7 +1453,8 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev, * 3) Stripping TIM */ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, - u16 *dest_size, u8 rate) + u16 *dest_size, + struct ieee80211_rate *rate) { const u8 *src_data; u8 *dest_data; @@ -1292,7 +1499,7 @@ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, *dest_size, - B43_RATE_TO_BASE100KBPS(rate)); + rate); hdr->duration_id = dur; return dest_data; @@ -1300,7 +1507,8 @@ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, static void b43_write_probe_resp_template(struct b43_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset, + struct ieee80211_rate *rate) { const u8 *probe_resp_data; u16 size; @@ -1313,20 +1521,89 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ - b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB); - b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB); - b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB); - b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB); + b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); + b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); + b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); + b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, - size, ram_offset, shm_size_offset, rate); + size, ram_offset, shm_size_offset, + rate->hw_value); kfree(probe_resp_data); } +static void handle_irq_beacon(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + u32 cmd, beacon0_valid, beacon1_valid; + + if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + return; + + /* This is the bottom half of the asynchronous beacon update. */ + + /* Ignore interrupt in the future. */ + dev->irq_savedstate &= ~B43_IRQ_BEACON; + + cmd = b43_read32(dev, B43_MMIO_MACCMD); + beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID); + beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID); + + /* Schedule interrupt manually, if busy. */ + if (beacon0_valid && beacon1_valid) { + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); + dev->irq_savedstate |= B43_IRQ_BEACON; + return; + } + + if (!beacon0_valid) { + if (!wl->beacon0_uploaded) { + b43_write_beacon_template(dev, 0x68, 0x18); + b43_write_probe_resp_template(dev, 0x268, 0x4A, + &__b43_ratetable[3]); + wl->beacon0_uploaded = 1; + } + cmd = b43_read32(dev, B43_MMIO_MACCMD); + cmd |= B43_MACCMD_BEACON0_VALID; + b43_write32(dev, B43_MMIO_MACCMD, cmd); + } else if (!beacon1_valid) { + if (!wl->beacon1_uploaded) { + b43_write_beacon_template(dev, 0x468, 0x1A); + wl->beacon1_uploaded = 1; + } + cmd = b43_read32(dev, B43_MMIO_MACCMD); + cmd |= B43_MACCMD_BEACON1_VALID; + b43_write32(dev, B43_MMIO_MACCMD, cmd); + } +} + +static void b43_beacon_update_trigger_work(struct work_struct *work) +{ + struct b43_wl *wl = container_of(work, struct b43_wl, + beacon_update_trigger); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { + spin_lock_irq(&wl->irq_lock); + /* update beacon right away or defer to irq */ + dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + handle_irq_beacon(dev); + /* The handler might have updated the IRQ mask. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, + dev->irq_savedstate); + mmiowb(); + spin_unlock_irq(&wl->irq_lock); + } + mutex_unlock(&wl->mutex); +} + /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ -static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) +static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, + const struct ieee80211_tx_control *txctl) { /* This is the top half of the ansynchronous beacon update. * The bottom half is the beacon IRQ. @@ -1337,8 +1614,10 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; + memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl)); wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; + queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); } static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) @@ -1364,44 +1643,14 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) { b43_time_lock(dev); if (dev->dev->id.revision >= 3) { - b43_write32(dev, 0x188, (beacon_int << 16)); + b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16)); + b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10)); } else { b43_write16(dev, 0x606, (beacon_int >> 6)); b43_write16(dev, 0x610, beacon_int); } b43_time_unlock(dev); -} - -static void handle_irq_beacon(struct b43_wldev *dev) -{ - struct b43_wl *wl = dev->wl; - u32 cmd; - - if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) - return; - - /* This is the bottom half of the asynchronous beacon update. */ - - cmd = b43_read32(dev, B43_MMIO_MACCMD); - if (!(cmd & B43_MACCMD_BEACON0_VALID)) { - if (!wl->beacon0_uploaded) { - b43_write_beacon_template(dev, 0x68, 0x18, - B43_CCK_RATE_1MB); - b43_write_probe_resp_template(dev, 0x268, 0x4A, - B43_CCK_RATE_11MB); - wl->beacon0_uploaded = 1; - } - cmd |= B43_MACCMD_BEACON0_VALID; - } - if (!(cmd & B43_MACCMD_BEACON1_VALID)) { - if (!wl->beacon1_uploaded) { - b43_write_beacon_template(dev, 0x468, 0x1A, - B43_CCK_RATE_1MB); - wl->beacon1_uploaded = 1; - } - cmd |= B43_MACCMD_BEACON1_VALID; - } - b43_write32(dev, B43_MMIO_MACCMD, cmd); + b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } static void handle_irq_ucode_debug(struct b43_wldev *dev) @@ -1483,12 +1732,15 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ - if (dma_reason[0] & B43_DMAIRQ_RX_DONE) - b43_dma_rx(dev->dma.rx_ring0); - if (dma_reason[3] & B43_DMAIRQ_RX_DONE) - b43_dma_rx(dev->dma.rx_ring3); + if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { + if (b43_using_pio_transfers(dev)) + b43_pio_rx(dev->pio.rx_queue); + else + b43_dma_rx(dev->dma.rx_ring); + } B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); + B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); @@ -2045,7 +2297,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/EnableMac */ -void b43_mac_enable(struct b43_wldev *dev) +static void b43_mac_enable(struct b43_wldev *dev) { dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); @@ -2068,7 +2320,7 @@ void b43_mac_enable(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/SuspendMAC */ -void b43_mac_suspend(struct b43_wldev *dev) +static void b43_mac_suspend(struct b43_wldev *dev) { int i; u32 tmp; @@ -2196,38 +2448,28 @@ static void b43_rate_memory_init(struct b43_wldev *dev) } } +/* Set the default values for the PHY TX Control Words. */ +static void b43_set_phytxctl_defaults(struct b43_wldev *dev) +{ + u16 ctl = 0; + + ctl |= B43_TXH_PHY_ENC_CCK; + ctl |= B43_TXH_PHY_ANT01AUTO; + ctl |= B43_TXH_PHY_TXPWR; + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl); +} + /* Set the TX-Antenna for management frames sent by firmware. */ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) { - u16 ant = 0; + u16 ant; u16 tmp; - switch (antenna) { - case B43_ANTENNA0: - ant |= B43_TXH_PHY_ANT0; - break; - case B43_ANTENNA1: - ant |= B43_TXH_PHY_ANT1; - break; - case B43_ANTENNA2: - ant |= B43_TXH_PHY_ANT2; - break; - case B43_ANTENNA3: - ant |= B43_TXH_PHY_ANT3; - break; - case B43_ANTENNA_AUTO: - ant |= B43_TXH_PHY_ANT01AUTO; - break; - default: - B43_WARN_ON(1); - } - - /* FIXME We also need to set the other flags of the PHY control field somewhere. */ + ant = b43_antenna_to_phyctl(antenna); - /* For Beacons */ - tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); - tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); /* For ACK/CTS */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; @@ -2589,22 +2831,199 @@ static int b43_op_tx(struct ieee80211_hw *hw, struct b43_wldev *dev = wl->current_dev; int err = -ENODEV; + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ + return -EINVAL; + } + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + if (unlikely(!dev)) goto out; if (unlikely(b43_status(dev) < B43_STAT_STARTED)) goto out; - /* DMA-TX is done without a global lock. */ - err = b43_dma_tx(dev, skb, ctl); + /* TX is done without a global lock. */ + if (b43_using_pio_transfers(dev)) + err = b43_pio_tx(dev, skb, ctl); + else + err = b43_dma_tx(dev, skb, ctl); out: if (unlikely(err)) return NETDEV_TX_BUSY; return NETDEV_TX_OK; } +/* Locking: wl->irq_lock */ +static void b43_qos_params_upload(struct b43_wldev *dev, + const struct ieee80211_tx_queue_params *p, + u16 shm_offset) +{ + u16 params[B43_NR_QOSPARAMS]; + int cw_min, cw_max, aifs, bslots, tmp; + unsigned int i; + + const u16 aCWmin = 0x0001; + const u16 aCWmax = 0x03FF; + + /* Calculate the default values for the parameters, if needed. */ + switch (shm_offset) { + case B43_QOS_VOICE: + aifs = (p->aifs == -1) ? 2 : p->aifs; + cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min; + cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max; + break; + case B43_QOS_VIDEO: + aifs = (p->aifs == -1) ? 2 : p->aifs; + cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min; + cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max; + break; + case B43_QOS_BESTEFFORT: + aifs = (p->aifs == -1) ? 3 : p->aifs; + cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; + cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; + break; + case B43_QOS_BACKGROUND: + aifs = (p->aifs == -1) ? 7 : p->aifs; + cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; + cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; + break; + default: + B43_WARN_ON(1); + return; + } + if (cw_min <= 0) + cw_min = aCWmin; + if (cw_max <= 0) + cw_max = aCWmin; + bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min; + + memset(¶ms, 0, sizeof(params)); + + params[B43_QOSPARAM_TXOP] = p->txop * 32; + params[B43_QOSPARAM_CWMIN] = cw_min; + params[B43_QOSPARAM_CWMAX] = cw_max; + params[B43_QOSPARAM_CWCUR] = cw_min; + params[B43_QOSPARAM_AIFS] = aifs; + params[B43_QOSPARAM_BSLOTS] = bslots; + params[B43_QOSPARAM_REGGAP] = bslots + aifs; + + for (i = 0; i < ARRAY_SIZE(params); i++) { + if (i == B43_QOSPARAM_STATUS) { + tmp = b43_shm_read16(dev, B43_SHM_SHARED, + shm_offset + (i * 2)); + /* Mark the parameters as updated. */ + tmp |= 0x100; + b43_shm_write16(dev, B43_SHM_SHARED, + shm_offset + (i * 2), + tmp); + } else { + b43_shm_write16(dev, B43_SHM_SHARED, + shm_offset + (i * 2), + params[i]); + } + } +} + +/* Update the QOS parameters in hardware. */ +static void b43_qos_update(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct b43_qos_params *params; + unsigned long flags; + unsigned int i; + + /* Mapping of mac80211 queues to b43 SHM offsets. */ + static const u16 qos_shm_offsets[] = { + [0] = B43_QOS_VOICE, + [1] = B43_QOS_VIDEO, + [2] = B43_QOS_BESTEFFORT, + [3] = B43_QOS_BACKGROUND, + }; + BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); + + b43_mac_suspend(dev); + spin_lock_irqsave(&wl->irq_lock, flags); + + for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { + params = &(wl->qos_params[i]); + if (params->need_hw_update) { + b43_qos_params_upload(dev, &(params->p), + qos_shm_offsets[i]); + params->need_hw_update = 0; + } + } + + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_mac_enable(dev); +} + +static void b43_qos_clear(struct b43_wl *wl) +{ + struct b43_qos_params *params; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { + params = &(wl->qos_params[i]); + + memset(&(params->p), 0, sizeof(params->p)); + params->p.aifs = -1; + params->need_hw_update = 1; + } +} + +/* Initialize the core's QOS capabilities */ +static void b43_qos_init(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + unsigned int i; + + /* Upload the current QOS parameters. */ + for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) + wl->qos_params[i].need_hw_update = 1; + b43_qos_update(dev); + + /* Enable QOS support. */ + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); + b43_write16(dev, B43_MMIO_IFSCTL, + b43_read16(dev, B43_MMIO_IFSCTL) + | B43_MMIO_IFSCTL_USE_EDCF); +} + +static void b43_qos_update_work(struct work_struct *work) +{ + struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) + b43_qos_update(dev); + mutex_unlock(&wl->mutex); +} + static int b43_op_conf_tx(struct ieee80211_hw *hw, - int queue, + int _queue, const struct ieee80211_tx_queue_params *params) { + struct b43_wl *wl = hw_to_b43_wl(hw); + unsigned long flags; + unsigned int queue = (unsigned int)_queue; + struct b43_qos_params *p; + + if (queue >= ARRAY_SIZE(wl->qos_params)) { + /* Queue not available or don't support setting + * params on this queue. Return success to not + * confuse mac80211. */ + return 0; + } + + spin_lock_irqsave(&wl->irq_lock, flags); + p = &(wl->qos_params[queue]); + memcpy(&(p->p), params, sizeof(p->p)); + p->need_hw_update = 1; + spin_unlock_irqrestore(&wl->irq_lock, flags); + + queue_work(hw->workqueue, &wl->qos_update_work); + return 0; } @@ -2620,7 +3039,10 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw, goto out; spin_lock_irqsave(&wl->irq_lock, flags); if (likely(b43_status(dev) >= B43_STAT_STARTED)) { - b43_dma_get_tx_stats(dev, stats); + if (b43_using_pio_transfers(dev)) + b43_pio_get_tx_stats(dev, stats); + else + b43_dma_get_tx_stats(dev, stats); err = 0; } spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -2641,45 +3063,6 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, return 0; } -static const char *phymode_to_string(unsigned int phymode) -{ - switch (phymode) { - case B43_PHYMODE_A: - return "A"; - case B43_PHYMODE_B: - return "B"; - case B43_PHYMODE_G: - return "G"; - default: - B43_WARN_ON(1); - } - return ""; -} - -static int find_wldev_for_phymode(struct b43_wl *wl, - unsigned int phymode, - struct b43_wldev **dev, bool * gmode) -{ - struct b43_wldev *d; - - list_for_each_entry(d, &wl->devlist, list) { - if (d->phy.possible_phymodes & phymode) { - /* Ok, this device supports the PHY-mode. - * Now figure out how the gmode bit has to be - * set to support it. */ - if (phymode == B43_PHYMODE_A) - *gmode = 0; - else - *gmode = 1; - *dev = d; - - return 0; - } - } - - return -ESRCH; -} - static void b43_put_phy_into_reset(struct b43_wldev *dev) { struct ssb_device *sdev = dev->dev; @@ -2699,28 +3082,64 @@ static void b43_put_phy_into_reset(struct b43_wldev *dev) msleep(1); } +static const char * band_to_string(enum ieee80211_band band) +{ + switch (band) { + case IEEE80211_BAND_5GHZ: + return "5"; + case IEEE80211_BAND_2GHZ: + return "2.4"; + default: + break; + } + B43_WARN_ON(1); + return ""; +} + /* Expects wl->mutex locked */ -static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) +static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) { - struct b43_wldev *up_dev; + struct b43_wldev *up_dev = NULL; struct b43_wldev *down_dev; + struct b43_wldev *d; int err; - bool gmode = 0; + bool gmode; int prev_status; - err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); - if (err) { - b43err(wl, "Could not find a device for %s-PHY mode\n", - phymode_to_string(new_mode)); - return err; + /* Find a device and PHY which supports the band. */ + list_for_each_entry(d, &wl->devlist, list) { + switch (chan->band) { + case IEEE80211_BAND_5GHZ: + if (d->phy.supports_5ghz) { + up_dev = d; + gmode = 0; + } + break; + case IEEE80211_BAND_2GHZ: + if (d->phy.supports_2ghz) { + up_dev = d; + gmode = 1; + } + break; + default: + B43_WARN_ON(1); + return -EINVAL; + } + if (up_dev) + break; + } + if (!up_dev) { + b43err(wl, "Could not find a device for %s-GHz band operation\n", + band_to_string(chan->band)); + return -ENODEV; } if ((up_dev == wl->current_dev) && (!!wl->current_dev->phy.gmode == !!gmode)) { /* This device is already running. */ return 0; } - b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n", - phymode_to_string(new_mode)); + b43dbg(wl, "Switching to %s-GHz band\n", + band_to_string(chan->band)); down_dev = wl->current_dev; prev_status = b43_status(down_dev); @@ -2742,8 +3161,8 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) err = b43_wireless_core_init(up_dev); if (err) { b43err(wl, "Fatal: Could not initialize device for " - "newly selected %s-PHY mode\n", - phymode_to_string(new_mode)); + "selected %s-GHz band\n", + band_to_string(chan->band)); goto init_failure; } } @@ -2751,8 +3170,8 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) err = b43_wireless_core_start(up_dev); if (err) { b43err(wl, "Fatal: Coult not start device for " - "newly selected %s-PHY mode\n", - phymode_to_string(new_mode)); + "selected %s-GHz band\n", + band_to_string(chan->band)); b43_wireless_core_exit(up_dev); goto init_failure; } @@ -2762,86 +3181,26 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) wl->current_dev = up_dev; return 0; - init_failure: +init_failure: /* Whoops, failed to init the new core. No core is operating now. */ wl->current_dev = NULL; return err; } -/* Check if the use of the antenna that ieee80211 told us to - * use is possible. This will fall back to DEFAULT. - * "antenna_nr" is the antenna identifier we got from ieee80211. */ -u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, - u8 antenna_nr) -{ - u8 antenna_mask; - - if (antenna_nr == 0) { - /* Zero means "use default antenna". That's always OK. */ - return 0; - } - - /* Get the mask of available antennas. */ - if (dev->phy.gmode) - antenna_mask = dev->dev->bus->sprom.ant_available_bg; - else - antenna_mask = dev->dev->bus->sprom.ant_available_a; - - if (!(antenna_mask & (1 << (antenna_nr - 1)))) { - /* This antenna is not available. Fall back to default. */ - return 0; - } - - return antenna_nr; -} - -static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) -{ - antenna = b43_ieee80211_antenna_sanitize(dev, antenna); - switch (antenna) { - case 0: /* default/diversity */ - return B43_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43_ANTENNA0; - case 2: /* Antenna 1 */ - return B43_ANTENNA1; - case 3: /* Antenna 2 */ - return B43_ANTENNA2; - case 4: /* Antenna 3 */ - return B43_ANTENNA3; - default: - return B43_ANTENNA_DEFAULT; - } -} - static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; unsigned long flags; - unsigned int new_phymode = 0xFFFF; int antenna; int err = 0; u32 savedirqs; mutex_lock(&wl->mutex); - /* Switch the PHY mode (if necessary). */ - switch (conf->phymode) { - case MODE_IEEE80211A: - new_phymode = B43_PHYMODE_A; - break; - case MODE_IEEE80211B: - new_phymode = B43_PHYMODE_B; - break; - case MODE_IEEE80211G: - new_phymode = B43_PHYMODE_G; - break; - default: - B43_WARN_ON(1); - } - err = b43_switch_phymode(wl, new_phymode); + /* Switch the band (if necessary). This might change the active core. */ + err = b43_switch_band(wl, conf->channel); if (err) goto out_unlock_mutex; dev = wl->current_dev; @@ -2861,8 +3220,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ - if (conf->channel_val != phy->channel) - b43_radio_selectchannel(dev, conf->channel_val, 0); + if (conf->channel->hw_value != phy->channel) + b43_radio_selectchannel(dev, conf->channel->hw_value, 0); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != @@ -3075,8 +3434,10 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) - b43_update_templates(wl, conf->beacon); + if (conf->beacon) { + b43_update_templates(wl, conf->beacon, + conf->beacon_control); + } } b43_write_mac_bssid_templates(dev); } @@ -3106,6 +3467,7 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) b43_set_status(dev, B43_STAT_INITIALIZED); + b43_pio_stop(dev); mutex_unlock(&wl->mutex); /* Must unlock as it would otherwise deadlock. No races here. * Cancel the possibly running self-rearming periodic work. */ @@ -3400,6 +3762,41 @@ static void b43_set_retry_limits(struct b43_wldev *dev, long_retry); } +static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) +{ + u16 pu_delay; + + /* The time value is in microseconds. */ + if (dev->phy.type == B43_PHYTYPE_A) + pu_delay = 3700; + else + pu_delay = 1050; + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle) + pu_delay = 500; + if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) + pu_delay = max(pu_delay, (u16)2400); + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay); +} + +/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */ +static void b43_set_pretbtt(struct b43_wldev *dev) +{ + u16 pretbtt; + + /* The time value is in microseconds. */ + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) { + pretbtt = 2; + } else { + if (dev->phy.type == B43_PHYTYPE_A) + pretbtt = 120; + else + pretbtt = 250; + } + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt); + b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt); +} + /* Shutdown a wireless core */ /* Locking: wl->mutex */ static void b43_wireless_core_exit(struct b43_wldev *dev) @@ -3423,6 +3820,7 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) b43_rng_exit(dev->wl, false); } b43_dma_free(dev); + b43_pio_free(dev); b43_chip_exit(dev); b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); @@ -3510,6 +3908,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1); b43_rate_memory_init(dev); + b43_set_phytxctl_defaults(dev); /* Minimum Contention Window */ if (phy->type == B43_PHYTYPE_B) { @@ -3520,18 +3919,17 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); - err = b43_dma_init(dev); + if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) { + dev->__using_pio_transfers = 1; + err = b43_pio_init(dev); + } else { + dev->__using_pio_transfers = 0; + err = b43_dma_init(dev); + } if (err) goto err_chip_exit; b43_qos_init(dev); - -//FIXME -#if 1 - b43_write16(dev, 0x0612, 0x0050); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4); -#endif - + b43_set_synth_pu_delay(dev, 1); b43_bluetooth_coext_enable(dev); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ @@ -3591,6 +3989,8 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); + b43_set_pretbtt(dev); + b43_set_synth_pu_delay(dev, 0); b43_upload_card_macaddress(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -3642,6 +4042,7 @@ static int b43_op_start(struct ieee80211_hw *hw) memset(wl->mac_addr, 0, ETH_ALEN); wl->filter_flags = 0; wl->radiotap_enabled = 0; + b43_qos_clear(wl); /* First register RFkill. * LEDs that are registered later depend on it. */ @@ -3683,6 +4084,8 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; b43_rfkill_exit(dev); + cancel_work_sync(&(wl->qos_update_work)); + cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); if (b43_status(dev) >= B43_STAT_STARTED) @@ -3716,16 +4119,17 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) struct b43_wl *wl = hw_to_b43_wl(hw); struct sk_buff *beacon; unsigned long flags; + struct ieee80211_tx_control txctl; /* We could modify the existing beacon and set the aid bit in * the TIM field, but that would probably require resizing and * moving of data within the beacon template. * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, NULL); + beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); if (unlikely(!beacon)) return -ENOMEM; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon); + b43_update_templates(wl, beacon, &txctl); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; @@ -3739,12 +4143,22 @@ static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, unsigned long flags; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon); + b43_update_templates(wl, beacon, ctl); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; } +static void b43_op_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + const u8 *addr) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + + B43_WARN_ON(!vif || wl->vif != vif); +} + static const struct ieee80211_ops b43_hw_ops = { .tx = b43_op_tx, .conf_tx = b43_op_conf_tx, @@ -3761,6 +4175,7 @@ static const struct ieee80211_ops b43_hw_ops = { .set_retry_limit = b43_op_set_retry_limit, .set_tim = b43_op_beacon_set_tim, .beacon_update = b43_op_ibss_beacon_update, + .sta_notify = b43_op_sta_notify, }; /* Hard-reset the chip. Do not call this directly. @@ -3804,31 +4219,23 @@ static void b43_chip_reset(struct work_struct *work) b43info(wl, "Controller restarted\n"); } -static int b43_setup_modes(struct b43_wldev *dev, +static int b43_setup_bands(struct b43_wldev *dev, bool have_2ghz_phy, bool have_5ghz_phy) { struct ieee80211_hw *hw = dev->wl->hw; - struct ieee80211_hw_mode *mode; - struct b43_phy *phy = &dev->phy; - int err; - /* XXX: This function will go away soon, when mac80211 - * band stuff is rewritten. So this is just a hack. - * For now we always claim GPHY mode, as there is no - * support for NPHY and APHY in the device, yet. - * This assumption is OK, as any B, N or A PHY will already - * have died a horrible sanity check death earlier. */ - - mode = &phy->hwmodes[0]; - mode->mode = MODE_IEEE80211G; - mode->num_channels = b43_2ghz_chantable_size; - mode->channels = b43_2ghz_chantable; - mode->num_rates = b43_g_ratetable_size; - mode->rates = b43_g_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - phy->possible_phymodes |= B43_PHYMODE_G; + if (have_2ghz_phy) + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz; + if (dev->phy.type == B43_PHYTYPE_N) { + if (have_5ghz_phy) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy; + } else { + if (have_5ghz_phy) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy; + } + + dev->phy.supports_2ghz = have_2ghz_phy; + dev->phy.supports_5ghz = have_5ghz_phy; return 0; } @@ -3910,7 +4317,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) err = b43_validate_chipaccess(dev); if (err) goto err_powerdown; - err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy); + err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy); if (err) goto err_powerdown; @@ -4040,7 +4447,7 @@ static int b43_wireless_init(struct ssb_device *dev) hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; - hw->queues = 1; /* FIXME: hardware has more queues */ + hw->queues = b43_modparam_qos ? 4 : 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); @@ -4056,6 +4463,8 @@ static int b43_wireless_init(struct ssb_device *dev) spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); + INIT_WORK(&wl->qos_update_work, b43_qos_update_work); + INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 2d52d9de930..5230aeca78b 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -38,6 +38,10 @@ /* Magic helper macro to pad structures. Ignore those above. It's magic. */ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) + +extern int b43_modparam_qos; + + /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline u8 b43_freq_to_channel_5ghz(int freq) { @@ -95,16 +99,13 @@ u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); -u32 b43_hf_read(struct b43_wldev *dev); -void b43_hf_write(struct b43_wldev *dev, u32 value); +u64 b43_hf_read(struct b43_wldev *dev); +void b43_hf_write(struct b43_wldev *dev, u64 value); void b43_dummy_transmission(struct b43_wldev *dev); void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); -void b43_mac_suspend(struct b43_wldev *dev); -void b43_mac_enable(struct b43_wldev *dev); - void b43_controller_restart(struct b43_wldev *dev, const char *reason); #define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */ diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 705131ef4bf..8695eb22347 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -240,7 +240,6 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) b43_phy_set(dev, B43_NPHY_IQFLIP, B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); - //FIXME the following condition is different in the specs. if (1 /* FIXME band is 2.4GHz */) { b43_phy_set(dev, B43_NPHY_CLASSCTL, B43_NPHY_CLASSCTL_CCKEN); diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h index 5d95118b819..faf46b9cbf1 100644 --- a/drivers/net/wireless/b43/nphy.h +++ b/drivers/net/wireless/b43/nphy.h @@ -919,6 +919,10 @@ struct b43_wldev; + +#ifdef CONFIG_B43_NPHY +/* N-PHY support enabled */ + int b43_phy_initn(struct b43_wldev *dev); void b43_nphy_radio_turn_on(struct b43_wldev *dev); @@ -929,4 +933,40 @@ int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel); void b43_nphy_xmitpower(struct b43_wldev *dev); void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); + +#else /* CONFIG_B43_NPHY */ +/* N-PHY support disabled */ + + +static inline +int b43_phy_initn(struct b43_wldev *dev) +{ + return -EOPNOTSUPP; +} + +static inline +void b43_nphy_radio_turn_on(struct b43_wldev *dev) +{ +} +static inline +void b43_nphy_radio_turn_off(struct b43_wldev *dev) +{ +} + +static inline +int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +{ + return -ENOSYS; +} + +static inline +void b43_nphy_xmitpower(struct b43_wldev *dev) +{ +} +static inline +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) +{ +} + +#endif /* CONFIG_B43_NPHY */ #endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 371e4a11951..b8aa16307f7 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); #ifdef CONFIG_PM static int b43_pcmcia_suspend(struct pcmcia_device *dev) { - //TODO - return 0; + struct ssb_bus *ssb = dev->priv; + + return ssb_bus_suspend(ssb); } static int b43_pcmcia_resume(struct pcmcia_device *dev) { - //TODO - return 0; + struct ssb_bus *ssb = dev->priv; + + return ssb_bus_resume(ssb); } #else /* CONFIG_PM */ # define b43_pcmcia_suspend NULL diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c new file mode 100644 index 00000000000..fcacafb0434 --- /dev/null +++ b/drivers/net/wireless/b43/pio.c @@ -0,0 +1,842 @@ +/* + + Broadcom B43 wireless driver + + PIO data transfer + + Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "pio.h" +#include "dma.h" +#include "main.h" +#include "xmit.h" + +#include <linux/delay.h> + + +static void b43_pio_rx_work(struct work_struct *work); + + +static u16 generate_cookie(struct b43_pio_txqueue *q, + struct b43_pio_txpacket *pack) +{ + u16 cookie; + + /* Use the upper 4 bits of the cookie as + * PIO controller ID and store the packet index number + * in the lower 12 bits. + * Note that the cookie must never be 0, as this + * is a special value used in RX path. + * It can also not be 0xFFFF because that is special + * for multicast frames. + */ + cookie = (((u16)q->index + 1) << 12); + cookie |= pack->index; + + return cookie; +} + +static +struct b43_pio_txqueue * parse_cookie(struct b43_wldev *dev, + u16 cookie, + struct b43_pio_txpacket **pack) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pio_txqueue *q = NULL; + unsigned int pack_index; + + switch (cookie & 0xF000) { + case 0x1000: + q = pio->tx_queue_AC_BK; + break; + case 0x2000: + q = pio->tx_queue_AC_BE; + break; + case 0x3000: + q = pio->tx_queue_AC_VI; + break; + case 0x4000: + q = pio->tx_queue_AC_VO; + break; + case 0x5000: + q = pio->tx_queue_mcast; + break; + } + if (B43_WARN_ON(!q)) + return NULL; + pack_index = (cookie & 0x0FFF); + if (B43_WARN_ON(pack_index >= ARRAY_SIZE(q->packets))) + return NULL; + *pack = &q->packets[pack_index]; + + return q; +} + +static u16 index_to_pioqueue_base(struct b43_wldev *dev, + unsigned int index) +{ + static const u16 bases[] = { + B43_MMIO_PIO_BASE0, + B43_MMIO_PIO_BASE1, + B43_MMIO_PIO_BASE2, + B43_MMIO_PIO_BASE3, + B43_MMIO_PIO_BASE4, + B43_MMIO_PIO_BASE5, + B43_MMIO_PIO_BASE6, + B43_MMIO_PIO_BASE7, + }; + static const u16 bases_rev11[] = { + B43_MMIO_PIO11_BASE0, + B43_MMIO_PIO11_BASE1, + B43_MMIO_PIO11_BASE2, + B43_MMIO_PIO11_BASE3, + B43_MMIO_PIO11_BASE4, + B43_MMIO_PIO11_BASE5, + }; + + if (dev->dev->id.revision >= 11) { + B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11)); + return bases_rev11[index]; + } + B43_WARN_ON(index >= ARRAY_SIZE(bases)); + return bases[index]; +} + +static u16 pio_txqueue_offset(struct b43_wldev *dev) +{ + if (dev->dev->id.revision >= 11) + return 0x18; + return 0; +} + +static u16 pio_rxqueue_offset(struct b43_wldev *dev) +{ + if (dev->dev->id.revision >= 11) + return 0x38; + return 8; +} + +static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev, + unsigned int index) +{ + struct b43_pio_txqueue *q; + struct b43_pio_txpacket *p; + unsigned int i; + + q = kzalloc(sizeof(*q), GFP_KERNEL); + if (!q) + return NULL; + spin_lock_init(&q->lock); + q->dev = dev; + q->rev = dev->dev->id.revision; + q->mmio_base = index_to_pioqueue_base(dev, index) + + pio_txqueue_offset(dev); + q->index = index; + + q->free_packet_slots = B43_PIO_MAX_NR_TXPACKETS; + if (q->rev >= 8) { + q->buffer_size = 1920; //FIXME this constant is wrong. + } else { + q->buffer_size = b43_piotx_read16(q, B43_PIO_TXQBUFSIZE); + q->buffer_size -= 80; + } + + INIT_LIST_HEAD(&q->packets_list); + for (i = 0; i < ARRAY_SIZE(q->packets); i++) { + p = &(q->packets[i]); + INIT_LIST_HEAD(&p->list); + p->index = i; + p->queue = q; + list_add(&p->list, &q->packets_list); + } + + return q; +} + +static struct b43_pio_rxqueue * b43_setup_pioqueue_rx(struct b43_wldev *dev, + unsigned int index) +{ + struct b43_pio_rxqueue *q; + + q = kzalloc(sizeof(*q), GFP_KERNEL); + if (!q) + return NULL; + spin_lock_init(&q->lock); + q->dev = dev; + q->rev = dev->dev->id.revision; + q->mmio_base = index_to_pioqueue_base(dev, index) + + pio_rxqueue_offset(dev); + INIT_WORK(&q->rx_work, b43_pio_rx_work); + + /* Enable Direct FIFO RX (PIO) on the engine. */ + b43_dma_direct_fifo_rx(dev, index, 1); + + return q; +} + +static void b43_pio_cancel_tx_packets(struct b43_pio_txqueue *q) +{ + struct b43_pio_txpacket *pack; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(q->packets); i++) { + pack = &(q->packets[i]); + if (pack->skb) { + dev_kfree_skb_any(pack->skb); + pack->skb = NULL; + } + } +} + +static void b43_destroy_pioqueue_tx(struct b43_pio_txqueue *q, + const char *name) +{ + if (!q) + return; + b43_pio_cancel_tx_packets(q); + kfree(q); +} + +static void b43_destroy_pioqueue_rx(struct b43_pio_rxqueue *q, + const char *name) +{ + if (!q) + return; + kfree(q); +} + +#define destroy_queue_tx(pio, queue) do { \ + b43_destroy_pioqueue_tx((pio)->queue, __stringify(queue)); \ + (pio)->queue = NULL; \ + } while (0) + +#define destroy_queue_rx(pio, queue) do { \ + b43_destroy_pioqueue_rx((pio)->queue, __stringify(queue)); \ + (pio)->queue = NULL; \ + } while (0) + +void b43_pio_free(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + if (!b43_using_pio_transfers(dev)) + return; + pio = &dev->pio; + + destroy_queue_rx(pio, rx_queue); + destroy_queue_tx(pio, tx_queue_mcast); + destroy_queue_tx(pio, tx_queue_AC_VO); + destroy_queue_tx(pio, tx_queue_AC_VI); + destroy_queue_tx(pio, tx_queue_AC_BE); + destroy_queue_tx(pio, tx_queue_AC_BK); +} + +void b43_pio_stop(struct b43_wldev *dev) +{ + if (!b43_using_pio_transfers(dev)) + return; + cancel_work_sync(&dev->pio.rx_queue->rx_work); +} + +int b43_pio_init(struct b43_wldev *dev) +{ + struct b43_pio *pio = &dev->pio; + int err = -ENOMEM; + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_BE); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RXPADOFF, 0); + + pio->tx_queue_AC_BK = b43_setup_pioqueue_tx(dev, 0); + if (!pio->tx_queue_AC_BK) + goto out; + + pio->tx_queue_AC_BE = b43_setup_pioqueue_tx(dev, 1); + if (!pio->tx_queue_AC_BE) + goto err_destroy_bk; + + pio->tx_queue_AC_VI = b43_setup_pioqueue_tx(dev, 2); + if (!pio->tx_queue_AC_VI) + goto err_destroy_be; + + pio->tx_queue_AC_VO = b43_setup_pioqueue_tx(dev, 3); + if (!pio->tx_queue_AC_VO) + goto err_destroy_vi; + + pio->tx_queue_mcast = b43_setup_pioqueue_tx(dev, 4); + if (!pio->tx_queue_mcast) + goto err_destroy_vo; + + pio->rx_queue = b43_setup_pioqueue_rx(dev, 0); + if (!pio->rx_queue) + goto err_destroy_mcast; + + b43dbg(dev->wl, "PIO initialized\n"); + err = 0; +out: + return err; + +err_destroy_mcast: + destroy_queue_tx(pio, tx_queue_mcast); +err_destroy_vo: + destroy_queue_tx(pio, tx_queue_AC_VO); +err_destroy_vi: + destroy_queue_tx(pio, tx_queue_AC_VI); +err_destroy_be: + destroy_queue_tx(pio, tx_queue_AC_BE); +err_destroy_bk: + destroy_queue_tx(pio, tx_queue_AC_BK); + return err; +} + +/* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */ +static struct b43_pio_txqueue * select_queue_by_priority(struct b43_wldev *dev, + u8 queue_prio) +{ + struct b43_pio_txqueue *q; + + if (b43_modparam_qos) { + /* 0 = highest priority */ + switch (queue_prio) { + default: + B43_WARN_ON(1); + /* fallthrough */ + case 0: + q = dev->pio.tx_queue_AC_VO; + break; + case 1: + q = dev->pio.tx_queue_AC_VI; + break; + case 2: + q = dev->pio.tx_queue_AC_BE; + break; + case 3: + q = dev->pio.tx_queue_AC_BK; + break; + } + } else + q = dev->pio.tx_queue_AC_BE; + + return q; +} + +static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q, + u16 ctl, + const void *_data, + unsigned int data_len) +{ + struct b43_wldev *dev = q->dev; + const u8 *data = _data; + + ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI; + b43_piotx_write16(q, B43_PIO_TXCTL, ctl); + + ssb_block_write(dev->dev, data, (data_len & ~1), + q->mmio_base + B43_PIO_TXDATA, + sizeof(u16)); + if (data_len & 1) { + /* Write the last byte. */ + ctl &= ~B43_PIO_TXCTL_WRITEHI; + b43_piotx_write16(q, B43_PIO_TXCTL, ctl); + b43_piotx_write16(q, B43_PIO_TXDATA, data[data_len - 1]); + } + + return ctl; +} + +static void pio_tx_frame_2byte_queue(struct b43_pio_txpacket *pack, + const u8 *hdr, unsigned int hdrlen) +{ + struct b43_pio_txqueue *q = pack->queue; + const char *frame = pack->skb->data; + unsigned int frame_len = pack->skb->len; + u16 ctl; + + ctl = b43_piotx_read16(q, B43_PIO_TXCTL); + ctl |= B43_PIO_TXCTL_FREADY; + ctl &= ~B43_PIO_TXCTL_EOF; + + /* Transfer the header data. */ + ctl = tx_write_2byte_queue(q, ctl, hdr, hdrlen); + /* Transfer the frame data. */ + ctl = tx_write_2byte_queue(q, ctl, frame, frame_len); + + ctl |= B43_PIO_TXCTL_EOF; + b43_piotx_write16(q, B43_PIO_TXCTL, ctl); +} + +static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q, + u32 ctl, + const void *_data, + unsigned int data_len) +{ + struct b43_wldev *dev = q->dev; + const u8 *data = _data; + + ctl |= B43_PIO8_TXCTL_0_7 | B43_PIO8_TXCTL_8_15 | + B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31; + b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); + + ssb_block_write(dev->dev, data, (data_len & ~3), + q->mmio_base + B43_PIO8_TXDATA, + sizeof(u32)); + if (data_len & 3) { + u32 value = 0; + + /* Write the last few bytes. */ + ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 | + B43_PIO8_TXCTL_24_31); + data = &(data[data_len - 1]); + switch (data_len & 3) { + case 3: + ctl |= B43_PIO8_TXCTL_16_23; + value |= (u32)(*data) << 16; + data--; + case 2: + ctl |= B43_PIO8_TXCTL_8_15; + value |= (u32)(*data) << 8; + data--; + case 1: + value |= (u32)(*data); + } + b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); + b43_piotx_write32(q, B43_PIO8_TXDATA, value); + } + + return ctl; +} + +static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack, + const u8 *hdr, unsigned int hdrlen) +{ + struct b43_pio_txqueue *q = pack->queue; + const char *frame = pack->skb->data; + unsigned int frame_len = pack->skb->len; + u32 ctl; + + ctl = b43_piotx_read32(q, B43_PIO8_TXCTL); + ctl |= B43_PIO8_TXCTL_FREADY; + ctl &= ~B43_PIO8_TXCTL_EOF; + + /* Transfer the header data. */ + ctl = tx_write_4byte_queue(q, ctl, hdr, hdrlen); + /* Transfer the frame data. */ + ctl = tx_write_4byte_queue(q, ctl, frame, frame_len); + + ctl |= B43_PIO8_TXCTL_EOF; + b43_piotx_write32(q, B43_PIO_TXCTL, ctl); +} + +static int pio_tx_frame(struct b43_pio_txqueue *q, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43_pio_txpacket *pack; + struct b43_txhdr txhdr; + u16 cookie; + int err; + unsigned int hdrlen; + + B43_WARN_ON(list_empty(&q->packets_list)); + pack = list_entry(q->packets_list.next, + struct b43_pio_txpacket, list); + memset(&pack->txstat, 0, sizeof(pack->txstat)); + memcpy(&pack->txstat.control, ctl, sizeof(*ctl)); + + cookie = generate_cookie(q, pack); + hdrlen = b43_txhdr_size(q->dev); + err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, + skb->len, ctl, cookie); + if (err) + return err; + + if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + /* Tell the firmware about the cookie of the last + * mcast frame, so it can clear the more-data bit in it. */ + b43_shm_write16(q->dev, B43_SHM_SHARED, + B43_SHM_SH_MCASTCOOKIE, cookie); + } + + pack->skb = skb; + if (q->rev >= 8) + pio_tx_frame_4byte_queue(pack, (const u8 *)&txhdr, hdrlen); + else + pio_tx_frame_2byte_queue(pack, (const u8 *)&txhdr, hdrlen); + + /* Remove it from the list of available packet slots. + * It will be put back when we receive the status report. */ + list_del(&pack->list); + + /* Update the queue statistics. */ + q->buffer_used += roundup(skb->len + hdrlen, 4); + q->free_packet_slots -= 1; + + return 0; +} + +int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_pio_txqueue *q; + struct ieee80211_hdr *hdr; + unsigned long flags; + unsigned int hdrlen, total_len; + int err = 0; + + hdr = (struct ieee80211_hdr *)skb->data; + if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + /* The multicast queue will be sent after the DTIM. */ + q = dev->pio.tx_queue_mcast; + /* Set the frame More-Data bit. Ucode will clear it + * for us on the last frame. */ + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } else { + /* Decide by priority where to put this frame. */ + q = select_queue_by_priority(dev, ctl->queue); + } + + spin_lock_irqsave(&q->lock, flags); + + hdrlen = b43_txhdr_size(dev); + total_len = roundup(skb->len + hdrlen, 4); + + if (unlikely(total_len > q->buffer_size)) { + err = -ENOBUFS; + b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); + goto out_unlock; + } + if (unlikely(q->free_packet_slots == 0)) { + err = -ENOBUFS; + b43warn(dev->wl, "PIO: TX packet overflow.\n"); + goto out_unlock; + } + B43_WARN_ON(q->buffer_used > q->buffer_size); + + if (total_len > (q->buffer_size - q->buffer_used)) { + /* Not enough memory on the queue. */ + err = -EBUSY; + ieee80211_stop_queue(dev->wl->hw, ctl->queue); + q->stopped = 1; + goto out_unlock; + } + + /* Assign the queue number to the ring (if not already done before) + * so TX status handling can use it. The mac80211-queue to b43-queue + * mapping is static, so we don't need to store it per frame. */ + q->queue_prio = ctl->queue; + + err = pio_tx_frame(q, skb, ctl); + if (unlikely(err == -ENOKEY)) { + /* Drop this packet, as we don't have the encryption key + * anymore and must not transmit it unencrypted. */ + dev_kfree_skb_any(skb); + err = 0; + goto out_unlock; + } + if (unlikely(err)) { + b43err(dev->wl, "PIO transmission failure\n"); + goto out_unlock; + } + q->nr_tx_packets++; + + B43_WARN_ON(q->buffer_used > q->buffer_size); + if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || + (q->free_packet_slots == 0)) { + /* The queue is full. */ + ieee80211_stop_queue(dev->wl->hw, ctl->queue); + q->stopped = 1; + } + +out_unlock: + spin_unlock_irqrestore(&q->lock, flags); + + return err; +} + +/* Called with IRQs disabled. */ +void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + struct b43_pio_txqueue *q; + struct b43_pio_txpacket *pack = NULL; + unsigned int total_len; + + q = parse_cookie(dev, status->cookie, &pack); + if (unlikely(!q)) + return; + B43_WARN_ON(!pack); + + spin_lock(&q->lock); /* IRQs are already disabled. */ + + b43_fill_txstatus_report(&(pack->txstat), status); + + total_len = pack->skb->len + b43_txhdr_size(dev); + total_len = roundup(total_len, 4); + q->buffer_used -= total_len; + q->free_packet_slots += 1; + + ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb, + &(pack->txstat)); + pack->skb = NULL; + list_add(&pack->list, &q->packets_list); + + if (q->stopped) { + ieee80211_wake_queue(dev->wl->hw, q->queue_prio); + q->stopped = 0; + } + + spin_unlock(&q->lock); +} + +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43_pio_txqueue *q; + struct ieee80211_tx_queue_stats_data *data; + unsigned long flags; + int i; + + for (i = 0; i < nr_queues; i++) { + data = &(stats->data[i]); + q = select_queue_by_priority(dev, i); + + spin_lock_irqsave(&q->lock, flags); + data->len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; + data->limit = B43_PIO_MAX_NR_TXPACKETS; + data->count = q->nr_tx_packets; + spin_unlock_irqrestore(&q->lock, flags); + } +} + +/* Returns whether we should fetch another frame. */ +static bool pio_rx_frame(struct b43_pio_rxqueue *q) +{ + struct b43_wldev *dev = q->dev; + struct b43_rxhdr_fw4 rxhdr; + u16 len; + u32 macstat; + unsigned int i, padding; + struct sk_buff *skb; + const char *err_msg = NULL; + + memset(&rxhdr, 0, sizeof(rxhdr)); + + /* Check if we have data and wait for it to get ready. */ + if (q->rev >= 8) { + u32 ctl; + + ctl = b43_piorx_read32(q, B43_PIO8_RXCTL); + if (!(ctl & B43_PIO8_RXCTL_FRAMERDY)) + return 0; + b43_piorx_write32(q, B43_PIO8_RXCTL, + B43_PIO8_RXCTL_FRAMERDY); + for (i = 0; i < 10; i++) { + ctl = b43_piorx_read32(q, B43_PIO8_RXCTL); + if (ctl & B43_PIO8_RXCTL_DATARDY) + goto data_ready; + udelay(10); + } + } else { + u16 ctl; + + ctl = b43_piorx_read16(q, B43_PIO_RXCTL); + if (!(ctl & B43_PIO_RXCTL_FRAMERDY)) + return 0; + b43_piorx_write16(q, B43_PIO_RXCTL, + B43_PIO_RXCTL_FRAMERDY); + for (i = 0; i < 10; i++) { + ctl = b43_piorx_read16(q, B43_PIO_RXCTL); + if (ctl & B43_PIO_RXCTL_DATARDY) + goto data_ready; + udelay(10); + } + } + b43dbg(q->dev->wl, "PIO RX timed out\n"); + return 1; +data_ready: + + /* Get the preamble (RX header) */ + if (q->rev >= 8) { + ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr), + q->mmio_base + B43_PIO8_RXDATA, + sizeof(u32)); + } else { + ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr), + q->mmio_base + B43_PIO_RXDATA, + sizeof(u16)); + } + /* Sanity checks. */ + len = le16_to_cpu(rxhdr.frame_len); + if (unlikely(len > 0x700)) { + err_msg = "len > 0x700"; + goto rx_error; + } + if (unlikely(len == 0)) { + err_msg = "len == 0"; + goto rx_error; + } + + macstat = le32_to_cpu(rxhdr.mac_status); + if (macstat & B43_RX_MAC_FCSERR) { + if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) { + /* Drop frames with failed FCS. */ + err_msg = "Frame FCS error"; + goto rx_error; + } + } + + /* We always pad 2 bytes, as that's what upstream code expects + * due to the RX-header being 30 bytes. In case the frame is + * unaligned, we pad another 2 bytes. */ + padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0; + skb = dev_alloc_skb(len + padding + 2); + if (unlikely(!skb)) { + err_msg = "Out of memory"; + goto rx_error; + } + skb_reserve(skb, 2); + skb_put(skb, len + padding); + if (q->rev >= 8) { + ssb_block_read(dev->dev, skb->data + padding, (len & ~3), + q->mmio_base + B43_PIO8_RXDATA, + sizeof(u32)); + if (len & 3) { + u32 value; + char *data; + + /* Read the last few bytes. */ + value = b43_piorx_read32(q, B43_PIO8_RXDATA); + data = &(skb->data[len + padding - 1]); + switch (len & 3) { + case 3: + *data = (value >> 16); + data--; + case 2: + *data = (value >> 8); + data--; + case 1: + *data = value; + } + } + } else { + ssb_block_read(dev->dev, skb->data + padding, (len & ~1), + q->mmio_base + B43_PIO_RXDATA, + sizeof(u16)); + if (len & 1) { + u16 value; + + /* Read the last byte. */ + value = b43_piorx_read16(q, B43_PIO_RXDATA); + skb->data[len + padding - 1] = value; + } + } + + b43_rx(q->dev, skb, &rxhdr); + + return 1; + +rx_error: + if (err_msg) + b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg); + b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); + return 1; +} + +/* RX workqueue. We can sleep, yay! */ +static void b43_pio_rx_work(struct work_struct *work) +{ + struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue, + rx_work); + unsigned int budget = 50; + bool stop; + + do { + spin_lock_irq(&q->lock); + stop = (pio_rx_frame(q) == 0); + spin_unlock_irq(&q->lock); + cond_resched(); + if (stop) + break; + } while (--budget); +} + +/* Called with IRQs disabled. */ +void b43_pio_rx(struct b43_pio_rxqueue *q) +{ + /* Due to latency issues we must run the RX path in + * a workqueue to be able to schedule between packets. */ + queue_work(q->dev->wl->hw->workqueue, &q->rx_work); +} + +static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) +{ + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + if (q->rev >= 8) { + b43_piotx_write32(q, B43_PIO8_TXCTL, + b43_piotx_read32(q, B43_PIO8_TXCTL) + | B43_PIO8_TXCTL_SUSPREQ); + } else { + b43_piotx_write16(q, B43_PIO_TXCTL, + b43_piotx_read16(q, B43_PIO_TXCTL) + | B43_PIO_TXCTL_SUSPREQ); + } + spin_unlock_irqrestore(&q->lock, flags); +} + +static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) +{ + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + if (q->rev >= 8) { + b43_piotx_write32(q, B43_PIO8_TXCTL, + b43_piotx_read32(q, B43_PIO8_TXCTL) + & ~B43_PIO8_TXCTL_SUSPREQ); + } else { + b43_piotx_write16(q, B43_PIO_TXCTL, + b43_piotx_read16(q, B43_PIO_TXCTL) + & ~B43_PIO_TXCTL_SUSPREQ); + } + spin_unlock_irqrestore(&q->lock, flags); +} + +void b43_pio_tx_suspend(struct b43_wldev *dev) +{ + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BK); + b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BE); + b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VI); + b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VO); + b43_pio_tx_suspend_queue(dev->pio.tx_queue_mcast); +} + +void b43_pio_tx_resume(struct b43_wldev *dev) +{ + b43_pio_tx_resume_queue(dev->pio.tx_queue_mcast); + b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VO); + b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VI); + b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BE); + b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BK); + b43_power_saving_ctl_bits(dev, 0); +} diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h new file mode 100644 index 00000000000..e2ec676cc9e --- /dev/null +++ b/drivers/net/wireless/b43/pio.h @@ -0,0 +1,220 @@ +#ifndef B43_PIO_H_ +#define B43_PIO_H_ + +#include "b43.h" + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/list.h> +#include <linux/skbuff.h> + + +/*** Registers for PIO queues up to revision 7. ***/ +/* TX queue. */ +#define B43_PIO_TXCTL 0x00 +#define B43_PIO_TXCTL_WRITELO 0x0001 +#define B43_PIO_TXCTL_WRITEHI 0x0002 +#define B43_PIO_TXCTL_EOF 0x0004 +#define B43_PIO_TXCTL_FREADY 0x0008 +#define B43_PIO_TXCTL_FLUSHREQ 0x0020 +#define B43_PIO_TXCTL_FLUSHPEND 0x0040 +#define B43_PIO_TXCTL_SUSPREQ 0x0080 +#define B43_PIO_TXCTL_QSUSP 0x0100 +#define B43_PIO_TXCTL_COMMCNT 0xFC00 +#define B43_PIO_TXCTL_COMMCNT_SHIFT 10 +#define B43_PIO_TXDATA 0x02 +#define B43_PIO_TXQBUFSIZE 0x04 +/* RX queue. */ +#define B43_PIO_RXCTL 0x00 +#define B43_PIO_RXCTL_FRAMERDY 0x0001 +#define B43_PIO_RXCTL_DATARDY 0x0002 +#define B43_PIO_RXDATA 0x02 + +/*** Registers for PIO queues revision 8 and later. ***/ +/* TX queue */ +#define B43_PIO8_TXCTL 0x00 +#define B43_PIO8_TXCTL_0_7 0x00000001 +#define B43_PIO8_TXCTL_8_15 0x00000002 +#define B43_PIO8_TXCTL_16_23 0x00000004 +#define B43_PIO8_TXCTL_24_31 0x00000008 +#define B43_PIO8_TXCTL_EOF 0x00000010 +#define B43_PIO8_TXCTL_FREADY 0x00000080 +#define B43_PIO8_TXCTL_SUSPREQ 0x00000100 +#define B43_PIO8_TXCTL_QSUSP 0x00000200 +#define B43_PIO8_TXCTL_FLUSHREQ 0x00000400 +#define B43_PIO8_TXCTL_FLUSHPEND 0x00000800 +#define B43_PIO8_TXDATA 0x04 +/* RX queue */ +#define B43_PIO8_RXCTL 0x00 +#define B43_PIO8_RXCTL_FRAMERDY 0x00000001 +#define B43_PIO8_RXCTL_DATARDY 0x00000002 +#define B43_PIO8_RXDATA 0x04 + + +/* The maximum number of TX-packets the HW can handle. */ +#define B43_PIO_MAX_NR_TXPACKETS 32 + + +#ifdef CONFIG_B43_PIO + +struct b43_pio_txpacket { + /* Pointer to the TX queue we belong to. */ + struct b43_pio_txqueue *queue; + /* The TX data packet. */ + struct sk_buff *skb; + /* The status meta data. */ + struct ieee80211_tx_status txstat; + /* Index in the (struct b43_pio_txqueue)->packets array. */ + u8 index; + + struct list_head list; +}; + +struct b43_pio_txqueue { + struct b43_wldev *dev; + spinlock_t lock; + u16 mmio_base; + + /* The device queue buffer size in bytes. */ + u16 buffer_size; + /* The number of used bytes in the device queue buffer. */ + u16 buffer_used; + /* The number of packets that can still get queued. + * This is decremented on queueing a packet and incremented + * after receiving the transmit status. */ + u16 free_packet_slots; + + /* True, if the mac80211 queue was stopped due to overflow at TX. */ + bool stopped; + /* Our b43 queue index number */ + u8 index; + /* The mac80211 QoS queue priority. */ + u8 queue_prio; + + /* Buffer for TX packet meta data. */ + struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS]; + struct list_head packets_list; + + /* Total number of transmitted packets. */ + unsigned int nr_tx_packets; + + /* Shortcut to the 802.11 core revision. This is to + * avoid horrible pointer dereferencing in the fastpaths. */ + u8 rev; +}; + +struct b43_pio_rxqueue { + struct b43_wldev *dev; + spinlock_t lock; + u16 mmio_base; + + /* Work to reduce latency issues on RX. */ + struct work_struct rx_work; + + /* Shortcut to the 802.11 core revision. This is to + * avoid horrible pointer dereferencing in the fastpaths. */ + u8 rev; +}; + + +static inline u16 b43_piotx_read16(struct b43_pio_txqueue *q, u16 offset) +{ + return b43_read16(q->dev, q->mmio_base + offset); +} + +static inline u32 b43_piotx_read32(struct b43_pio_txqueue *q, u16 offset) +{ + return b43_read32(q->dev, q->mmio_base + offset); +} + +static inline void b43_piotx_write16(struct b43_pio_txqueue *q, + u16 offset, u16 value) +{ + b43_write16(q->dev, q->mmio_base + offset, value); +} + +static inline void b43_piotx_write32(struct b43_pio_txqueue *q, + u16 offset, u32 value) +{ + b43_write32(q->dev, q->mmio_base + offset, value); +} + + +static inline u16 b43_piorx_read16(struct b43_pio_rxqueue *q, u16 offset) +{ + return b43_read16(q->dev, q->mmio_base + offset); +} + +static inline u32 b43_piorx_read32(struct b43_pio_rxqueue *q, u16 offset) +{ + return b43_read32(q->dev, q->mmio_base + offset); +} + +static inline void b43_piorx_write16(struct b43_pio_rxqueue *q, + u16 offset, u16 value) +{ + b43_write16(q->dev, q->mmio_base + offset, value); +} + +static inline void b43_piorx_write32(struct b43_pio_rxqueue *q, + u16 offset, u32 value) +{ + b43_write32(q->dev, q->mmio_base + offset, value); +} + + +int b43_pio_init(struct b43_wldev *dev); +void b43_pio_stop(struct b43_wldev *dev); +void b43_pio_free(struct b43_wldev *dev); + +int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); +void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); +void b43_pio_rx(struct b43_pio_rxqueue *q); + +void b43_pio_tx_suspend(struct b43_wldev *dev); +void b43_pio_tx_resume(struct b43_wldev *dev); + + +#else /* CONFIG_B43_PIO */ + + +static inline int b43_pio_init(struct b43_wldev *dev) +{ + return 0; +} +static inline void b43_pio_free(struct b43_wldev *dev) +{ +} +static inline void b43_pio_stop(struct b43_wldev *dev) +{ +} +static inline int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} +static inline void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline void b43_pio_rx(struct b43_pio_rxqueue *q) +{ +} +static inline void b43_pio_tx_suspend(struct b43_wldev *dev) +{ +} +static inline void b43_pio_tx_resume(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_PIO */ +#endif /* B43_PIO_H_ */ diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index f4faff6a7d6..275095b8cbe 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -47,29 +47,6 @@ static int get_integer(const char *buf, size_t count) return ret; } -static int get_boolean(const char *buf, size_t count) -{ - if (count != 0) { - if (buf[0] == '1') - return 1; - if (buf[0] == '0') - return 0; - if (count >= 4 && memcmp(buf, "true", 4) == 0) - return 1; - if (count >= 5 && memcmp(buf, "false", 5) == 0) - return 0; - if (count >= 3 && memcmp(buf, "yes", 3) == 0) - return 1; - if (count >= 2 && memcmp(buf, "no", 2) == 0) - return 0; - if (count >= 2 && memcmp(buf, "on", 2) == 0) - return 1; - if (count >= 3 && memcmp(buf, "off", 3) == 0) - return 0; - } - return -EINVAL; -} - static ssize_t b43_attr_interfmode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -155,82 +132,18 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, static DEVICE_ATTR(interference, 0644, b43_attr_interfmode_show, b43_attr_interfmode_store); -static ssize_t b43_attr_preamble_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct b43_wldev *wldev = dev_to_b43_wldev(dev); - ssize_t count; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&wldev->wl->mutex); - - if (wldev->short_preamble) - count = - snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); - else - count = - snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); - - mutex_unlock(&wldev->wl->mutex); - - return count; -} - -static ssize_t b43_attr_preamble_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct b43_wldev *wldev = dev_to_b43_wldev(dev); - unsigned long flags; - int value; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - value = get_boolean(buf, count); - if (value < 0) - return value; - mutex_lock(&wldev->wl->mutex); - spin_lock_irqsave(&wldev->wl->irq_lock, flags); - - wldev->short_preamble = !!value; - - spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); - mutex_unlock(&wldev->wl->mutex); - - return count; -} - -static DEVICE_ATTR(shortpreamble, 0644, - b43_attr_preamble_show, b43_attr_preamble_store); - int b43_sysfs_register(struct b43_wldev *wldev) { struct device *dev = wldev->dev->dev; - int err; B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED); - err = device_create_file(dev, &dev_attr_interference); - if (err) - goto out; - err = device_create_file(dev, &dev_attr_shortpreamble); - if (err) - goto err_remove_interfmode; - - out: - return err; - err_remove_interfmode: - device_remove_file(dev, &dev_attr_interference); - goto out; + return device_create_file(dev, &dev_attr_interference); } void b43_sysfs_unregister(struct b43_wldev *wldev) { struct device *dev = wldev->dev->dev; - device_remove_file(dev, &dev_attr_shortpreamble); device_remove_file(dev, &dev_attr_interference); } diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index e632125cb77..daa94211f83 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -204,42 +204,43 @@ static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]); } +static void b43_write_null_nst(struct b43_wldev *dev) +{ + int i; + + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, 0); +} + +static void b43_write_nst(struct b43_wldev *dev, const u16 *nst) +{ + int i; + + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, nst[i]); +} + static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */ { struct b43_phy *phy = &dev->phy; - int i; if (phy->type == B43_PHYTYPE_A) { if (phy->rev <= 1) - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, 0); + b43_write_null_nst(dev); else if (phy->rev == 2) - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, b43_tab_noisescalea2[i]); + b43_write_nst(dev, b43_tab_noisescalea2); else if (phy->rev == 3) - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, b43_tab_noisescalea3[i]); + b43_write_nst(dev, b43_tab_noisescalea3); else - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, b43_tab_noisescaleg3[i]); + b43_write_nst(dev, b43_tab_noisescaleg3); } else { if (phy->rev >= 6) { if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, b43_tab_noisescaleg3[i]); + b43_write_nst(dev, b43_tab_noisescaleg3); else - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, b43_tab_noisescaleg2[i]); + b43_write_nst(dev, b43_tab_noisescaleg2); } else { - for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, - i, b43_tab_noisescaleg1[i]); + b43_write_nst(dev, b43_tab_noisescaleg1); } } } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 7caa26eb410..19aefbfb2c9 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -30,48 +30,51 @@ #include "xmit.h" #include "phy.h" #include "dma.h" +#include "pio.h" -/* Extract the bitrate out of a CCK PLCP header. */ -static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) +/* Extract the bitrate index out of a CCK PLCP header. */ +static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) { switch (plcp->raw[0]) { case 0x0A: - return B43_CCK_RATE_1MB; + return 0; case 0x14: - return B43_CCK_RATE_2MB; + return 1; case 0x37: - return B43_CCK_RATE_5MB; + return 2; case 0x6E: - return B43_CCK_RATE_11MB; + return 3; } B43_WARN_ON(1); - return 0; + return -1; } -/* Extract the bitrate out of an OFDM PLCP header. */ -static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp) +/* Extract the bitrate index out of an OFDM PLCP header. */ +static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) { + int base = aphy ? 0 : 4; + switch (plcp->raw[0] & 0xF) { case 0xB: - return B43_OFDM_RATE_6MB; + return base + 0; case 0xF: - return B43_OFDM_RATE_9MB; + return base + 1; case 0xA: - return B43_OFDM_RATE_12MB; + return base + 2; case 0xE: - return B43_OFDM_RATE_18MB; + return base + 3; case 0x9: - return B43_OFDM_RATE_24MB; + return base + 4; case 0xD: - return B43_OFDM_RATE_36MB; + return base + 5; case 0x8: - return B43_OFDM_RATE_48MB; + return base + 6; case 0xC: - return B43_OFDM_RATE_54MB; + return base + 7; } B43_WARN_ON(1); - return 0; + return -1; } u8 b43_plcp_get_ratecode_cck(const u8 bitrate) @@ -191,6 +194,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, (const struct ieee80211_hdr *)fragment_data; int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl = le16_to_cpu(wlhdr->frame_control); + struct ieee80211_rate *fbrate; u8 rate, rate_fb; int rate_ofdm, rate_fb_ofdm; unsigned int plcp_fragment_len; @@ -200,9 +204,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate; + WARN_ON(!txctl->tx_rate); + rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); if (rate_ofdm) @@ -221,11 +227,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, txctl->vif, fragment_len, - fbrate_base100kbps); + fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -287,7 +292,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (dev->short_preamble) + if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { @@ -332,7 +337,8 @@ int b43_generate_txhdr(struct b43_wldev *dev, int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; - rts_rate = txctl->rts_cts_rate; + WARN_ON(!txctl->rts_cts_rate); + rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); @@ -506,7 +512,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) u16 phystat0, phystat3, chanstat, mactime; u32 macstat; u16 chanid; - u8 jssi; + u16 phytype; int padding; memset(&status, 0, sizeof(status)); @@ -514,10 +520,10 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) /* Get metadata about the frame from the header. */ phystat0 = le16_to_cpu(rxhdr->phy_status0); phystat3 = le16_to_cpu(rxhdr->phy_status3); - jssi = rxhdr->jssi; macstat = le32_to_cpu(rxhdr->mac_status); mactime = le16_to_cpu(rxhdr->mac_time); chanstat = le16_to_cpu(rxhdr->channel); + phytype = chanstat & B43_RX_CHAN_PHYTYPE; if (macstat & B43_RX_MAC_FCSERR) dev->wl->ieee_stats.dot11FCSErrorCount++; @@ -567,26 +573,40 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } } - status.ssi = b43_rssi_postprocess(dev, jssi, - (phystat0 & B43_RX_PHYST0_OFDM), - (phystat0 & B43_RX_PHYST0_GAINCTL), - (phystat3 & B43_RX_PHYST3_TRSTATE)); + /* Link quality statistics */ status.noise = dev->stats.link_noise; - /* the next line looks wrong, but is what mac80211 wants */ - status.signal = (jssi * 100) / B43_RX_MAX_SSI; + if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) { +// s8 rssi = max(rxhdr->power0, rxhdr->power1); + //TODO: Find out what the rssi value is (dBm or percentage?) + // and also find out what the maximum possible value is. + // Fill status.ssi and status.signal fields. + } else { + status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi, + (phystat0 & B43_RX_PHYST0_OFDM), + (phystat0 & B43_RX_PHYST0_GAINCTL), + (phystat3 & B43_RX_PHYST3_TRSTATE)); + /* the next line looks wrong, but is what mac80211 wants */ + status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; + } + if (phystat0 & B43_RX_PHYST0_OFDM) - status.rate = b43_plcp_get_bitrate_ofdm(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, + phytype == B43_PHYTYPE_A); else - status.rate = b43_plcp_get_bitrate_cck(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); /* - * If monitors are present get full 64-bit timestamp. This - * code assumes we get to process the packet within 16 bits - * of timestamp, i.e. about 65 milliseconds after the PHY - * received the first symbol. + * All frames on monitor interfaces and beacons always need a full + * 64-bit timestamp. Monitor interfaces need it for diagnostic + * purposes and beacons for IBSS merging. + * This code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY received + * the first symbol. */ - if (dev->wl->radiotap_enabled) { + if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) + == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) || + dev->wl->radiotap_enabled) { u16 low_mactime_now; b43_tsf_read(dev, &status.mactime); @@ -601,29 +621,28 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; switch (chanstat & B43_RX_CHAN_PHYTYPE) { case B43_PHYTYPE_A: - status.phymode = MODE_IEEE80211A; + status.band = IEEE80211_BAND_5GHZ; B43_WARN_ON(1); /* FIXME: We don't really know which value the "chanid" contains. * So the following assignment might be wrong. */ - status.channel = chanid; - status.freq = b43_channel_to_freq_5ghz(status.channel); + status.freq = b43_channel_to_freq_5ghz(chanid); break; case B43_PHYTYPE_G: - status.phymode = MODE_IEEE80211G; + status.band = IEEE80211_BAND_2GHZ; /* chanid is the radio channel cookie value as used * to tune the radio. */ status.freq = chanid + 2400; - status.channel = b43_freq_to_channel_2ghz(status.freq); break; case B43_PHYTYPE_N: - status.phymode = 0xDEAD /*FIXME MODE_IEEE80211N*/; /* chanid is the SHM channel cookie. Which is the plain * channel number in b43. */ - status.channel = chanid; - if (chanstat & B43_RX_CHAN_5GHZ) - status.freq = b43_freq_to_channel_5ghz(status.freq); - else - status.freq = b43_freq_to_channel_2ghz(status.freq); + if (chanstat & B43_RX_CHAN_5GHZ) { + status.band = IEEE80211_BAND_5GHZ; + status.freq = b43_freq_to_channel_5ghz(chanid); + } else { + status.band = IEEE80211_BAND_2GHZ; + status.freq = b43_freq_to_channel_2ghz(chanid); + } break; default: B43_WARN_ON(1); @@ -657,67 +676,54 @@ void b43_handle_txstatus(struct b43_wldev *dev, dev->wl->ieee_stats.dot11RTSSuccessCount++; } - b43_dma_handle_txstatus(dev, status); + if (b43_using_pio_transfers(dev)) + b43_pio_handle_txstatus(dev, status); + else + b43_dma_handle_txstatus(dev, status); } -/* Handle TX status report as received through DMA/PIO queues */ -void b43_handle_hwtxstatus(struct b43_wldev *dev, - const struct b43_hwtxstatus *hw) +/* Fill out the mac80211 TXstatus report based on the b43-specific + * txstatus report data. This returns a boolean whether the frame was + * successfully transmitted. */ +bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, + const struct b43_txstatus *status) { - struct b43_txstatus status; - u8 tmp; - - status.cookie = le16_to_cpu(hw->cookie); - status.seq = le16_to_cpu(hw->seq); - status.phy_stat = hw->phy_stat; - tmp = hw->count; - status.frame_count = (tmp >> 4); - status.rts_count = (tmp & 0x0F); - tmp = hw->flags; - status.supp_reason = ((tmp & 0x1C) >> 2); - status.pm_indicated = !!(tmp & 0x80); - status.intermediate = !!(tmp & 0x40); - status.for_ampdu = !!(tmp & 0x20); - status.acked = !!(tmp & 0x02); - - b43_handle_txstatus(dev, &status); + bool frame_success = 1; + + if (status->acked) { + /* The frame was ACKed. */ + report->flags |= IEEE80211_TX_STATUS_ACK; + } else { + /* The frame was not ACKed... */ + if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { + /* ...but we expected an ACK. */ + frame_success = 0; + report->excessive_retries = 1; + } + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + report->retry_count = 0; + } else + report->retry_count = status->frame_count - 1; + + return frame_success; } /* Stop any TX operation on the device (suspend the hardware queues) */ void b43_tx_suspend(struct b43_wldev *dev) { - b43_dma_tx_suspend(dev); + if (b43_using_pio_transfers(dev)) + b43_pio_tx_suspend(dev); + else + b43_dma_tx_suspend(dev); } /* Resume any TX operation on the device (resume the hardware queues) */ void b43_tx_resume(struct b43_wldev *dev) { - b43_dma_tx_resume(dev); -} - -#if 0 -static void upload_qos_parms(struct b43_wldev *dev, - const u16 * parms, u16 offset) -{ - int i; - - for (i = 0; i < B43_NR_QOSPARMS; i++) { - b43_shm_write16(dev, B43_SHM_SHARED, - offset + (i * 2), parms[i]); - } -} -#endif - -/* Initialize the QoS parameters */ -void b43_qos_init(struct b43_wldev *dev) -{ - /* FIXME: This function must probably be called from the mac80211 - * config callback. */ - return; - - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); - //FIXME kill magic - b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4); - - /*TODO: We might need some stack support here to get the values. */ + if (b43_using_pio_transfers(dev)) + b43_pio_tx_resume(dev); + else + b43_dma_tx_resume(dev); } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 41765039552..b05f44e0d62 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -207,25 +207,24 @@ enum { B43_TXST_SUPP_ABNACK, /* Afterburner NACK */ }; -/* Transmit Status as received through DMA/PIO on old chips */ -struct b43_hwtxstatus { - PAD_BYTES(4); - __le16 cookie; - u8 flags; - u8 count; - PAD_BYTES(2); - __le16 seq; - u8 phy_stat; - PAD_BYTES(1); -} __attribute__ ((__packed__)); - /* Receive header for v4 firmware. */ struct b43_rxhdr_fw4 { __le16 frame_len; /* Frame length */ PAD_BYTES(2); __le16 phy_status0; /* PHY RX Status 0 */ - __u8 jssi; /* PHY RX Status 1: JSSI */ - __u8 sig_qual; /* PHY RX Status 1: Signal Quality */ + union { + /* RSSI for A/B/G-PHYs */ + struct { + __u8 jssi; /* PHY RX Status 1: JSSI */ + __u8 sig_qual; /* PHY RX Status 1: Signal Quality */ + } __attribute__ ((__packed__)); + + /* RSSI for N-PHYs */ + struct { + __s8 power0; /* PHY RX Status 1: Power 0 */ + __s8 power1; /* PHY RX Status 1: Power 1 */ + } __attribute__ ((__packed__)); + } __attribute__ ((__packed__)); __le16 phy_status2; /* PHY RX Status 2 */ __le16 phy_status3; /* PHY RX Status 3 */ __le32 mac_status; /* MAC RX status */ @@ -295,25 +294,12 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); - -void b43_handle_hwtxstatus(struct b43_wldev *dev, - const struct b43_hwtxstatus *hw); +bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, + const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); void b43_tx_resume(struct b43_wldev *dev); -#define B43_NR_QOSPARMS 22 -enum { - B43_QOSPARM_TXOP = 0, - B43_QOSPARM_CWMIN, - B43_QOSPARM_CWMAX, - B43_QOSPARM_CWCUR, - B43_QOSPARM_AIFS, - B43_QOSPARM_BSLOTS, - B43_QOSPARM_REGGAP, - B43_QOSPARM_STATUS, -}; -void b43_qos_init(struct b43_wldev *dev); /* Helper functions for converting the key-table index from "firmware-format" * to "raw-format" and back. The firmware API changed for this at some revision. diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 93d45b71799..242b8ad4e33 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -130,13 +130,19 @@ #define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */ /* SHM_SHARED crypto engine */ #define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */ -/* SHM_SHARED beacon variables */ +/* SHM_SHARED beacon/AP variables */ +#define B43legacy_SHM_SH_DTIMP 0x0012 /* DTIM period */ +#define B43legacy_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ +#define B43legacy_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ +#define B43legacy_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ +#define B43legacy_SHM_SH_TIMPOS 0x001E /* TIM position in beacon */ #define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */ /* SHM_SHARED ACK/CTS control */ #define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */ /* SHM_SHARED probe response variables */ -#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */ +#define B43legacy_SHM_SH_PRTLEN 0x004A /* Probe Response template length */ #define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ +#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */ /* SHM_SHARED rate tables */ /* SHM_SHARED microcode soft registers */ #define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ @@ -199,6 +205,13 @@ #define B43legacy_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */ #define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */ +/* MAC Command bitfield */ +#define B43legacy_MACCMD_BEACON0_VALID 0x00000001 /* Beacon 0 in template RAM is busy/valid */ +#define B43legacy_MACCMD_BEACON1_VALID 0x00000002 /* Beacon 1 in template RAM is busy/valid */ +#define B43legacy_MACCMD_DFQ_VALID 0x00000004 /* Directed frame queue valid (IBSS PS mode, ATIM) */ +#define B43legacy_MACCMD_CCA 0x00000008 /* Clear channel assessment */ +#define B43legacy_MACCMD_BGNOISE 0x00000010 /* Background noise */ + /* 802.11 core specific TM State Low flags */ #define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ #define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */ @@ -317,15 +330,7 @@ enum { # undef assert #endif #ifdef CONFIG_B43LEGACY_DEBUG -# define B43legacy_WARN_ON(expr) \ - do { \ - if (unlikely((expr))) { \ - printk(KERN_INFO PFX "Test (%s) failed at:" \ - " %s:%d:%s()\n", \ - #expr, __FILE__, \ - __LINE__, __FUNCTION__); \ - } \ - } while (0) +# define B43legacy_WARN_ON(x) WARN_ON(x) # define B43legacy_BUG_ON(expr) \ do { \ if (unlikely((expr))) { \ @@ -336,7 +341,9 @@ enum { } while (0) # define B43legacy_DEBUG 1 #else -# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0) +/* This will evaluate the argument even if debugging is disabled. */ +static inline bool __b43legacy_warn_on_dummy(bool x) { return x; } +# define B43legacy_WARN_ON(x) __b43legacy_warn_on_dummy(unlikely(!!(x))) # define B43legacy_BUG_ON(x) do { /* nothing */ } while (0) # define B43legacy_DEBUG 0 #endif @@ -392,10 +399,6 @@ struct b43legacy_phy { u8 possible_phymodes; /* GMODE bit enabled in MACCTL? */ bool gmode; - /* Possible ieee80211 subsystem hwmodes for this PHY. - * Which mode is selected, depends on thr GMODE enabled bit */ -#define B43legacy_MAX_PHYHWMODES 2 - struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES]; /* Analog Type */ u8 analog; @@ -598,6 +601,12 @@ struct b43legacy_wl { u8 nr_devs; bool radiotap_enabled; + + /* The beacon we are currently using (AP or IBSS mode). + * This beacon stuff is protected by the irq_lock. */ + struct sk_buff *current_beacon; + bool beacon0_uploaded; + bool beacon1_uploaded; }; /* Pointers to the firmware data and meta information about it. */ @@ -649,7 +658,7 @@ struct b43legacy_wldev { bool __using_pio; /* Using pio rather than dma. */ bool bad_frames_preempt;/* Use "Bad Frames Preemption". */ - bool reg124_set_0x4; /* Variable to keep track of IRQ. */ + bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM). */ bool short_preamble; /* TRUE if using short preamble. */ bool short_slot; /* TRUE if using short slot timing. */ bool radio_hw_enable; /* State of radio hardware enable bit. */ @@ -696,9 +705,6 @@ struct b43legacy_wldev { u8 max_nr_keys; struct b43legacy_key key[58]; - /* Cached beacon template while uploading the template. */ - struct sk_buff *cached_beacon; - /* Firmware data */ struct b43legacy_firmware fw; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 5f3f34e1dbf..f518e796bde 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -95,28 +95,29 @@ MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl); * data in there. This data is the same for all devices, so we don't * get concurrency issues */ #define RATETAB_ENT(_rateid, _flags) \ - { \ - .rate = B43legacy_RATE_TO_100KBPS(_rateid), \ - .val = (_rateid), \ - .val2 = (_rateid), \ - .flags = (_flags), \ + { \ + .bitrate = B43legacy_RATE_TO_100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ } +/* + * NOTE: When changing this, sync with xmit.c's + * b43legacy_plcp_get_bitrate_idx_* functions! + */ static struct ieee80211_rate __b43legacy_ratetable[] = { - RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK), - RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_CCK_RATE_1MB, 0), + RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43legacy_OFDM_RATE_6MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_9MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_12MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_18MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_24MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_36MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_48MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_54MB, 0), }; -#define b43legacy_a_ratetable (__b43legacy_ratetable + 4) -#define b43legacy_a_ratetable_size 8 #define b43legacy_b_ratetable (__b43legacy_ratetable + 0) #define b43legacy_b_ratetable_size 4 #define b43legacy_g_ratetable (__b43legacy_ratetable + 0) @@ -124,14 +125,8 @@ static struct ieee80211_rate __b43legacy_ratetable[] = { #define CHANTAB_ENT(_chanid, _freq) \ { \ - .chan = (_chanid), \ - .freq = (_freq), \ - .val = (_chanid), \ - .flag = IEEE80211_CHAN_W_SCAN | \ - IEEE80211_CHAN_W_ACTIVE_SCAN | \ - IEEE80211_CHAN_W_IBSS, \ - .power_level = 0x0A, \ - .antenna_max = 0xFF, \ + .center_freq = (_freq), \ + .hw_value = (_chanid), \ } static struct ieee80211_channel b43legacy_bg_chantable[] = { CHANTAB_ENT(1, 2412), @@ -149,7 +144,20 @@ static struct ieee80211_channel b43legacy_bg_chantable[] = { CHANTAB_ENT(13, 2472), CHANTAB_ENT(14, 2484), }; -#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable) + +static struct ieee80211_supported_band b43legacy_band_2GHz_BPHY = { + .channels = b43legacy_bg_chantable, + .n_channels = ARRAY_SIZE(b43legacy_bg_chantable), + .bitrates = b43legacy_b_ratetable, + .n_bitrates = b43legacy_b_ratetable_size, +}; + +static struct ieee80211_supported_band b43legacy_band_2GHz_GPHY = { + .channels = b43legacy_bg_chantable, + .n_channels = ARRAY_SIZE(b43legacy_bg_chantable), + .bitrates = b43legacy_g_ratetable, + .n_bitrates = b43legacy_g_ratetable_size, +}; static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev); static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev); @@ -797,9 +805,8 @@ static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev) { b43legacy_jssi_write(dev, 0x7F7F7F7F); b43legacy_write32(dev, B43legacy_MMIO_MACCMD, - b43legacy_read32(dev, - B43legacy_MMIO_MACCMD) - | (1 << 4)); + b43legacy_read32(dev, B43legacy_MMIO_MACCMD) + | B43legacy_MACCMD_BGNOISE); B43legacy_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); } @@ -888,18 +895,18 @@ static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev) if (1/*FIXME: the last PSpoll frame was sent successfully */) b43legacy_power_saving_ctl_bits(dev, -1, -1); } - dev->reg124_set_0x4 = 0; if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) - dev->reg124_set_0x4 = 1; + dev->dfq_valid = 1; } static void handle_irq_atim_end(struct b43legacy_wldev *dev) { - if (!dev->reg124_set_0x4) /*FIXME rename this variable*/ - return; - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, - b43legacy_read32(dev, B43legacy_MMIO_MACCMD) - | 0x4); + if (dev->dfq_valid) { + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, + b43legacy_read32(dev, B43legacy_MMIO_MACCMD) + | B43legacy_MACCMD_DFQ_VALID); + dev->dfq_valid = 0; + } } static void handle_irq_pmq(struct b43legacy_wldev *dev) @@ -955,32 +962,77 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate) { - int len; - const u8 *data; - B43legacy_WARN_ON(!dev->cached_beacon); - len = min((size_t)dev->cached_beacon->len, + unsigned int i, len, variable_len; + const struct ieee80211_mgmt *bcn; + const u8 *ie; + bool tim_found = 0; + + bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); + len = min((size_t)dev->wl->current_beacon->len, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); - data = (const u8 *)(dev->cached_beacon->data); - b43legacy_write_template_common(dev, data, - len, ram_offset, + + b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); + + /* Find the position of the TIM and the DTIM_period value + * and write them to SHM. */ + ie = bcn->u.beacon.variable; + variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable); + for (i = 0; i < variable_len - 2; ) { + uint8_t ie_id, ie_len; + + ie_id = ie[i]; + ie_len = ie[i + 1]; + if (ie_id == 5) { + u16 tim_position; + u16 dtim_period; + /* This is the TIM Information Element */ + + /* Check whether the ie_len is in the beacon data range. */ + if (variable_len < ie_len + 2 + i) + break; + /* A valid TIM is at least 4 bytes long. */ + if (ie_len < 4) + break; + tim_found = 1; + + tim_position = sizeof(struct b43legacy_plcp_hdr6); + tim_position += offsetof(struct ieee80211_mgmt, + u.beacon.variable); + tim_position += i; + + dtim_period = ie[i + 3]; + + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_TIMPOS, tim_position); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_DTIMP, dtim_period); + break; + } + i += ie_len + 2; + } + if (!tim_found) { + b43legacywarn(dev->wl, "Did not find a valid TIM IE in the " + "beacon template packet. AP or IBSS operation " + "may be broken.\n"); + } } static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, u16 shm_offset, u16 size, - u8 rate) + struct ieee80211_rate *rate) { struct b43legacy_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; - b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, size, - B43legacy_RATE_TO_100KBPS(rate)); + rate); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset, @@ -997,45 +1049,44 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, * 2) Patching duration field * 3) Stripping TIM */ -static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, - u16 *dest_size, u8 rate) +static const u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, + u16 *dest_size, + struct ieee80211_rate *rate) { const u8 *src_data; u8 *dest_data; - u16 src_size; - u16 elem_size; - u16 src_pos; - u16 dest_pos; + u16 src_size, elem_size, src_pos, dest_pos; __le16 dur; struct ieee80211_hdr *hdr; + size_t ie_start; + + src_size = dev->wl->current_beacon->len; + src_data = (const u8 *)dev->wl->current_beacon->data; - B43legacy_WARN_ON(!dev->cached_beacon); - src_size = dev->cached_beacon->len; - src_data = (const u8 *)dev->cached_beacon->data; + /* Get the start offset of the variable IEs in the packet. */ + ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + B43legacy_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, + u.beacon.variable)); - if (unlikely(src_size < 0x24)) { - b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: " - "invalid beacon\n"); + if (B43legacy_WARN_ON(src_size < ie_start)) return NULL; - } dest_data = kmalloc(src_size, GFP_ATOMIC); if (unlikely(!dest_data)) return NULL; - /* 0x24 is offset of first variable-len Information-Element - * in beacon frame. - */ - memcpy(dest_data, src_data, 0x24); - src_pos = 0x24; - dest_pos = 0x24; - for (; src_pos < src_size - 2; src_pos += elem_size) { + /* Copy the static data and all Information Elements, except the TIM. */ + memcpy(dest_data, src_data, ie_start); + src_pos = ie_start; + dest_pos = ie_start; + for ( ; src_pos < src_size - 2; src_pos += elem_size) { elem_size = src_data[src_pos + 1] + 2; - if (src_data[src_pos] != 0x05) { /* TIM */ - memcpy(dest_data + dest_pos, src_data + src_pos, - elem_size); - dest_pos += elem_size; + if (src_data[src_pos] == 5) { + /* This is the TIM. */ + continue; } + memcpy(dest_data + dest_pos, src_data + src_pos, elem_size); + dest_pos += elem_size; } *dest_size = dest_pos; hdr = (struct ieee80211_hdr *)dest_data; @@ -1046,7 +1097,7 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, *dest_size, - B43legacy_RATE_TO_100KBPS(rate)); + rate); hdr->duration_id = dur; return dest_data; @@ -1054,13 +1105,13 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset, + struct ieee80211_rate *rate) { - u8 *probe_resp_data; + const u8 *probe_resp_data; u16 size; - B43legacy_WARN_ON(!dev->cached_beacon); - size = dev->cached_beacon->len; + size = dev->wl->current_beacon->len; probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate); if (unlikely(!probe_resp_data)) return; @@ -1069,59 +1120,37 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, * all possible basic rates */ b43legacy_write_probe_resp_plcp(dev, 0x31A, size, - B43legacy_CCK_RATE_1MB); + &b43legacy_b_ratetable[0]); b43legacy_write_probe_resp_plcp(dev, 0x32C, size, - B43legacy_CCK_RATE_2MB); + &b43legacy_b_ratetable[1]); b43legacy_write_probe_resp_plcp(dev, 0x33E, size, - B43legacy_CCK_RATE_5MB); + &b43legacy_b_ratetable[2]); b43legacy_write_probe_resp_plcp(dev, 0x350, size, - B43legacy_CCK_RATE_11MB); + &b43legacy_b_ratetable[3]); size = min((size_t)size, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); b43legacy_write_template_common(dev, probe_resp_data, size, ram_offset, - shm_size_offset, rate); + shm_size_offset, rate->bitrate); kfree(probe_resp_data); } -static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev, - struct sk_buff *beacon) -{ - if (dev->cached_beacon) - kfree_skb(dev->cached_beacon); - dev->cached_beacon = beacon; - - return 0; -} - -static void b43legacy_update_templates(struct b43legacy_wldev *dev) -{ - u32 status; - - B43legacy_WARN_ON(!dev->cached_beacon); - - b43legacy_write_beacon_template(dev, 0x68, 0x18, - B43legacy_CCK_RATE_1MB); - b43legacy_write_beacon_template(dev, 0x468, 0x1A, - B43legacy_CCK_RATE_1MB); - b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, - B43legacy_CCK_RATE_11MB); - - status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); - status |= 0x03; - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, status); -} - -static void b43legacy_refresh_templates(struct b43legacy_wldev *dev, - struct sk_buff *beacon) +/* Asynchronously update the packet templates in template RAM. + * Locking: Requires wl->irq_lock to be locked. */ +static void b43legacy_update_templates(struct b43legacy_wl *wl, + struct sk_buff *beacon) { - int err; + /* This is the top half of the ansynchronous beacon update. The bottom + * half is the beacon IRQ. Beacon update must be asynchronous to avoid + * sending an invalid beacon. This can happen for example, if the + * firmware transmits a beacon while we are updating it. */ - err = b43legacy_refresh_cached_beacon(dev, beacon); - if (unlikely(err)) - return; - b43legacy_update_templates(dev); + if (wl->current_beacon) + dev_kfree_skb_any(wl->current_beacon); + wl->current_beacon = beacon; + wl->beacon0_uploaded = 0; + wl->beacon1_uploaded = 0; } static void b43legacy_set_ssid(struct b43legacy_wldev *dev, @@ -1162,38 +1191,37 @@ static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, static void handle_irq_beacon(struct b43legacy_wldev *dev) { - u32 status; + struct b43legacy_wl *wl = dev->wl; + u32 cmd; - if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) return; - dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; - status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); - - if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { - /* ACK beacon IRQ. */ - b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, - B43legacy_IRQ_BEACON); - dev->irq_savedstate |= B43legacy_IRQ_BEACON; - if (dev->cached_beacon) - kfree_skb(dev->cached_beacon); - dev->cached_beacon = NULL; - return; - } - if (!(status & 0x1)) { - b43legacy_write_beacon_template(dev, 0x68, 0x18, - B43legacy_CCK_RATE_1MB); - status |= 0x1; - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, - status); - } - if (!(status & 0x2)) { - b43legacy_write_beacon_template(dev, 0x468, 0x1A, - B43legacy_CCK_RATE_1MB); - status |= 0x2; - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, - status); + /* This is the bottom half of the asynchronous beacon update. */ + + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) { + if (!wl->beacon0_uploaded) { + b43legacy_write_beacon_template(dev, 0x68, + B43legacy_SHM_SH_BTL0, + B43legacy_CCK_RATE_1MB); + b43legacy_write_probe_resp_template(dev, 0x268, + B43legacy_SHM_SH_PRTLEN, + &__b43legacy_ratetable[3]); + wl->beacon0_uploaded = 1; + } + cmd |= B43legacy_MACCMD_BEACON0_VALID; + } + if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) { + if (!wl->beacon1_uploaded) { + b43legacy_write_beacon_template(dev, 0x468, + B43legacy_SHM_SH_BTL1, + B43legacy_CCK_RATE_1MB); + wl->beacon1_uploaded = 1; + } + cmd |= B43legacy_MACCMD_BEACON1_VALID; } + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); } static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) @@ -2550,14 +2578,16 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); mutex_lock(&wl->mutex); + dev = wl->current_dev; + phy = &dev->phy; /* Switch the PHY mode (if necessary). */ - switch (conf->phymode) { - case MODE_IEEE80211B: - new_phymode = B43legacy_PHYMODE_B; - break; - case MODE_IEEE80211G: - new_phymode = B43legacy_PHYMODE_G; + switch (conf->channel->band) { + case IEEE80211_BAND_2GHZ: + if (phy->type == B43legacy_PHYTYPE_B) + new_phymode = B43legacy_PHYMODE_B; + else + new_phymode = B43legacy_PHYMODE_G; break; default: B43legacy_WARN_ON(1); @@ -2565,8 +2595,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, err = b43legacy_switch_phymode(wl, new_phymode); if (err) goto out_unlock_mutex; - dev = wl->current_dev; - phy = &dev->phy; /* Disable IRQs while reconfiguring the device. * This makes it possible to drop the spinlock throughout @@ -2582,8 +2610,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ - if (conf->channel_val != phy->channel) - b43legacy_radio_selectchannel(dev, conf->channel_val, 0); + if (conf->channel->hw_value != phy->channel) + b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) @@ -2700,7 +2728,7 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->beacon) - b43legacy_refresh_templates(dev, conf->beacon); + b43legacy_update_templates(wl, conf->beacon); } b43legacy_write_mac_bssid_templates(dev); } @@ -2918,7 +2946,7 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) { /* Flags */ - dev->reg124_set_0x4 = 0; + dev->dfq_valid = 0; /* Stats */ memset(&dev->stats, 0, sizeof(dev->stats)); @@ -3013,6 +3041,11 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) kfree(phy->tssi2dbm); kfree(phy->lo_control); phy->lo_control = NULL; + if (dev->wl->current_beacon) { + dev_kfree_skb_any(dev->wl->current_beacon); + dev->wl->current_beacon = NULL; + } + ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(dev->dev->bus); } @@ -3337,6 +3370,41 @@ out_unlock: return err; } +static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, + int aid, int set) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct sk_buff *beacon; + unsigned long flags; + + /* We could modify the existing beacon and set the aid bit in the TIM + * field, but that would probably require resizing and moving of data + * within the beacon template. Simply request a new beacon and let + * mac80211 do the hard work. */ + beacon = ieee80211_beacon_get(hw, wl->vif, NULL); + if (unlikely(!beacon)) + return -ENOMEM; + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_update_templates(wl, beacon); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *beacon, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + unsigned long flags; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_update_templates(wl, beacon); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + static const struct ieee80211_ops b43legacy_hw_ops = { .tx = b43legacy_op_tx, .conf_tx = b43legacy_op_conf_tx, @@ -3350,6 +3418,8 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .start = b43legacy_op_start, .stop = b43legacy_op_stop, .set_retry_limit = b43legacy_op_set_retry_limit, + .set_tim = b43legacy_op_beacon_set_tim, + .beacon_update = b43legacy_op_ibss_beacon_update, }; /* Hard-reset the chip. Do not call this directly. @@ -3398,48 +3468,19 @@ static int b43legacy_setup_modes(struct b43legacy_wldev *dev, int have_gphy) { struct ieee80211_hw *hw = dev->wl->hw; - struct ieee80211_hw_mode *mode; struct b43legacy_phy *phy = &dev->phy; - int cnt = 0; - int err; phy->possible_phymodes = 0; - for (; 1; cnt++) { - if (have_bphy) { - B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211B; - mode->num_channels = b43legacy_bg_chantable_size; - mode->channels = b43legacy_bg_chantable; - mode->num_rates = b43legacy_b_ratetable_size; - mode->rates = b43legacy_b_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43legacy_PHYMODE_B; - have_bphy = 0; - continue; - } - if (have_gphy) { - B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211G; - mode->num_channels = b43legacy_bg_chantable_size; - mode->channels = b43legacy_bg_chantable; - mode->num_rates = b43legacy_g_ratetable_size; - mode->rates = b43legacy_g_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43legacy_PHYMODE_G; - have_gphy = 0; - continue; - } - break; + if (have_bphy) { + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &b43legacy_band_2GHz_BPHY; + phy->possible_phymodes |= B43legacy_PHYMODE_B; + } + + if (have_gphy) { + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &b43legacy_band_2GHz_GPHY; + phy->possible_phymodes |= B43legacy_PHYMODE_G; } return 0; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index d84408a82db..dcad2491a60 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -37,45 +37,48 @@ /* Extract the bitrate out of a CCK PLCP header. */ -static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp) +static u8 b43legacy_plcp_get_bitrate_idx_cck(struct b43legacy_plcp_hdr6 *plcp) { switch (plcp->raw[0]) { case 0x0A: - return B43legacy_CCK_RATE_1MB; + return 0; case 0x14: - return B43legacy_CCK_RATE_2MB; + return 1; case 0x37: - return B43legacy_CCK_RATE_5MB; + return 2; case 0x6E: - return B43legacy_CCK_RATE_11MB; + return 3; } B43legacy_BUG_ON(1); - return 0; + return -1; } /* Extract the bitrate out of an OFDM PLCP header. */ -static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp) +static u8 b43legacy_plcp_get_bitrate_idx_ofdm(struct b43legacy_plcp_hdr6 *plcp, + bool aphy) { + int base = aphy ? 0 : 4; + switch (plcp->raw[0] & 0xF) { case 0xB: - return B43legacy_OFDM_RATE_6MB; + return base + 0; case 0xF: - return B43legacy_OFDM_RATE_9MB; + return base + 1; case 0xA: - return B43legacy_OFDM_RATE_12MB; + return base + 2; case 0xE: - return B43legacy_OFDM_RATE_18MB; + return base + 3; case 0x9: - return B43legacy_OFDM_RATE_24MB; + return base + 4; case 0xD: - return B43legacy_OFDM_RATE_36MB; + return base + 5; case 0x8: - return B43legacy_OFDM_RATE_48MB; + return base + 6; case 0xC: - return B43legacy_OFDM_RATE_54MB; + return base + 7; } B43legacy_BUG_ON(1); - return 0; + return -1; } u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate) @@ -192,7 +195,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl; u8 rate; - u8 rate_fb; + struct ieee80211_rate *rate_fb; int rate_ofdm; int rate_fb_ofdm; unsigned int plcp_fragment_len; @@ -204,16 +207,16 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate; + rate = txctl->tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; - rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb); + rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); /* Calculate duration for fallback rate */ - if ((rate_fb == rate) || + if ((rate_fb->hw_value == rate) || (wlhdr->duration_id & cpu_to_le16(0x8000)) || (wlhdr->duration_id == cpu_to_le16(0))) { /* If the fallback rate equals the normal rate or the @@ -221,11 +224,10 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, txctl->vif, fragment_len, - fbrate_base100kbps); + rate_fb); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -266,7 +268,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, rate); b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) (&txhdr->plcp_fb), plcp_fragment_len, - rate_fb); + rate_fb->hw_value); /* PHY TX Control word */ if (rate_ofdm) @@ -310,7 +312,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = txctl->rts_cts_rate; + rts_rate = txctl->rts_cts_rate->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); @@ -536,19 +538,24 @@ void b43legacy_rx(struct b43legacy_wldev *dev, (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); status.noise = dev->stats.link_noise; status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + /* change to support A PHY */ if (phystat0 & B43legacy_RX_PHYST0_OFDM) - status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp); + status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); else - status.rate = b43legacy_plcp_get_bitrate_cck(plcp); + status.rate_idx = b43legacy_plcp_get_bitrate_idx_cck(plcp); status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT); /* - * If monitors are present get full 64-bit timestamp. This - * code assumes we get to process the packet within 16 bits - * of timestamp, i.e. about 65 milliseconds after the PHY - * received the first symbol. + * All frames on monitor interfaces and beacons always need a full + * 64-bit timestamp. Monitor interfaces need it for diagnostic + * purposes and beacons for IBSS merging. + * This code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY received + * the first symbol. */ - if (dev->wl->radiotap_enabled) { + if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) + == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) || + dev->wl->radiotap_enabled) { u16 low_mactime_now; b43legacy_tsf_read(dev, &status.mactime); @@ -564,14 +571,9 @@ void b43legacy_rx(struct b43legacy_wldev *dev, B43legacy_RX_CHAN_ID_SHIFT; switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) { case B43legacy_PHYTYPE_B: - status.phymode = MODE_IEEE80211B; - status.freq = chanid + 2400; - status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); - break; case B43legacy_PHYTYPE_G: - status.phymode = MODE_IEEE80211G; + status.band = IEEE80211_BAND_2GHZ; status.freq = chanid + 2400; - status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); break; default: b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n", diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig deleted file mode 100644 index afb8f4305c2..00000000000 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ /dev/null @@ -1,70 +0,0 @@ -config BCM43XX - tristate "Broadcom BCM43xx wireless support (DEPRECATED)" - depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && (!SSB_B43_PCI_BRIDGE || SSB != y) && EXPERIMENTAL - select WIRELESS_EXT - select FW_LOADER - select HW_RANDOM - ---help--- - This is an experimental driver for the Broadcom 43xx wireless - chip, found in the Apple Airport Extreme and various other - devices. This driver is deprecated and will be removed - from the kernel in the near future. It has been replaced - by the b43 and b43legacy drivers. - -config BCM43XX_DEBUG - bool "Broadcom BCM43xx debugging (RECOMMENDED)" - depends on BCM43XX - default y - ---help--- - Broadcom 43xx debugging messages. - Say Y, because the driver is still very experimental and - this will help you get it running. - -config BCM43XX_DMA - bool - depends on BCM43XX - -config BCM43XX_PIO - bool - depends on BCM43XX - -choice - prompt "BCM43xx data transfer mode" - depends on BCM43XX - default BCM43XX_DMA_AND_PIO_MODE - -config BCM43XX_DMA_AND_PIO_MODE - bool "DMA + PIO" - select BCM43XX_DMA - select BCM43XX_PIO - ---help--- - Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) - data transfer modes. - The actually used mode is selectable through the module - parameter "pio". If the module parameter is pio=0, DMA is used. - Otherwise PIO is used. DMA is default. - - If unsure, choose this option. - -config BCM43XX_DMA_MODE - bool "DMA (Direct Memory Access) only" - select BCM43XX_DMA - ---help--- - Only include Direct Memory Access (DMA). - This reduces the size of the driver module, by omitting the PIO code. - -config BCM43XX_PIO_MODE - bool "PIO (Programmed I/O) only" - select BCM43XX_PIO - ---help--- - Only include Programmed I/O (PIO). - This reduces the size of the driver module, by omitting the DMA code. - Please note that PIO transfers are slow (compared to DMA). - - Also note that not all devices of the 43xx series support PIO. - The 4306 (Apple Airport Extreme and others) supports PIO, while - the 4318 is known to _not_ support PIO. - - Only use PIO, if DMA does not work for you. - -endchoice diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile deleted file mode 100644 index bb5220c629d..00000000000 --- a/drivers/net/wireless/bcm43xx/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -obj-$(CONFIG_BCM43XX) += bcm43xx.o -bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o - -bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o -bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o - -bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ - bcm43xx_radio.o bcm43xx_phy.o \ - bcm43xx_power.o bcm43xx_wx.o \ - bcm43xx_leds.o bcm43xx_ethtool.o \ - bcm43xx_xmit.o bcm43xx_sysfs.o \ - $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h deleted file mode 100644 index 2ebd2edf586..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ /dev/null @@ -1,997 +0,0 @@ -#ifndef BCM43xx_H_ -#define BCM43xx_H_ - -#include <linux/hw_random.h> -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/stringify.h> -#include <linux/pci.h> -#include <net/ieee80211.h> -#include <net/ieee80211softmac.h> -#include <asm/atomic.h> -#include <asm/io.h> - - -#include "bcm43xx_debugfs.h" -#include "bcm43xx_leds.h" - - -#define PFX KBUILD_MODNAME ": " - -#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50 -#define BCM43xx_IRQWAIT_MAX_RETRIES 100 - -#define BCM43xx_IO_SIZE 8192 - -/* Active Core PCI Configuration Register. */ -#define BCM43xx_PCICFG_ACTIVE_CORE 0x80 -/* SPROM control register. */ -#define BCM43xx_PCICFG_SPROMCTL 0x88 -/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ -#define BCM43xx_PCICFG_ICR 0x94 - -/* MMIO offsets */ -#define BCM43xx_MMIO_DMA0_REASON 0x20 -#define BCM43xx_MMIO_DMA0_IRQ_MASK 0x24 -#define BCM43xx_MMIO_DMA1_REASON 0x28 -#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x2C -#define BCM43xx_MMIO_DMA2_REASON 0x30 -#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x34 -#define BCM43xx_MMIO_DMA3_REASON 0x38 -#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x3C -#define BCM43xx_MMIO_DMA4_REASON 0x40 -#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x44 -#define BCM43xx_MMIO_DMA5_REASON 0x48 -#define BCM43xx_MMIO_DMA5_IRQ_MASK 0x4C -#define BCM43xx_MMIO_STATUS_BITFIELD 0x120 -#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124 -#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128 -#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C -#define BCM43xx_MMIO_RAM_CONTROL 0x130 -#define BCM43xx_MMIO_RAM_DATA 0x134 -#define BCM43xx_MMIO_PS_STATUS 0x140 -#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158 -#define BCM43xx_MMIO_SHM_CONTROL 0x160 -#define BCM43xx_MMIO_SHM_DATA 0x164 -#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166 -#define BCM43xx_MMIO_XMITSTAT_0 0x170 -#define BCM43xx_MMIO_XMITSTAT_1 0x174 -#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ -#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ - -/* 32-bit DMA */ -#define BCM43xx_MMIO_DMA32_BASE0 0x200 -#define BCM43xx_MMIO_DMA32_BASE1 0x220 -#define BCM43xx_MMIO_DMA32_BASE2 0x240 -#define BCM43xx_MMIO_DMA32_BASE3 0x260 -#define BCM43xx_MMIO_DMA32_BASE4 0x280 -#define BCM43xx_MMIO_DMA32_BASE5 0x2A0 -/* 64-bit DMA */ -#define BCM43xx_MMIO_DMA64_BASE0 0x200 -#define BCM43xx_MMIO_DMA64_BASE1 0x240 -#define BCM43xx_MMIO_DMA64_BASE2 0x280 -#define BCM43xx_MMIO_DMA64_BASE3 0x2C0 -#define BCM43xx_MMIO_DMA64_BASE4 0x300 -#define BCM43xx_MMIO_DMA64_BASE5 0x340 -/* PIO */ -#define BCM43xx_MMIO_PIO1_BASE 0x300 -#define BCM43xx_MMIO_PIO2_BASE 0x310 -#define BCM43xx_MMIO_PIO3_BASE 0x320 -#define BCM43xx_MMIO_PIO4_BASE 0x330 - -#define BCM43xx_MMIO_PHY_VER 0x3E0 -#define BCM43xx_MMIO_PHY_RADIO 0x3E2 -#define BCM43xx_MMIO_ANTENNA 0x3E8 -#define BCM43xx_MMIO_CHANNEL 0x3F0 -#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4 -#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6 -#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8 -#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA -#define BCM43xx_MMIO_PHY_CONTROL 0x3FC -#define BCM43xx_MMIO_PHY_DATA 0x3FE -#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420 -#define BCM43xx_MMIO_MACFILTER_DATA 0x422 -#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A -#define BCM43xx_MMIO_GPIO_CONTROL 0x49C -#define BCM43xx_MMIO_GPIO_MASK 0x49E -#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */ -#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ -#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ -#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ -#define BCM43xx_MMIO_RNG 0x65A -#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 - -/* SPROM offsets. */ -#define BCM43xx_SPROM_BASE 0x1000 -#define BCM43xx_SPROM_BOARDFLAGS2 0x1c -#define BCM43xx_SPROM_IL0MACADDR 0x24 -#define BCM43xx_SPROM_ET0MACADDR 0x27 -#define BCM43xx_SPROM_ET1MACADDR 0x2a -#define BCM43xx_SPROM_ETHPHY 0x2d -#define BCM43xx_SPROM_BOARDREV 0x2e -#define BCM43xx_SPROM_PA0B0 0x2f -#define BCM43xx_SPROM_PA0B1 0x30 -#define BCM43xx_SPROM_PA0B2 0x31 -#define BCM43xx_SPROM_WL0GPIO0 0x32 -#define BCM43xx_SPROM_WL0GPIO2 0x33 -#define BCM43xx_SPROM_MAXPWR 0x34 -#define BCM43xx_SPROM_PA1B0 0x35 -#define BCM43xx_SPROM_PA1B1 0x36 -#define BCM43xx_SPROM_PA1B2 0x37 -#define BCM43xx_SPROM_IDL_TSSI_TGT 0x38 -#define BCM43xx_SPROM_BOARDFLAGS 0x39 -#define BCM43xx_SPROM_ANTENNA_GAIN 0x3a -#define BCM43xx_SPROM_VERSION 0x3f - -/* BCM43xx_SPROM_BOARDFLAGS values */ -#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ -#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ -#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ -#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ -#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ -#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ -#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ -#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */ -#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */ -#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ -#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ -#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ -#define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */ -#define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */ -#define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ -#define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ - -/* GPIO register offset, in both ChipCommon and PCI core. */ -#define BCM43xx_GPIO_CONTROL 0x6c - -/* SHM Routing */ -#define BCM43xx_SHM_SHARED 0x0001 -#define BCM43xx_SHM_WIRELESS 0x0002 -#define BCM43xx_SHM_PCM 0x0003 -#define BCM43xx_SHM_HWMAC 0x0004 -#define BCM43xx_SHM_UCODE 0x0300 - -/* MacFilter offsets. */ -#define BCM43xx_MACFILTER_SELF 0x0000 -#define BCM43xx_MACFILTER_ASSOC 0x0003 - -/* Chipcommon registers. */ -#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04 -#define BCM43xx_CHIPCOMMON_CTL 0x28 -#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0 -#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4 -#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8 -#define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0 - -/* PCI core specific registers. */ -#define BCM43xx_PCICORE_BCAST_ADDR 0x50 -#define BCM43xx_PCICORE_BCAST_DATA 0x54 -#define BCM43xx_PCICORE_SBTOPCI2 0x108 - -/* SBTOPCI2 values. */ -#define BCM43xx_SBTOPCI2_PREFETCH 0x4 -#define BCM43xx_SBTOPCI2_BURST 0x8 -#define BCM43xx_SBTOPCI2_MEMREAD_MULTI 0x20 - -/* PCI-E core registers. */ -#define BCM43xx_PCIECORE_REG_ADDR 0x0130 -#define BCM43xx_PCIECORE_REG_DATA 0x0134 -#define BCM43xx_PCIECORE_MDIO_CTL 0x0128 -#define BCM43xx_PCIECORE_MDIO_DATA 0x012C - -/* PCI-E registers. */ -#define BCM43xx_PCIE_TLP_WORKAROUND 0x0004 -#define BCM43xx_PCIE_DLLP_LINKCTL 0x0100 - -/* PCI-E MDIO bits. */ -#define BCM43xx_PCIE_MDIO_ST 0x40000000 -#define BCM43xx_PCIE_MDIO_WT 0x10000000 -#define BCM43xx_PCIE_MDIO_DEV 22 -#define BCM43xx_PCIE_MDIO_REG 18 -#define BCM43xx_PCIE_MDIO_TA 0x00020000 -#define BCM43xx_PCIE_MDIO_TC 0x0100 - -/* MDIO devices. */ -#define BCM43xx_MDIO_SERDES_RX 0x1F - -/* SERDES RX registers. */ -#define BCM43xx_SERDES_RXTIMER 0x2 -#define BCM43xx_SERDES_CDR 0x6 -#define BCM43xx_SERDES_CDR_BW 0x7 - -/* Chipcommon capabilities. */ -#define BCM43xx_CAPABILITIES_PCTL 0x00040000 -#define BCM43xx_CAPABILITIES_PLLMASK 0x00030000 -#define BCM43xx_CAPABILITIES_PLLSHIFT 16 -#define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700 -#define BCM43xx_CAPABILITIES_FLASHSHIFT 8 -#define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040 -#define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020 -#define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018 -#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3 -#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004 -#define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003 - -/* PowerControl */ -#define BCM43xx_PCTL_IN 0xB0 -#define BCM43xx_PCTL_OUT 0xB4 -#define BCM43xx_PCTL_OUTENABLE 0xB8 -#define BCM43xx_PCTL_XTAL_POWERUP 0x40 -#define BCM43xx_PCTL_PLL_POWERDOWN 0x80 - -/* PowerControl Clock Modes */ -#define BCM43xx_PCTL_CLK_FAST 0x00 -#define BCM43xx_PCTL_CLK_SLOW 0x01 -#define BCM43xx_PCTL_CLK_DYNAMIC 0x02 - -#define BCM43xx_PCTL_FORCE_SLOW 0x0800 -#define BCM43xx_PCTL_FORCE_PLL 0x1000 -#define BCM43xx_PCTL_DYN_XTAL 0x2000 - -/* COREIDs */ -#define BCM43xx_COREID_CHIPCOMMON 0x800 -#define BCM43xx_COREID_ILINE20 0x801 -#define BCM43xx_COREID_SDRAM 0x803 -#define BCM43xx_COREID_PCI 0x804 -#define BCM43xx_COREID_MIPS 0x805 -#define BCM43xx_COREID_ETHERNET 0x806 -#define BCM43xx_COREID_V90 0x807 -#define BCM43xx_COREID_USB11_HOSTDEV 0x80a -#define BCM43xx_COREID_IPSEC 0x80b -#define BCM43xx_COREID_PCMCIA 0x80d -#define BCM43xx_COREID_EXT_IF 0x80f -#define BCM43xx_COREID_80211 0x812 -#define BCM43xx_COREID_MIPS_3302 0x816 -#define BCM43xx_COREID_USB11_HOST 0x817 -#define BCM43xx_COREID_USB11_DEV 0x818 -#define BCM43xx_COREID_USB20_HOST 0x819 -#define BCM43xx_COREID_USB20_DEV 0x81a -#define BCM43xx_COREID_SDIO_HOST 0x81b -#define BCM43xx_COREID_PCIE 0x820 - -/* Core Information Registers */ -#define BCM43xx_CIR_BASE 0xf00 -#define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18) -#define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90) -#define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94) -#define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98) -#define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c) -#define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8) -#define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc) - -/* Mask to get the Backplane Flag Number from SBTPSFLAG. */ -#define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f - -/* SBIMCONFIGLOW values/masks. */ -#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007 -#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0 -#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070 -#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4 -#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000 -#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16 - -/* sbtmstatelow state flags */ -#define BCM43xx_SBTMSTATELOW_RESET 0x01 -#define BCM43xx_SBTMSTATELOW_REJECT 0x02 -#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 -#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 -#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000 - -/* sbtmstatehigh state flags */ -#define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001 -#define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004 -#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020 -#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000 -#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000 -#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 -#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000 -#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000 -#define BCM43xx_SBTMSTATEHIGH_BISTFAILED 0x40000000 -#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000 - -/* sbimstate flags */ -#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000 -#define BCM43xx_SBIMSTATE_TIMEOUT 0x40000 - -/* PHYVersioning */ -#define BCM43xx_PHYTYPE_A 0x00 -#define BCM43xx_PHYTYPE_B 0x01 -#define BCM43xx_PHYTYPE_G 0x02 - -/* PHYRegisters */ -#define BCM43xx_PHY_ILT_A_CTRL 0x0072 -#define BCM43xx_PHY_ILT_A_DATA1 0x0073 -#define BCM43xx_PHY_ILT_A_DATA2 0x0074 -#define BCM43xx_PHY_G_LO_CONTROL 0x0810 -#define BCM43xx_PHY_ILT_G_CTRL 0x0472 -#define BCM43xx_PHY_ILT_G_DATA1 0x0473 -#define BCM43xx_PHY_ILT_G_DATA2 0x0474 -#define BCM43xx_PHY_A_PCTL 0x007B -#define BCM43xx_PHY_G_PCTL 0x0029 -#define BCM43xx_PHY_A_CRS 0x0029 -#define BCM43xx_PHY_RADIO_BITFIELD 0x0401 -#define BCM43xx_PHY_G_CRS 0x0429 -#define BCM43xx_PHY_NRSSILT_CTRL 0x0803 -#define BCM43xx_PHY_NRSSILT_DATA 0x0804 - -/* RadioRegisters */ -#define BCM43xx_RADIOCTL_ID 0x01 - -/* StatusBitField */ -#define BCM43xx_SBF_MAC_ENABLED 0x00000001 -#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/ -#define BCM43xx_SBF_CORE_READY 0x00000004 -#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/ -#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/ -#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/ -#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000 -#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000 -#define BCM43xx_SBF_MODE_AP 0x00040000 -#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000 -#define BCM43xx_SBF_MODE_MONITOR 0x00400000 -#define BCM43xx_SBF_MODE_PROMISC 0x01000000 -#define BCM43xx_SBF_PS1 0x02000000 -#define BCM43xx_SBF_PS2 0x04000000 -#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000 -#define BCM43xx_SBF_TIME_UPDATE 0x10000000 -#define BCM43xx_SBF_MODE_G 0x80000000 - -/* Microcode */ -#define BCM43xx_UCODE_REVISION 0x0000 -#define BCM43xx_UCODE_PATCHLEVEL 0x0002 -#define BCM43xx_UCODE_DATE 0x0004 -#define BCM43xx_UCODE_TIME 0x0006 -#define BCM43xx_UCODE_STATUS 0x0040 - -/* MicrocodeFlagsBitfield (addr + lo-word values?)*/ -#define BCM43xx_UCODEFLAGS_OFFSET 0x005E - -#define BCM43xx_UCODEFLAG_AUTODIV 0x0001 -#define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002 -#define BCM43xx_UCODEFLAG_UNKBPHY 0x0004 -#define BCM43xx_UCODEFLAG_UNKGPHY 0x0020 -#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 -#define BCM43xx_UCODEFLAG_JAPAN 0x0080 - -/* Hardware Radio Enable masks */ -#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) -#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) - -/* Generic-Interrupt reasons. */ -#define BCM43xx_IRQ_READY (1 << 0) -#define BCM43xx_IRQ_BEACON (1 << 1) -#define BCM43xx_IRQ_PS (1 << 2) -#define BCM43xx_IRQ_REG124 (1 << 5) -#define BCM43xx_IRQ_PMQ (1 << 6) -#define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8) -#define BCM43xx_IRQ_XMIT_ERROR (1 << 11) -#define BCM43xx_IRQ_RX (1 << 15) -#define BCM43xx_IRQ_SCAN (1 << 16) -#define BCM43xx_IRQ_NOISE (1 << 18) -#define BCM43xx_IRQ_XMIT_STATUS (1 << 29) - -#define BCM43xx_IRQ_ALL 0xffffffff -#define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \ - BCM43xx_IRQ_REG124 | \ - BCM43xx_IRQ_PMQ | \ - BCM43xx_IRQ_XMIT_ERROR | \ - BCM43xx_IRQ_RX | \ - BCM43xx_IRQ_SCAN | \ - BCM43xx_IRQ_NOISE | \ - BCM43xx_IRQ_XMIT_STATUS) - - -/* Initial default iw_mode */ -#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA - -/* Bus type PCI. */ -#define BCM43xx_BUSTYPE_PCI 0 -/* Bus type Silicone Backplane Bus. */ -#define BCM43xx_BUSTYPE_SB 1 -/* Bus type PCMCIA. */ -#define BCM43xx_BUSTYPE_PCMCIA 2 - -/* Threshold values. */ -#define BCM43xx_MIN_RTS_THRESHOLD 1U -#define BCM43xx_MAX_RTS_THRESHOLD 2304U -#define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD - -#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7 -#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4 - -/* FIXME: the next line is a guess as to what the maximum RSSI value might be */ -#define RX_RSSI_MAX 60 - -/* Max size of a security key */ -#define BCM43xx_SEC_KEYSIZE 16 -/* Security algorithms. */ -enum { - BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ - BCM43xx_SEC_ALGO_WEP, - BCM43xx_SEC_ALGO_UNKNOWN, - BCM43xx_SEC_ALGO_AES, - BCM43xx_SEC_ALGO_WEP104, - BCM43xx_SEC_ALGO_TKIP, -}; - -#ifdef assert -# undef assert -#endif -#ifdef CONFIG_BCM43XX_DEBUG -#define assert(expr) \ - do { \ - if (unlikely(!(expr))) { \ - printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \ - #expr, __FILE__, __LINE__, __FUNCTION__); \ - } \ - } while (0) -#else -#define assert(expr) do { /* nothing */ } while (0) -#endif - -/* rate limited printk(). */ -#ifdef printkl -# undef printkl -#endif -#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) -/* rate limited printk() for debugging */ -#ifdef dprintkl -# undef dprintkl -#endif -#ifdef CONFIG_BCM43XX_DEBUG -# define dprintkl printkl -#else -# define dprintkl(f, x...) do { /* nothing */ } while (0) -#endif - -/* Helper macro for if branches. - * An if branch marked with this macro is only taken in DEBUG mode. - * Example: - * if (DEBUG_ONLY(foo == bar)) { - * do something - * } - * In DEBUG mode, the branch will be taken if (foo == bar). - * In non-DEBUG mode, the branch will never be taken. - */ -#ifdef DEBUG_ONLY -# undef DEBUG_ONLY -#endif -#ifdef CONFIG_BCM43XX_DEBUG -# define DEBUG_ONLY(x) (x) -#else -# define DEBUG_ONLY(x) 0 -#endif - -/* debugging printk() */ -#ifdef dprintk -# undef dprintk -#endif -#ifdef CONFIG_BCM43XX_DEBUG -# define dprintk(f, x...) do { printk(f ,##x); } while (0) -#else -# define dprintk(f, x...) do { /* nothing */ } while (0) -#endif - - -struct net_device; -struct pci_dev; -struct bcm43xx_dmaring; -struct bcm43xx_pioqueue; - -struct bcm43xx_initval { - __be16 offset; - __be16 size; - __be32 value; -} __attribute__((__packed__)); - -/* Values for bcm430x_sprominfo.locale */ -enum { - BCM43xx_LOCALE_WORLD = 0, - BCM43xx_LOCALE_THAILAND, - BCM43xx_LOCALE_ISRAEL, - BCM43xx_LOCALE_JORDAN, - BCM43xx_LOCALE_CHINA, - BCM43xx_LOCALE_JAPAN, - BCM43xx_LOCALE_USA_CANADA_ANZ, - BCM43xx_LOCALE_EUROPE, - BCM43xx_LOCALE_USA_LOW, - BCM43xx_LOCALE_JAPAN_HIGH, - BCM43xx_LOCALE_ALL, - BCM43xx_LOCALE_NONE, -}; - -#define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */ -struct bcm43xx_sprominfo { - u16 boardflags2; - u8 il0macaddr[6]; - u8 et0macaddr[6]; - u8 et1macaddr[6]; - u8 et0phyaddr:5; - u8 et1phyaddr:5; - u8 boardrev; - u8 locale:4; - u8 antennas_aphy:2; - u8 antennas_bgphy:2; - u16 pa0b0; - u16 pa0b1; - u16 pa0b2; - u8 wl0gpio0; - u8 wl0gpio1; - u8 wl0gpio2; - u8 wl0gpio3; - u8 maxpower_aphy; - u8 maxpower_bgphy; - u16 pa1b0; - u16 pa1b1; - u16 pa1b2; - u8 idle_tssi_tgt_aphy; - u8 idle_tssi_tgt_bgphy; - u16 boardflags; - u16 antennagain_aphy; - u16 antennagain_bgphy; -}; - -/* Value pair to measure the LocalOscillator. */ -struct bcm43xx_lopair { - s8 low; - s8 high; - u8 used:1; -}; -#define BCM43xx_LO_COUNT (14*4) - -struct bcm43xx_phyinfo { - /* Hardware Data */ - u8 analog; - u8 type; - u8 rev; - u16 antenna_diversity; - u16 savedpctlreg; - u16 minlowsig[2]; - u16 minlowsigpos[2]; - u8 connected:1, - calibrated:1, - is_locked:1, /* used in bcm43xx_phy_{un}lock() */ - dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */ - /* LO Measurement Data. - * Use bcm43xx_get_lopair() to get a value. - */ - struct bcm43xx_lopair *_lo_pairs; - - /* TSSI to dBm table in use */ - const s8 *tssi2dbm; - /* idle TSSI value */ - s8 idle_tssi; - - /* Values from bcm43xx_calc_loopback_gain() */ - u16 loopback_gain[2]; - - /* PHY lock for core.rev < 3 - * This lock is only used by bcm43xx_phy_{un}lock() - */ - spinlock_t lock; - - /* Firmware. */ - const struct firmware *ucode; - const struct firmware *pcm; - const struct firmware *initvals0; - const struct firmware *initvals1; -}; - - -struct bcm43xx_radioinfo { - u16 manufact; - u16 version; - u8 revision; - - /* Desired TX power in dBm Q5.2 */ - u16 txpower_desired; - /* TX Power control values. */ - union { - /* B/G PHY */ - struct { - u16 baseband_atten; - u16 radio_atten; - u16 txctl1; - u16 txctl2; - }; - /* A PHY */ - struct { - u16 txpwr_offset; - }; - }; - - /* Current Interference Mitigation mode */ - int interfmode; - /* Stack of saved values from the Interference Mitigation code. - * Each value in the stack is layed out as follows: - * bit 0-11: offset - * bit 12-15: register ID - * bit 16-32: value - * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT - */ -#define BCM43xx_INTERFSTACK_SIZE 26 - u32 interfstack[BCM43xx_INTERFSTACK_SIZE]; - - /* Saved values from the NRSSI Slope calculation */ - s16 nrssi[2]; - s32 nrssislope; - /* In memory nrssi lookup table. */ - s8 nrssi_lt[64]; - - /* current channel */ - u8 channel; - u8 initial_channel; - - u16 lofcal; - - u16 initval; - - u8 enabled:1; - /* ACI (adjacent channel interference) flags. */ - u8 aci_enable:1, - aci_wlan_automatic:1, - aci_hw_rssi:1; -}; - -/* Data structures for DMA transmission, per 80211 core. */ -struct bcm43xx_dma { - struct bcm43xx_dmaring *tx_ring0; - struct bcm43xx_dmaring *tx_ring1; - struct bcm43xx_dmaring *tx_ring2; - struct bcm43xx_dmaring *tx_ring3; - struct bcm43xx_dmaring *tx_ring4; - struct bcm43xx_dmaring *tx_ring5; - - struct bcm43xx_dmaring *rx_ring0; - struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */ -}; - -/* Data structures for PIO transmission, per 80211 core. */ -struct bcm43xx_pio { - struct bcm43xx_pioqueue *queue0; - struct bcm43xx_pioqueue *queue1; - struct bcm43xx_pioqueue *queue2; - struct bcm43xx_pioqueue *queue3; -}; - -#define BCM43xx_MAX_80211_CORES 2 - -/* Generic information about a core. */ -struct bcm43xx_coreinfo { - u8 available:1, - enabled:1, - initialized:1; - /** core_rev revision number */ - u8 rev; - /** Index number for _switch_core() */ - u8 index; - /** core_id ID number */ - u16 id; - /** Core-specific data. */ - void *priv; -}; - -/* Additional information for each 80211 core. */ -struct bcm43xx_coreinfo_80211 { - /* PHY device. */ - struct bcm43xx_phyinfo phy; - /* Radio device. */ - struct bcm43xx_radioinfo radio; - union { - /* DMA context. */ - struct bcm43xx_dma dma; - /* PIO context. */ - struct bcm43xx_pio pio; - }; -}; - -/* Context information for a noise calculation (Link Quality). */ -struct bcm43xx_noise_calculation { - struct bcm43xx_coreinfo *core_at_start; - u8 channel_at_start; - u8 calculation_running:1; - u8 nr_samples; - s8 samples[8][4]; -}; - -struct bcm43xx_stats { - u8 noise; - struct iw_statistics wstats; - /* Store the last TX/RX times here for updating the leds. */ - unsigned long last_tx; - unsigned long last_rx; -}; - -struct bcm43xx_key { - u8 enabled:1; - u8 algorithm; -}; - -/* Driver initialization status. */ -enum { - BCM43xx_STAT_UNINIT, /* Uninitialized. */ - BCM43xx_STAT_INITIALIZING, /* init_board() in progress. */ - BCM43xx_STAT_INITIALIZED, /* Fully operational. */ - BCM43xx_STAT_SHUTTINGDOWN, /* free_board() in progress. */ - BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ -}; -#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) -#define bcm43xx_set_status(bcm, stat) do { \ - atomic_set(&(bcm)->init_status, (stat)); \ - smp_wmb(); \ - } while (0) - -/* *** THEORY OF LOCKING *** - * - * We have two different locks in the bcm43xx driver. - * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private - * and the device registers. This mutex does _not_ protect - * against concurrency from the IRQ handler. - * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. - * - * Please note that, if you only take the irq_lock, you are not protected - * against concurrency from the periodic work handlers. - * Most times you want to take _both_ locks. - */ - -struct bcm43xx_private { - struct ieee80211_device *ieee; - struct ieee80211softmac_device *softmac; - - struct net_device *net_dev; - struct pci_dev *pci_dev; - unsigned int irq; - - void __iomem *mmio_addr; - - spinlock_t irq_lock; - struct mutex mutex; - - /* Driver initialization status BCM43xx_STAT_*** */ - atomic_t init_status; - - u16 was_initialized:1, /* for PCI suspend/resume. */ - __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ - bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ - reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ - short_preamble:1, /* TRUE, if short preamble is enabled. */ - firmware_norelease:1, /* Do not release the firmware. Used on suspend. */ - radio_hw_enable:1; /* TRUE if radio is hardware enabled */ - - struct bcm43xx_stats stats; - - /* Bus type we are connected to. - * This is currently always BCM43xx_BUSTYPE_PCI - */ - u8 bustype; - u64 dma_mask; - - u16 board_vendor; - u16 board_type; - u16 board_revision; - - u16 chip_id; - u8 chip_rev; - u8 chip_package; - - struct bcm43xx_sprominfo sprom; -#define BCM43xx_NR_LEDS 4 - struct bcm43xx_led leds[BCM43xx_NR_LEDS]; - spinlock_t leds_lock; - - /* The currently active core. */ - struct bcm43xx_coreinfo *current_core; - struct bcm43xx_coreinfo *active_80211_core; - /* coreinfo structs for all possible cores follow. - * Note that a core might not exist. - * So check the coreinfo flags before using it. - */ - struct bcm43xx_coreinfo core_chipcommon; - struct bcm43xx_coreinfo core_pci; - struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; - /* Additional information, specific to the 80211 cores. */ - struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; - /* Number of available 80211 cores. */ - int nr_80211_available; - - u32 chipcommon_capabilities; - - /* Reason code of the last interrupt. */ - u32 irq_reason; - u32 dma_reason[6]; - /* saved irq enable/disable state bitfield. */ - u32 irq_savedstate; - /* Link Quality calculation context. */ - struct bcm43xx_noise_calculation noisecalc; - /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ - int mac_suspended; - - /* Threshold values. */ - //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. - u32 rts_threshold; - - /* Interrupt Service Routine tasklet (bottom-half) */ - struct tasklet_struct isr_tasklet; - - /* Periodic tasks */ - struct delayed_work periodic_work; - unsigned int periodic_state; - - struct work_struct restart_work; - - /* Informational stuff. */ - char nick[IW_ESSID_MAX_SIZE + 1]; - - /* encryption/decryption */ - u16 security_offset; - struct bcm43xx_key key[54]; - u8 default_key_idx; - - /* Random Number Generator. */ - struct hwrng rng; - char rng_name[20 + 1]; - - /* Debugging stuff follows. */ -#ifdef CONFIG_BCM43XX_DEBUG - struct bcm43xx_dfsentry *dfsentry; -#endif -}; - - -static inline -struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) -{ - return ieee80211softmac_priv(dev); -} - -struct device; - -static inline -struct bcm43xx_private * dev_to_bcm(struct device *dev) -{ - struct net_device *net_dev; - struct bcm43xx_private *bcm; - - net_dev = dev_get_drvdata(dev); - bcm = bcm43xx_priv(net_dev); - - return bcm; -} - - -/* Helper function, which returns a boolean. - * TRUE, if PIO is used; FALSE, if DMA is used. - */ -#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) -static inline -int bcm43xx_using_pio(struct bcm43xx_private *bcm) -{ - return bcm->__using_pio; -} -#elif defined(CONFIG_BCM43XX_DMA) -static inline -int bcm43xx_using_pio(struct bcm43xx_private *bcm) -{ - return 0; -} -#elif defined(CONFIG_BCM43XX_PIO) -static inline -int bcm43xx_using_pio(struct bcm43xx_private *bcm) -{ - return 1; -} -#else -# error "Using neither DMA nor PIO? Confused..." -#endif - -/* Helper functions to access data structures private to the 80211 cores. - * Note that we _must_ have an 80211 core mapped when calling - * any of these functions. - */ -static inline -struct bcm43xx_coreinfo_80211 * -bcm43xx_current_80211_priv(struct bcm43xx_private *bcm) -{ - assert(bcm->current_core->id == BCM43xx_COREID_80211); - return bcm->current_core->priv; -} -static inline -struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) -{ - assert(bcm43xx_using_pio(bcm)); - return &(bcm43xx_current_80211_priv(bcm)->pio); -} -static inline -struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) -{ - assert(!bcm43xx_using_pio(bcm)); - return &(bcm43xx_current_80211_priv(bcm)->dma); -} -static inline -struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) -{ - return &(bcm43xx_current_80211_priv(bcm)->phy); -} -static inline -struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) -{ - return &(bcm43xx_current_80211_priv(bcm)->radio); -} - - -static inline -struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, - u16 radio_attenuation, - u16 baseband_attenuation) -{ - return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2)); -} - - -static inline -u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) -{ - return ioread16(bcm->mmio_addr + offset); -} - -static inline -void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) -{ - iowrite16(value, bcm->mmio_addr + offset); -} - -static inline -u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) -{ - return ioread32(bcm->mmio_addr + offset); -} - -static inline -void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) -{ - iowrite32(value, bcm->mmio_addr + offset); -} - -static inline -int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) -{ - return pci_read_config_word(bcm->pci_dev, offset, value); -} - -static inline -int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) -{ - return pci_read_config_dword(bcm->pci_dev, offset, value); -} - -static inline -int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) -{ - return pci_write_config_word(bcm->pci_dev, offset, value); -} - -static inline -int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) -{ - return pci_write_config_dword(bcm->pci_dev, offset, value); -} - -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max) \ - ({ \ - typeof(value) __value = (value); \ - typeof(value) __min = (min); \ - typeof(value) __max = (max); \ - if (__value < __min) \ - __value = __min; \ - else if (__value > __max) \ - __value = __max; \ - __value; \ - }) - -#endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c deleted file mode 100644 index 76e9dd843fa..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - debugfs driver debugging code - - Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - - - -#include <linux/fs.h> -#include <linux/debugfs.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/pci.h> -#include <asm/io.h> - -#include "bcm43xx.h" -#include "bcm43xx_main.h" -#include "bcm43xx_debugfs.h" -#include "bcm43xx_dma.h" -#include "bcm43xx_pio.h" -#include "bcm43xx_xmit.h" - -#define REALLY_BIG_BUFFER_SIZE (1024*256) - -static struct bcm43xx_debugfs fs; -static char really_big_buffer[REALLY_BIG_BUFFER_SIZE]; -static DECLARE_MUTEX(big_buffer_sem); - - -static ssize_t write_file_dummy(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return count; -} - -static int open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x) - -static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - const size_t len = REALLY_BIG_BUFFER_SIZE; - - struct bcm43xx_private *bcm = file->private_data; - char *buf = really_big_buffer; - size_t pos = 0; - ssize_t res; - struct net_device *net_dev; - struct pci_dev *pci_dev; - unsigned long flags; - u16 tmp16; - int i; - - down(&big_buffer_sem); - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { - fappend("Board not initialized.\n"); - goto out; - } - net_dev = bcm->net_dev; - pci_dev = bcm->pci_dev; - - /* This is where the information is written to the "devinfo" file */ - fappend("*** %s devinfo ***\n", net_dev->name); - fappend("vendor: 0x%04x device: 0x%04x\n", - pci_dev->vendor, pci_dev->device); - fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", - pci_dev->subsystem_vendor, pci_dev->subsystem_device); - fappend("IRQ: %d\n", bcm->irq); - fappend("mmio_addr: 0x%p\n", bcm->mmio_addr); - fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); - if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) - fappend("Radio disabled by hardware!\n"); - if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4))) - fappend("Radio disabled by hardware!\n"); - fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor, - bcm->board_type); - - fappend("\nCores:\n"); -#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ - "rev: 0x%02x, index: 0x%02x\n", \ - (info).available \ - ? "available" : "nonavailable", \ - (info).enabled \ - ? "enabled" : "disabled", \ - (info).id, (info).rev, (info).index) - fappend_core("CHIPCOMMON", bcm->core_chipcommon); - fappend_core("PCI", bcm->core_pci); - fappend_core("first 80211", bcm->core_80211[0]); - fappend_core("second 80211", bcm->core_80211[1]); -#undef fappend_core - tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - fappend("LEDs: "); - for (i = 0; i < BCM43xx_NR_LEDS; i++) - fappend("%d ", !!(tmp16 & (1 << i))); - fappend("\n"); - -out: - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - up(&big_buffer_sem); - return res; -} - -static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - const size_t len = REALLY_BIG_BUFFER_SIZE; - - char *buf = really_big_buffer; - size_t pos = 0; - ssize_t res; - - down(&big_buffer_sem); - - /* This is where the information is written to the "driver" file */ - fappend(KBUILD_MODNAME " driver\n"); - fappend("Compiled at: %s %s\n", __DATE__, __TIME__); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - up(&big_buffer_sem); - return res; -} - -static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - const size_t len = REALLY_BIG_BUFFER_SIZE; - - struct bcm43xx_private *bcm = file->private_data; - char *buf = really_big_buffer; - size_t pos = 0; - ssize_t res; - unsigned long flags; - - down(&big_buffer_sem); - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { - fappend("Board not initialized.\n"); - goto out; - } - - /* This is where the information is written to the "sprom_dump" file */ - fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); - -out: - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - up(&big_buffer_sem); - return res; -} - -static ssize_t tsf_read_file(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - const size_t len = REALLY_BIG_BUFFER_SIZE; - - struct bcm43xx_private *bcm = file->private_data; - char *buf = really_big_buffer; - size_t pos = 0; - ssize_t res; - unsigned long flags; - u64 tsf; - - down(&big_buffer_sem); - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { - fappend("Board not initialized.\n"); - goto out; - } - bcm43xx_tsf_read(bcm, &tsf); - fappend("0x%08x%08x\n", - (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(tsf & 0xFFFFFFFFULL)); - -out: - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - up(&big_buffer_sem); - return res; -} - -static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct bcm43xx_private *bcm = file->private_data; - char *buf = really_big_buffer; - ssize_t buf_size; - ssize_t res; - unsigned long flags; - unsigned long long tsf; - - buf_size = min(count, sizeof (really_big_buffer) - 1); - down(&big_buffer_sem); - if (copy_from_user(buf, user_buf, buf_size)) { - res = -EFAULT; - goto out_up; - } - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { - printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); - res = -EFAULT; - goto out_unlock; - } - if (sscanf(buf, "%lli", &tsf) != 1) { - printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n"); - res = -EINVAL; - goto out_unlock; - } - bcm43xx_tsf_write(bcm, tsf); - mmiowb(); - res = buf_size; - -out_unlock: - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); -out_up: - up(&big_buffer_sem); - return res; -} - -static ssize_t txstat_read_file(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - const size_t len = REALLY_BIG_BUFFER_SIZE; - - struct bcm43xx_private *bcm = file->private_data; - char *buf = really_big_buffer; - size_t pos = 0; - ssize_t res; - unsigned long flags; - struct bcm43xx_dfsentry *e; - struct bcm43xx_xmitstatus *status; - int i, cnt, j = 0; - - down(&big_buffer_sem); - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - - fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", - BCM43xx_NR_LOGGED_XMITSTATUS); - e = bcm->dfsentry; - if (e->xmitstatus_printing == 0) { - /* At the beginning, make a copy of all data to avoid - * concurrency, as this function is called multiple - * times for big logs. Without copying, the data might - * change between reads. This would result in total trash. - */ - e->xmitstatus_printing = 1; - e->saved_xmitstatus_ptr = e->xmitstatus_ptr; - e->saved_xmitstatus_cnt = e->xmitstatus_cnt; - memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer, - BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer))); - } - i = e->saved_xmitstatus_ptr - 1; - if (i < 0) - i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; - cnt = e->saved_xmitstatus_cnt; - while (cnt) { - status = e->xmitstatus_print_buffer + i; - fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, " - "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, " - "unk: 0x%04x\n", j, - status->cookie, status->flags, - status->cnt1, status->cnt2, status->seq, - status->unknown); - j++; - cnt--; - i--; - if (i < 0) - i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; - } - - spin_unlock_irqrestore(&bcm->irq_lock, flags); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (*ppos == pos) { - /* Done. Drop the copied data. */ - e->xmitstatus_printing = 0; - } - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - up(&big_buffer_sem); - return res; -} - -static ssize_t restart_write_file(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct bcm43xx_private *bcm = file->private_data; - char *buf = really_big_buffer; - ssize_t buf_size; - ssize_t res; - unsigned long flags; - - buf_size = min(count, sizeof (really_big_buffer) - 1); - down(&big_buffer_sem); - if (copy_from_user(buf, user_buf, buf_size)) { - res = -EFAULT; - goto out_up; - } - mutex_lock(&(bcm)->mutex); - spin_lock_irqsave(&(bcm)->irq_lock, flags); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { - printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); - res = -EFAULT; - goto out_unlock; - } - if (count > 0 && buf[0] == '1') { - bcm43xx_controller_restart(bcm, "manually restarted"); - res = count; - } else - res = -EINVAL; - -out_unlock: - spin_unlock_irqrestore(&(bcm)->irq_lock, flags); - mutex_unlock(&(bcm)->mutex); -out_up: - up(&big_buffer_sem); - return res; -} - -#undef fappend - - -static const struct file_operations devinfo_fops = { - .read = devinfo_read_file, - .write = write_file_dummy, - .open = open_file_generic, -}; - -static const struct file_operations spromdump_fops = { - .read = spromdump_read_file, - .write = write_file_dummy, - .open = open_file_generic, -}; - -static const struct file_operations drvinfo_fops = { - .read = drvinfo_read_file, - .write = write_file_dummy, - .open = open_file_generic, -}; - -static const struct file_operations tsf_fops = { - .read = tsf_read_file, - .write = tsf_write_file, - .open = open_file_generic, -}; - -static const struct file_operations txstat_fops = { - .read = txstat_read_file, - .write = write_file_dummy, - .open = open_file_generic, -}; - -static const struct file_operations restart_fops = { - .write = restart_write_file, - .open = open_file_generic, -}; - - -void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) -{ - struct bcm43xx_dfsentry *e; - char devdir[IFNAMSIZ]; - - assert(bcm); - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) { - printk(KERN_ERR PFX "out of memory\n"); - return; - } - e->bcm = bcm; - e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS - * sizeof(*(e->xmitstatus_buffer)), - GFP_KERNEL); - if (!e->xmitstatus_buffer) { - printk(KERN_ERR PFX "out of memory\n"); - kfree(e); - return; - } - e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS - * sizeof(*(e->xmitstatus_buffer)), - GFP_KERNEL); - if (!e->xmitstatus_print_buffer) { - printk(KERN_ERR PFX "out of memory\n"); - kfree(e); - return; - } - - - bcm->dfsentry = e; - - strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir)); - e->subdir = debugfs_create_dir(devdir, fs.root); - e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir, - bcm, &devinfo_fops); - if (!e->dentry_devinfo) - printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir); - e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir, - bcm, &spromdump_fops); - if (!e->dentry_spromdump) - printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir); - e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, - bcm, &tsf_fops); - if (!e->dentry_tsf) - printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); - e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, - bcm, &txstat_fops); - if (!e->dentry_txstat) - printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); - e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir, - bcm, &restart_fops); - if (!e->dentry_restart) - printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir); -} - -void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) -{ - struct bcm43xx_dfsentry *e; - - if (!bcm) - return; - - e = bcm->dfsentry; - assert(e); - debugfs_remove(e->dentry_spromdump); - debugfs_remove(e->dentry_devinfo); - debugfs_remove(e->dentry_tsf); - debugfs_remove(e->dentry_txstat); - debugfs_remove(e->dentry_restart); - debugfs_remove(e->subdir); - kfree(e->xmitstatus_buffer); - kfree(e->xmitstatus_print_buffer); - kfree(e); -} - -void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) -{ - struct bcm43xx_dfsentry *e; - struct bcm43xx_xmitstatus *savedstatus; - - /* This is protected by bcm->_lock */ - e = bcm->dfsentry; - assert(e); - savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; - memcpy(savedstatus, status, sizeof(*status)); - e->xmitstatus_ptr++; - if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS) - e->xmitstatus_ptr = 0; - if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS) - e->xmitstatus_cnt++; -} - -void bcm43xx_debugfs_init(void) -{ - memset(&fs, 0, sizeof(fs)); - fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!fs.root) - printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); - fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); - if (!fs.dentry_driverinfo) - printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); -} - -void bcm43xx_debugfs_exit(void) -{ - debugfs_remove(fs.dentry_driverinfo); - debugfs_remove(fs.root); -} - -void bcm43xx_printk_dump(const char *data, - size_t size, - const char *description) -{ - size_t i; - char c; - - printk(KERN_INFO PFX "Data dump (%s, %zd bytes):", - description, size); - for (i = 0; i < size; i++) { - c = data[i]; - if (i % 8 == 0) - printk("\n" KERN_INFO PFX "0x%08zx: 0x%02x, ", i, c & 0xff); - else - printk("0x%02x, ", c & 0xff); - } - printk("\n"); -} - -void bcm43xx_printk_bitdump(const unsigned char *data, - size_t bytes, int msb_to_lsb, - const char *description) -{ - size_t i; - int j; - const unsigned char *d; - - printk(KERN_INFO PFX "*** Bitdump (%s, %zd bytes, %s) ***", - description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); - for (i = 0; i < bytes; i++) { - d = data + i; - if (i % 8 == 0) - printk("\n" KERN_INFO PFX "0x%08zx: ", i); - if (msb_to_lsb) { - for (j = 7; j >= 0; j--) { - if (*d & (1 << j)) - printk("1"); - else - printk("0"); - } - } else { - for (j = 0; j < 8; j++) { - if (*d & (1 << j)) - printk("1"); - else - printk("0"); - } - } - printk(" "); - } - printk("\n"); -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h deleted file mode 100644 index a40d1af3554..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef BCM43xx_DEBUGFS_H_ -#define BCM43xx_DEBUGFS_H_ - -struct bcm43xx_private; -struct bcm43xx_xmitstatus; - -#ifdef CONFIG_BCM43XX_DEBUG - -#include <linux/list.h> -#include <asm/semaphore.h> - -struct dentry; - -/* limited by the size of the "really_big_buffer" */ -#define BCM43xx_NR_LOGGED_XMITSTATUS 100 - -struct bcm43xx_dfsentry { - struct dentry *subdir; - struct dentry *dentry_devinfo; - struct dentry *dentry_spromdump; - struct dentry *dentry_tsf; - struct dentry *dentry_txstat; - struct dentry *dentry_restart; - - struct bcm43xx_private *bcm; - - /* saved xmitstatus. */ - struct bcm43xx_xmitstatus *xmitstatus_buffer; - int xmitstatus_ptr; - int xmitstatus_cnt; - /* We need a seperate buffer while printing to avoid - * concurrency issues. (New xmitstatus can arrive - * while we are printing). - */ - struct bcm43xx_xmitstatus *xmitstatus_print_buffer; - int saved_xmitstatus_ptr; - int saved_xmitstatus_cnt; - int xmitstatus_printing; -}; - -struct bcm43xx_debugfs { - struct dentry *root; - struct dentry *dentry_driverinfo; -}; - -void bcm43xx_debugfs_init(void); -void bcm43xx_debugfs_exit(void); -void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm); -void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm); -void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status); - -/* Debug helper: Dump binary data through printk. */ -void bcm43xx_printk_dump(const char *data, - size_t size, - const char *description); -/* Debug helper: Dump bitwise binary data through printk. */ -void bcm43xx_printk_bitdump(const unsigned char *data, - size_t bytes, int msb_to_lsb, - const char *description); -#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \ - do { \ - bcm43xx_printk_bitdump((const unsigned char *)(pointer), \ - sizeof(*(pointer)), \ - (msb_to_lsb), \ - (description)); \ - } while (0) - -#else /* CONFIG_BCM43XX_DEBUG*/ - -static inline -void bcm43xx_debugfs_init(void) { } -static inline -void bcm43xx_debugfs_exit(void) { } -static inline -void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { } -static inline -void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { } -static inline -void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) { } - -static inline -void bcm43xx_printk_dump(const char *data, - size_t size, - const char *description) -{ -} -static inline -void bcm43xx_printk_bitdump(const unsigned char *data, - size_t bytes, int msb_to_lsb, - const char *description) -{ -} -#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0) - -#endif /* CONFIG_BCM43XX_DEBUG*/ - -/* Ugly helper macros to make incomplete code more verbose on runtime */ -#ifdef TODO -# undef TODO -#endif -#define TODO() \ - do { \ - printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \ - __FUNCTION__, __FILE__, __LINE__); \ - } while (0) - -#ifdef FIXME -# undef FIXME -#endif -#define FIXME() \ - do { \ - printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \ - __FUNCTION__, __FILE__, __LINE__); \ - } while (0) - -#endif /* BCM43xx_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c deleted file mode 100644 index 1f7731fcfbd..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - DMA ringbuffer and descriptor allocation/management - - Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de> - - Some code in this file is derived from the b44.c driver - Copyright (C) 2002 David S. Miller - Copyright (C) Pekka Pietikainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx.h" -#include "bcm43xx_dma.h" -#include "bcm43xx_main.h" -#include "bcm43xx_debugfs.h" -#include "bcm43xx_power.h" -#include "bcm43xx_xmit.h" - -#include <linux/dma-mapping.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/skbuff.h> - - -static inline int free_slots(struct bcm43xx_dmaring *ring) -{ - return (ring->nr_slots - ring->used_slots); -} - -static inline int next_slot(struct bcm43xx_dmaring *ring, int slot) -{ - assert(slot >= -1 && slot <= ring->nr_slots - 1); - if (slot == ring->nr_slots - 1) - return 0; - return slot + 1; -} - -static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot) -{ - assert(slot >= 0 && slot <= ring->nr_slots - 1); - if (slot == 0) - return ring->nr_slots - 1; - return slot - 1; -} - -/* Request a slot for usage. */ -static inline -int request_slot(struct bcm43xx_dmaring *ring) -{ - int slot; - - assert(ring->tx); - assert(!ring->suspended); - assert(free_slots(ring) != 0); - - slot = next_slot(ring, ring->current_slot); - ring->current_slot = slot; - ring->used_slots++; - - /* Check the number of available slots and suspend TX, - * if we are running low on free slots. - */ - if (unlikely(free_slots(ring) < ring->suspend_mark)) { - netif_stop_queue(ring->bcm->net_dev); - ring->suspended = 1; - } -#ifdef CONFIG_BCM43XX_DEBUG - if (ring->used_slots > ring->max_used_slots) - ring->max_used_slots = ring->used_slots; -#endif /* CONFIG_BCM43XX_DEBUG*/ - - return slot; -} - -/* Return a slot to the free slots. */ -static inline -void return_slot(struct bcm43xx_dmaring *ring, int slot) -{ - assert(ring->tx); - - ring->used_slots--; - - /* Check if TX is suspended and check if we have - * enough free slots to resume it again. - */ - if (unlikely(ring->suspended)) { - if (free_slots(ring) >= ring->resume_mark) { - ring->suspended = 0; - netif_wake_queue(ring->bcm->net_dev); - } - } -} - -u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx) -{ - static const u16 map64[] = { - BCM43xx_MMIO_DMA64_BASE0, - BCM43xx_MMIO_DMA64_BASE1, - BCM43xx_MMIO_DMA64_BASE2, - BCM43xx_MMIO_DMA64_BASE3, - BCM43xx_MMIO_DMA64_BASE4, - BCM43xx_MMIO_DMA64_BASE5, - }; - static const u16 map32[] = { - BCM43xx_MMIO_DMA32_BASE0, - BCM43xx_MMIO_DMA32_BASE1, - BCM43xx_MMIO_DMA32_BASE2, - BCM43xx_MMIO_DMA32_BASE3, - BCM43xx_MMIO_DMA32_BASE4, - BCM43xx_MMIO_DMA32_BASE5, - }; - - if (dma64bit) { - assert(controller_idx >= 0 && - controller_idx < ARRAY_SIZE(map64)); - return map64[controller_idx]; - } - assert(controller_idx >= 0 && - controller_idx < ARRAY_SIZE(map32)); - return map32[controller_idx]; -} - -static inline -dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, - unsigned char *buf, - size_t len, - int tx) -{ - dma_addr_t dmaaddr; - int direction = PCI_DMA_FROMDEVICE; - - if (tx) - direction = PCI_DMA_TODEVICE; - - dmaaddr = pci_map_single(ring->bcm->pci_dev, - buf, len, - direction); - - return dmaaddr; -} - -static inline -void unmap_descbuffer(struct bcm43xx_dmaring *ring, - dma_addr_t addr, - size_t len, - int tx) -{ - if (tx) { - pci_unmap_single(ring->bcm->pci_dev, - addr, len, - PCI_DMA_TODEVICE); - } else { - pci_unmap_single(ring->bcm->pci_dev, - addr, len, - PCI_DMA_FROMDEVICE); - } -} - -static inline -void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, - dma_addr_t addr, - size_t len) -{ - assert(!ring->tx); - - pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, - addr, len, PCI_DMA_FROMDEVICE); -} - -static inline -void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, - dma_addr_t addr, - size_t len) -{ - assert(!ring->tx); - - pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, - addr, len, PCI_DMA_TODEVICE); -} - -/* Unmap and free a descriptor buffer. */ -static inline -void free_descriptor_buffer(struct bcm43xx_dmaring *ring, - struct bcm43xx_dmadesc_meta *meta, - int irq_context) -{ - assert(meta->skb); - if (irq_context) - dev_kfree_skb_irq(meta->skb); - else - dev_kfree_skb(meta->skb); - meta->skb = NULL; -} - -static int alloc_ringmemory(struct bcm43xx_dmaring *ring) -{ - ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE, - &(ring->dmabase)); - if (!ring->descbase) { - /* Allocation may have failed due to pci_alloc_consistent - insisting on use of GFP_DMA, which is more restrictive - than necessary... */ - struct dma_desc *rx_ring; - dma_addr_t rx_ring_dma; - - rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL); - if (!rx_ring) - goto out_err; - - rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring, - BCM43xx_DMA_RINGMEMSIZE, - PCI_DMA_BIDIRECTIONAL); - - if (pci_dma_mapping_error(rx_ring_dma) || - rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { - /* Sigh... */ - if (!pci_dma_mapping_error(rx_ring_dma)) - pci_unmap_single(ring->bcm->pci_dev, - rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, - PCI_DMA_BIDIRECTIONAL); - rx_ring_dma = pci_map_single(ring->bcm->pci_dev, - rx_ring, BCM43xx_DMA_RINGMEMSIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(rx_ring_dma) || - rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { - assert(0); - if (!pci_dma_mapping_error(rx_ring_dma)) - pci_unmap_single(ring->bcm->pci_dev, - rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, - PCI_DMA_BIDIRECTIONAL); - goto out_err; - } - } - - ring->descbase = rx_ring; - ring->dmabase = rx_ring_dma; - } - memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE); - - return 0; -out_err: - printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); - return -ENOMEM; -} - -static void free_ringmemory(struct bcm43xx_dmaring *ring) -{ - struct device *dev = &(ring->bcm->pci_dev->dev); - - dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, - ring->descbase, ring->dmabase); -} - -/* Reset the RX DMA channel */ -int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, - u16 mmio_base, int dma64) -{ - int i; - u32 value; - u16 offset; - - offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL; - bcm43xx_write32(bcm, mmio_base + offset, 0); - for (i = 0; i < 1000; i++) { - offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS; - value = bcm43xx_read32(bcm, mmio_base + offset); - if (dma64) { - value &= BCM43xx_DMA64_RXSTAT; - if (value == BCM43xx_DMA64_RXSTAT_DISABLED) { - i = -1; - break; - } - } else { - value &= BCM43xx_DMA32_RXSTATE; - if (value == BCM43xx_DMA32_RXSTAT_DISABLED) { - i = -1; - break; - } - } - udelay(10); - } - if (i != -1) { - printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n"); - return -ENODEV; - } - - return 0; -} - -/* Reset the RX DMA channel */ -int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, - u16 mmio_base, int dma64) -{ - int i; - u32 value; - u16 offset; - - for (i = 0; i < 1000; i++) { - offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS; - value = bcm43xx_read32(bcm, mmio_base + offset); - if (dma64) { - value &= BCM43xx_DMA64_TXSTAT; - if (value == BCM43xx_DMA64_TXSTAT_DISABLED || - value == BCM43xx_DMA64_TXSTAT_IDLEWAIT || - value == BCM43xx_DMA64_TXSTAT_STOPPED) - break; - } else { - value &= BCM43xx_DMA32_TXSTATE; - if (value == BCM43xx_DMA32_TXSTAT_DISABLED || - value == BCM43xx_DMA32_TXSTAT_IDLEWAIT || - value == BCM43xx_DMA32_TXSTAT_STOPPED) - break; - } - udelay(10); - } - offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL; - bcm43xx_write32(bcm, mmio_base + offset, 0); - for (i = 0; i < 1000; i++) { - offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS; - value = bcm43xx_read32(bcm, mmio_base + offset); - if (dma64) { - value &= BCM43xx_DMA64_TXSTAT; - if (value == BCM43xx_DMA64_TXSTAT_DISABLED) { - i = -1; - break; - } - } else { - value &= BCM43xx_DMA32_TXSTATE; - if (value == BCM43xx_DMA32_TXSTAT_DISABLED) { - i = -1; - break; - } - } - udelay(10); - } - if (i != -1) { - printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n"); - return -ENODEV; - } - /* ensure the reset is completed. */ - udelay(300); - - return 0; -} - -static void fill_descriptor(struct bcm43xx_dmaring *ring, - struct bcm43xx_dmadesc_generic *desc, - dma_addr_t dmaaddr, - u16 bufsize, - int start, int end, int irq) -{ - int slot; - - slot = bcm43xx_dma_desc2idx(ring, desc); - assert(slot >= 0 && slot < ring->nr_slots); - - if (ring->dma64) { - u32 ctl0 = 0, ctl1 = 0; - u32 addrlo, addrhi; - u32 addrext; - - addrlo = (u32)(dmaaddr & 0xFFFFFFFF); - addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING); - addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT); - addrhi |= ring->routing; - if (slot == ring->nr_slots - 1) - ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND; - if (start) - ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART; - if (end) - ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND; - if (irq) - ctl0 |= BCM43xx_DMA64_DCTL0_IRQ; - ctl1 |= (bufsize - ring->frameoffset) - & BCM43xx_DMA64_DCTL1_BYTECNT; - ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT) - & BCM43xx_DMA64_DCTL1_ADDREXT_MASK; - - desc->dma64.control0 = cpu_to_le32(ctl0); - desc->dma64.control1 = cpu_to_le32(ctl1); - desc->dma64.address_low = cpu_to_le32(addrlo); - desc->dma64.address_high = cpu_to_le32(addrhi); - } else { - u32 ctl; - u32 addr; - u32 addrext; - - addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING); - addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING) - >> BCM43xx_DMA32_ROUTING_SHIFT; - addr |= ring->routing; - ctl = (bufsize - ring->frameoffset) - & BCM43xx_DMA32_DCTL_BYTECNT; - if (slot == ring->nr_slots - 1) - ctl |= BCM43xx_DMA32_DCTL_DTABLEEND; - if (start) - ctl |= BCM43xx_DMA32_DCTL_FRAMESTART; - if (end) - ctl |= BCM43xx_DMA32_DCTL_FRAMEEND; - if (irq) - ctl |= BCM43xx_DMA32_DCTL_IRQ; - ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT) - & BCM43xx_DMA32_DCTL_ADDREXT_MASK; - - desc->dma32.control = cpu_to_le32(ctl); - desc->dma32.address = cpu_to_le32(addr); - } -} - -static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, - struct bcm43xx_dmadesc_generic *desc, - struct bcm43xx_dmadesc_meta *meta, - gfp_t gfp_flags) -{ - struct bcm43xx_rxhdr *rxhdr; - struct bcm43xx_hwxmitstatus *xmitstat; - dma_addr_t dmaaddr; - struct sk_buff *skb; - - assert(!ring->tx); - - skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); - if (unlikely(!skb)) - return -ENOMEM; - dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); - /* This hardware bug work-around adapted from the b44 driver. - The chip may be unable to do PCI DMA to/from anything above 1GB */ - if (pci_dma_mapping_error(dmaaddr) || - dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { - /* This one has 30-bit addressing... */ - if (!pci_dma_mapping_error(dmaaddr)) - pci_unmap_single(ring->bcm->pci_dev, - dmaaddr, ring->rx_buffersize, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(skb); - skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA); - if (skb == NULL) - return -ENOMEM; - dmaaddr = pci_map_single(ring->bcm->pci_dev, - skb->data, ring->rx_buffersize, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(dmaaddr) || - dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { - assert(0); - dev_kfree_skb_any(skb); - return -ENOMEM; - } - } - meta->skb = skb; - meta->dmaaddr = dmaaddr; - skb->dev = ring->bcm->net_dev; - - fill_descriptor(ring, desc, dmaaddr, - ring->rx_buffersize, 0, 0, 0); - - rxhdr = (struct bcm43xx_rxhdr *)(skb->data); - rxhdr->frame_length = 0; - rxhdr->flags1 = 0; - xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data); - xmitstat->cookie = 0; - - return 0; -} - -/* Allocate the initial descbuffers. - * This is used for an RX ring only. - */ -static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) -{ - int i, err = -ENOMEM; - struct bcm43xx_dmadesc_generic *desc; - struct bcm43xx_dmadesc_meta *meta; - - for (i = 0; i < ring->nr_slots; i++) { - desc = bcm43xx_dma_idx2desc(ring, i, &meta); - - err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); - if (err) - goto err_unwind; - } - mb(); - ring->used_slots = ring->nr_slots; - err = 0; -out: - return err; - -err_unwind: - for (i--; i >= 0; i--) { - desc = bcm43xx_dma_idx2desc(ring, i, &meta); - - unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); - dev_kfree_skb(meta->skb); - } - goto out; -} - -/* Do initial setup of the DMA controller. - * Reset the controller, write the ring busaddress - * and switch the "enable" bit on. - */ -static int dmacontroller_setup(struct bcm43xx_dmaring *ring) -{ - int err = 0; - u32 value; - u32 addrext; - - if (ring->tx) { - if (ring->dma64) { - u64 ringbase = (u64)(ring->dmabase); - - addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT); - value = BCM43xx_DMA64_TXENABLE; - value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT) - & BCM43xx_DMA64_TXADDREXT_MASK; - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value); - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, - (ringbase & 0xFFFFFFFF)); - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, - ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING) - | ring->routing); - } else { - u32 ringbase = (u32)(ring->dmabase); - - addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT); - value = BCM43xx_DMA32_TXENABLE; - value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT) - & BCM43xx_DMA32_TXADDREXT_MASK; - bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value); - bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, - (ringbase & ~BCM43xx_DMA32_ROUTING) - | ring->routing); - } - } else { - err = alloc_initial_descbuffers(ring); - if (err) - goto out; - if (ring->dma64) { - u64 ringbase = (u64)(ring->dmabase); - - addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT); - value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT); - value |= BCM43xx_DMA64_RXENABLE; - value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT) - & BCM43xx_DMA64_RXADDREXT_MASK; - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value); - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, - (ringbase & 0xFFFFFFFF)); - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, - ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING) - | ring->routing); - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200); - } else { - u32 ringbase = (u32)(ring->dmabase); - - addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT); - value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT); - value |= BCM43xx_DMA32_RXENABLE; - value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT) - & BCM43xx_DMA32_RXADDREXT_MASK; - bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value); - bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, - (ringbase & ~BCM43xx_DMA32_ROUTING) - | ring->routing); - bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200); - } - } - -out: - return err; -} - -/* Shutdown the DMA controller. */ -static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) -{ - if (ring->tx) { - bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64); - if (ring->dma64) { - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0); - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0); - } else - bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0); - } else { - bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64); - if (ring->dma64) { - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0); - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0); - } else - bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0); - } -} - -static void free_all_descbuffers(struct bcm43xx_dmaring *ring) -{ - struct bcm43xx_dmadesc_generic *desc; - struct bcm43xx_dmadesc_meta *meta; - int i; - - if (!ring->used_slots) - return; - for (i = 0; i < ring->nr_slots; i++) { - desc = bcm43xx_dma_idx2desc(ring, i, &meta); - - if (!meta->skb) { - assert(ring->tx); - continue; - } - if (ring->tx) { - unmap_descbuffer(ring, meta->dmaaddr, - meta->skb->len, 1); - } else { - unmap_descbuffer(ring, meta->dmaaddr, - ring->rx_buffersize, 0); - } - free_descriptor_buffer(ring, meta, 0); - } -} - -/* Main initialization function. */ -static -struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, - int controller_index, - int for_tx, - int dma64) -{ - struct bcm43xx_dmaring *ring; - int err; - int nr_slots; - - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - goto out; - - nr_slots = BCM43xx_RXRING_SLOTS; - if (for_tx) - nr_slots = BCM43xx_TXRING_SLOTS; - - ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta), - GFP_KERNEL); - if (!ring->meta) - goto err_kfree_ring; - - ring->routing = BCM43xx_DMA32_CLIENTTRANS; - if (dma64) - ring->routing = BCM43xx_DMA64_CLIENTTRANS; - - ring->bcm = bcm; - ring->nr_slots = nr_slots; - ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; - ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; - assert(ring->suspend_mark < ring->resume_mark); - ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index); - ring->index = controller_index; - ring->dma64 = !!dma64; - if (for_tx) { - ring->tx = 1; - ring->current_slot = -1; - } else { - if (ring->index == 0) { - ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE; - ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET; - } else if (ring->index == 3) { - ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE; - ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET; - } else - assert(0); - } - - err = alloc_ringmemory(ring); - if (err) - goto err_kfree_meta; - err = dmacontroller_setup(ring); - if (err) - goto err_free_ringmemory; - return ring; - -out: - printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n"); - return ring; - -err_free_ringmemory: - free_ringmemory(ring); -err_kfree_meta: - kfree(ring->meta); -err_kfree_ring: - kfree(ring); - ring = NULL; - goto out; -} - -/* Main cleanup function. */ -static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) -{ - if (!ring) - return; - - dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n", - (ring->dma64) ? "64" : "32", - ring->mmio_base, - (ring->tx) ? "TX" : "RX", - ring->max_used_slots, ring->nr_slots); - /* Device IRQs are disabled prior entering this function, - * so no need to take care of concurrency with rx handler stuff. - */ - dmacontroller_cleanup(ring); - free_all_descbuffers(ring); - free_ringmemory(ring); - - kfree(ring->meta); - kfree(ring); -} - -void bcm43xx_dma_free(struct bcm43xx_private *bcm) -{ - struct bcm43xx_dma *dma; - - if (bcm43xx_using_pio(bcm)) - return; - dma = bcm43xx_current_dma(bcm); - - bcm43xx_destroy_dmaring(dma->rx_ring3); - dma->rx_ring3 = NULL; - bcm43xx_destroy_dmaring(dma->rx_ring0); - dma->rx_ring0 = NULL; - - bcm43xx_destroy_dmaring(dma->tx_ring5); - dma->tx_ring5 = NULL; - bcm43xx_destroy_dmaring(dma->tx_ring4); - dma->tx_ring4 = NULL; - bcm43xx_destroy_dmaring(dma->tx_ring3); - dma->tx_ring3 = NULL; - bcm43xx_destroy_dmaring(dma->tx_ring2); - dma->tx_ring2 = NULL; - bcm43xx_destroy_dmaring(dma->tx_ring1); - dma->tx_ring1 = NULL; - bcm43xx_destroy_dmaring(dma->tx_ring0); - dma->tx_ring0 = NULL; -} - -int bcm43xx_dma_init(struct bcm43xx_private *bcm) -{ - struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); - struct bcm43xx_dmaring *ring; - int err = -ENOMEM; - int dma64 = 0; - - bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm); - if (bcm->dma_mask == DMA_64BIT_MASK) - dma64 = 1; - err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask); - if (err) - goto no_dma; - err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask); - if (err) - goto no_dma; - - /* setup TX DMA channels. */ - ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64); - if (!ring) - goto out; - dma->tx_ring0 = ring; - - ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64); - if (!ring) - goto err_destroy_tx0; - dma->tx_ring1 = ring; - - ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64); - if (!ring) - goto err_destroy_tx1; - dma->tx_ring2 = ring; - - ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64); - if (!ring) - goto err_destroy_tx2; - dma->tx_ring3 = ring; - - ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64); - if (!ring) - goto err_destroy_tx3; - dma->tx_ring4 = ring; - - ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64); - if (!ring) - goto err_destroy_tx4; - dma->tx_ring5 = ring; - - /* setup RX DMA channels. */ - ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64); - if (!ring) - goto err_destroy_tx5; - dma->rx_ring0 = ring; - - if (bcm->current_core->rev < 5) { - ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64); - if (!ring) - goto err_destroy_rx0; - dma->rx_ring3 = ring; - } - - dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", - (bcm->dma_mask == DMA_64BIT_MASK) ? 64 : - (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30); - err = 0; -out: - return err; - -err_destroy_rx0: - bcm43xx_destroy_dmaring(dma->rx_ring0); - dma->rx_ring0 = NULL; -err_destroy_tx5: - bcm43xx_destroy_dmaring(dma->tx_ring5); - dma->tx_ring5 = NULL; -err_destroy_tx4: - bcm43xx_destroy_dmaring(dma->tx_ring4); - dma->tx_ring4 = NULL; -err_destroy_tx3: - bcm43xx_destroy_dmaring(dma->tx_ring3); - dma->tx_ring3 = NULL; -err_destroy_tx2: - bcm43xx_destroy_dmaring(dma->tx_ring2); - dma->tx_ring2 = NULL; -err_destroy_tx1: - bcm43xx_destroy_dmaring(dma->tx_ring1); - dma->tx_ring1 = NULL; -err_destroy_tx0: - bcm43xx_destroy_dmaring(dma->tx_ring0); - dma->tx_ring0 = NULL; -no_dma: -#ifdef CONFIG_BCM43XX_PIO - printk(KERN_WARNING PFX "DMA not supported on this device." - " Falling back to PIO.\n"); - bcm->__using_pio = 1; - return -ENOSYS; -#else - printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " - "Please recompile the driver with PIO support.\n"); - return -ENODEV; -#endif /* CONFIG_BCM43XX_PIO */ -} - -/* Generate a cookie for the TX header. */ -static u16 generate_cookie(struct bcm43xx_dmaring *ring, - int slot) -{ - u16 cookie = 0x1000; - - /* Use the upper 4 bits of the cookie as - * DMA controller ID and store the slot number - * in the lower 12 bits. - * Note that the cookie must never be 0, as this - * is a special value used in RX path. - */ - switch (ring->index) { - case 0: - cookie = 0xA000; - break; - case 1: - cookie = 0xB000; - break; - case 2: - cookie = 0xC000; - break; - case 3: - cookie = 0xD000; - break; - case 4: - cookie = 0xE000; - break; - case 5: - cookie = 0xF000; - break; - } - assert(((u16)slot & 0xF000) == 0x0000); - cookie |= (u16)slot; - - return cookie; -} - -/* Inspect a cookie and find out to which controller/slot it belongs. */ -static -struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, - u16 cookie, int *slot) -{ - struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); - struct bcm43xx_dmaring *ring = NULL; - - switch (cookie & 0xF000) { - case 0xA000: - ring = dma->tx_ring0; - break; - case 0xB000: - ring = dma->tx_ring1; - break; - case 0xC000: - ring = dma->tx_ring2; - break; - case 0xD000: - ring = dma->tx_ring3; - break; - case 0xE000: - ring = dma->tx_ring4; - break; - case 0xF000: - ring = dma->tx_ring5; - break; - default: - assert(0); - } - *slot = (cookie & 0x0FFF); - assert(*slot >= 0 && *slot < ring->nr_slots); - - return ring; -} - -static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, - int slot) -{ - u16 offset; - int descsize; - - /* Everything is ready to start. Buffers are DMA mapped and - * associated with slots. - * "slot" is the last slot of the new frame we want to transmit. - * Close your seat belts now, please. - */ - wmb(); - slot = next_slot(ring, slot); - offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX; - descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64) - : sizeof(struct bcm43xx_dmadesc32); - bcm43xx_dma_write(ring, offset, - (u32)(slot * descsize)); -} - -static void dma_tx_fragment(struct bcm43xx_dmaring *ring, - struct sk_buff *skb, - u8 cur_frag) -{ - int slot; - struct bcm43xx_dmadesc_generic *desc; - struct bcm43xx_dmadesc_meta *meta; - dma_addr_t dmaaddr; - struct sk_buff *bounce_skb; - - assert(skb_shinfo(skb)->nr_frags == 0); - - slot = request_slot(ring); - desc = bcm43xx_dma_idx2desc(ring, slot, &meta); - - /* Add a device specific TX header. */ - assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); - /* Reserve enough headroom for the device tx header. */ - __skb_push(skb, sizeof(struct bcm43xx_txhdr)); - /* Now calculate and add the tx header. - * The tx header includes the PLCP header. - */ - bcm43xx_generate_txhdr(ring->bcm, - (struct bcm43xx_txhdr *)skb->data, - skb->data + sizeof(struct bcm43xx_txhdr), - skb->len - sizeof(struct bcm43xx_txhdr), - (cur_frag == 0), - generate_cookie(ring, slot)); - dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); - if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { - /* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */ - if (!dma_mapping_error(dmaaddr)) - unmap_descbuffer(ring, dmaaddr, skb->len, 1); - bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA); - if (!bounce_skb) - return; - dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1); - if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { - if (!dma_mapping_error(dmaaddr)) - unmap_descbuffer(ring, dmaaddr, skb->len, 1); - dev_kfree_skb_any(bounce_skb); - assert(0); - return; - } - skb_copy_from_linear_data(skb, skb_put(bounce_skb, skb->len), - skb->len); - dev_kfree_skb_any(skb); - skb = bounce_skb; - } - - meta->skb = skb; - meta->dmaaddr = dmaaddr; - - fill_descriptor(ring, desc, dmaaddr, - skb->len, 1, 1, 1); - - /* Now transfer the whole frame. */ - dmacontroller_poke_tx(ring, slot); -} - -int bcm43xx_dma_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - /* We just received a packet from the kernel network subsystem. - * Add headers and DMA map the memory. Poke - * the device to send the stuff. - * Note that this is called from atomic context. - */ - struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1; - u8 i; - struct sk_buff *skb; - - assert(ring->tx); - if (unlikely(free_slots(ring) < txb->nr_frags)) { - /* The queue should be stopped, - * if we are low on free slots. - * If this ever triggers, we have to lower the suspend_mark. - */ - dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n"); - return -ENOMEM; - } - - for (i = 0; i < txb->nr_frags; i++) { - skb = txb->fragments[i]; - /* Take skb from ieee80211_txb_free */ - txb->fragments[i] = NULL; - dma_tx_fragment(ring, skb, i); - } - ieee80211_txb_free(txb); - - return 0; -} - -void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) -{ - struct bcm43xx_dmaring *ring; - struct bcm43xx_dmadesc_generic *desc; - struct bcm43xx_dmadesc_meta *meta; - int is_last_fragment; - int slot; - u32 tmp; - - ring = parse_cookie(bcm, status->cookie, &slot); - assert(ring); - assert(ring->tx); - while (1) { - assert(slot >= 0 && slot < ring->nr_slots); - desc = bcm43xx_dma_idx2desc(ring, slot, &meta); - - if (ring->dma64) { - tmp = le32_to_cpu(desc->dma64.control0); - is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND); - } else { - tmp = le32_to_cpu(desc->dma32.control); - is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND); - } - unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); - free_descriptor_buffer(ring, meta, 1); - /* Everything belonging to the slot is unmapped - * and freed, so we can return it. - */ - return_slot(ring, slot); - - if (is_last_fragment) - break; - slot = next_slot(ring, slot); - } - bcm->stats.last_tx = jiffies; -} - -static void dma_rx(struct bcm43xx_dmaring *ring, - int *slot) -{ - struct bcm43xx_dmadesc_generic *desc; - struct bcm43xx_dmadesc_meta *meta; - struct bcm43xx_rxhdr *rxhdr; - struct sk_buff *skb; - u16 len; - int err; - dma_addr_t dmaaddr; - - desc = bcm43xx_dma_idx2desc(ring, *slot, &meta); - - sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); - skb = meta->skb; - - if (ring->index == 3) { - /* We received an xmit status. */ - struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data; - struct bcm43xx_xmitstatus stat; - int i = 0; - - stat.cookie = le16_to_cpu(hw->cookie); - while (stat.cookie == 0) { - if (unlikely(++i >= 10000)) { - assert(0); - break; - } - udelay(2); - barrier(); - stat.cookie = le16_to_cpu(hw->cookie); - } - stat.flags = hw->flags; - stat.cnt1 = hw->cnt1; - stat.cnt2 = hw->cnt2; - stat.seq = le16_to_cpu(hw->seq); - stat.unknown = le16_to_cpu(hw->unknown); - - bcm43xx_debugfs_log_txstat(ring->bcm, &stat); - bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat); - /* recycle the descriptor buffer. */ - sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize); - - return; - } - rxhdr = (struct bcm43xx_rxhdr *)skb->data; - len = le16_to_cpu(rxhdr->frame_length); - if (len == 0) { - int i = 0; - - do { - udelay(2); - barrier(); - len = le16_to_cpu(rxhdr->frame_length); - } while (len == 0 && i++ < 5); - if (unlikely(len == 0)) { - /* recycle the descriptor buffer. */ - sync_descbuffer_for_device(ring, meta->dmaaddr, - ring->rx_buffersize); - goto drop; - } - } - if (unlikely(len > ring->rx_buffersize)) { - /* The data did not fit into one descriptor buffer - * and is split over multiple buffers. - * This should never happen, as we try to allocate buffers - * big enough. So simply ignore this packet. - */ - int cnt = 0; - s32 tmp = len; - - while (1) { - desc = bcm43xx_dma_idx2desc(ring, *slot, &meta); - /* recycle the descriptor buffer. */ - sync_descbuffer_for_device(ring, meta->dmaaddr, - ring->rx_buffersize); - *slot = next_slot(ring, *slot); - cnt++; - tmp -= ring->rx_buffersize; - if (tmp <= 0) - break; - } - printkl(KERN_ERR PFX "DMA RX buffer too small " - "(len: %u, buffer: %u, nr-dropped: %d)\n", - len, ring->rx_buffersize, cnt); - goto drop; - } - len -= IEEE80211_FCS_LEN; - - dmaaddr = meta->dmaaddr; - err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); - if (unlikely(err)) { - dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); - sync_descbuffer_for_device(ring, dmaaddr, - ring->rx_buffersize); - goto drop; - } - - unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); - skb_put(skb, len + ring->frameoffset); - skb_pull(skb, ring->frameoffset); - - err = bcm43xx_rx(ring->bcm, skb, rxhdr); - if (err) { - dev_kfree_skb_irq(skb); - goto drop; - } - -drop: - return; -} - -void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) -{ - u32 status; - u16 descptr; - int slot, current_slot; -#ifdef CONFIG_BCM43XX_DEBUG - int used_slots = 0; -#endif - - assert(!ring->tx); - if (ring->dma64) { - status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS); - descptr = (status & BCM43xx_DMA64_RXSTATDPTR); - current_slot = descptr / sizeof(struct bcm43xx_dmadesc64); - } else { - status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS); - descptr = (status & BCM43xx_DMA32_RXDPTR); - current_slot = descptr / sizeof(struct bcm43xx_dmadesc32); - } - assert(current_slot >= 0 && current_slot < ring->nr_slots); - - slot = ring->current_slot; - for ( ; slot != current_slot; slot = next_slot(ring, slot)) { - dma_rx(ring, &slot); -#ifdef CONFIG_BCM43XX_DEBUG - if (++used_slots > ring->max_used_slots) - ring->max_used_slots = used_slots; -#endif - } - if (ring->dma64) { - bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, - (u32)(slot * sizeof(struct bcm43xx_dmadesc64))); - } else { - bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, - (u32)(slot * sizeof(struct bcm43xx_dmadesc32))); - } - ring->current_slot = slot; -} - -void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) -{ - assert(ring->tx); - bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1); - if (ring->dma64) { - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, - bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL) - | BCM43xx_DMA64_TXSUSPEND); - } else { - bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, - bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL) - | BCM43xx_DMA32_TXSUSPEND); - } -} - -void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) -{ - assert(ring->tx); - if (ring->dma64) { - bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, - bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL) - & ~BCM43xx_DMA64_TXSUSPEND); - } else { - bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, - bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL) - & ~BCM43xx_DMA32_TXSUSPEND); - } - bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h deleted file mode 100644 index d1105e569a4..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ /dev/null @@ -1,386 +0,0 @@ -#ifndef BCM43xx_DMA_H_ -#define BCM43xx_DMA_H_ - -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/workqueue.h> -#include <linux/dma-mapping.h> -#include <linux/linkage.h> -#include <asm/atomic.h> - - -/* DMA-Interrupt reasons. */ -#define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ - | (1 << 14) | (1 << 15)) -#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13) -#define BCM43xx_DMAIRQ_RX_DONE (1 << 16) - - -/*** 32-bit DMA Engine. ***/ - -/* 32-bit DMA controller registers. */ -#define BCM43xx_DMA32_TXCTL 0x00 -#define BCM43xx_DMA32_TXENABLE 0x00000001 -#define BCM43xx_DMA32_TXSUSPEND 0x00000002 -#define BCM43xx_DMA32_TXLOOPBACK 0x00000004 -#define BCM43xx_DMA32_TXFLUSH 0x00000010 -#define BCM43xx_DMA32_TXADDREXT_MASK 0x00030000 -#define BCM43xx_DMA32_TXADDREXT_SHIFT 16 -#define BCM43xx_DMA32_TXRING 0x04 -#define BCM43xx_DMA32_TXINDEX 0x08 -#define BCM43xx_DMA32_TXSTATUS 0x0C -#define BCM43xx_DMA32_TXDPTR 0x00000FFF -#define BCM43xx_DMA32_TXSTATE 0x0000F000 -#define BCM43xx_DMA32_TXSTAT_DISABLED 0x00000000 -#define BCM43xx_DMA32_TXSTAT_ACTIVE 0x00001000 -#define BCM43xx_DMA32_TXSTAT_IDLEWAIT 0x00002000 -#define BCM43xx_DMA32_TXSTAT_STOPPED 0x00003000 -#define BCM43xx_DMA32_TXSTAT_SUSP 0x00004000 -#define BCM43xx_DMA32_TXERROR 0x000F0000 -#define BCM43xx_DMA32_TXERR_NOERR 0x00000000 -#define BCM43xx_DMA32_TXERR_PROT 0x00010000 -#define BCM43xx_DMA32_TXERR_UNDERRUN 0x00020000 -#define BCM43xx_DMA32_TXERR_BUFREAD 0x00030000 -#define BCM43xx_DMA32_TXERR_DESCREAD 0x00040000 -#define BCM43xx_DMA32_TXACTIVE 0xFFF00000 -#define BCM43xx_DMA32_RXCTL 0x10 -#define BCM43xx_DMA32_RXENABLE 0x00000001 -#define BCM43xx_DMA32_RXFROFF_MASK 0x000000FE -#define BCM43xx_DMA32_RXFROFF_SHIFT 1 -#define BCM43xx_DMA32_RXDIRECTFIFO 0x00000100 -#define BCM43xx_DMA32_RXADDREXT_MASK 0x00030000 -#define BCM43xx_DMA32_RXADDREXT_SHIFT 16 -#define BCM43xx_DMA32_RXRING 0x14 -#define BCM43xx_DMA32_RXINDEX 0x18 -#define BCM43xx_DMA32_RXSTATUS 0x1C -#define BCM43xx_DMA32_RXDPTR 0x00000FFF -#define BCM43xx_DMA32_RXSTATE 0x0000F000 -#define BCM43xx_DMA32_RXSTAT_DISABLED 0x00000000 -#define BCM43xx_DMA32_RXSTAT_ACTIVE 0x00001000 -#define BCM43xx_DMA32_RXSTAT_IDLEWAIT 0x00002000 -#define BCM43xx_DMA32_RXSTAT_STOPPED 0x00003000 -#define BCM43xx_DMA32_RXERROR 0x000F0000 -#define BCM43xx_DMA32_RXERR_NOERR 0x00000000 -#define BCM43xx_DMA32_RXERR_PROT 0x00010000 -#define BCM43xx_DMA32_RXERR_OVERFLOW 0x00020000 -#define BCM43xx_DMA32_RXERR_BUFWRITE 0x00030000 -#define BCM43xx_DMA32_RXERR_DESCREAD 0x00040000 -#define BCM43xx_DMA32_RXACTIVE 0xFFF00000 - -/* 32-bit DMA descriptor. */ -struct bcm43xx_dmadesc32 { - __le32 control; - __le32 address; -} __attribute__((__packed__)); -#define BCM43xx_DMA32_DCTL_BYTECNT 0x00001FFF -#define BCM43xx_DMA32_DCTL_ADDREXT_MASK 0x00030000 -#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT 16 -#define BCM43xx_DMA32_DCTL_DTABLEEND 0x10000000 -#define BCM43xx_DMA32_DCTL_IRQ 0x20000000 -#define BCM43xx_DMA32_DCTL_FRAMEEND 0x40000000 -#define BCM43xx_DMA32_DCTL_FRAMESTART 0x80000000 - -/* Address field Routing value. */ -#define BCM43xx_DMA32_ROUTING 0xC0000000 -#define BCM43xx_DMA32_ROUTING_SHIFT 30 -#define BCM43xx_DMA32_NOTRANS 0x00000000 -#define BCM43xx_DMA32_CLIENTTRANS 0x40000000 - - - -/*** 64-bit DMA Engine. ***/ - -/* 64-bit DMA controller registers. */ -#define BCM43xx_DMA64_TXCTL 0x00 -#define BCM43xx_DMA64_TXENABLE 0x00000001 -#define BCM43xx_DMA64_TXSUSPEND 0x00000002 -#define BCM43xx_DMA64_TXLOOPBACK 0x00000004 -#define BCM43xx_DMA64_TXFLUSH 0x00000010 -#define BCM43xx_DMA64_TXADDREXT_MASK 0x00030000 -#define BCM43xx_DMA64_TXADDREXT_SHIFT 16 -#define BCM43xx_DMA64_TXINDEX 0x04 -#define BCM43xx_DMA64_TXRINGLO 0x08 -#define BCM43xx_DMA64_TXRINGHI 0x0C -#define BCM43xx_DMA64_TXSTATUS 0x10 -#define BCM43xx_DMA64_TXSTATDPTR 0x00001FFF -#define BCM43xx_DMA64_TXSTAT 0xF0000000 -#define BCM43xx_DMA64_TXSTAT_DISABLED 0x00000000 -#define BCM43xx_DMA64_TXSTAT_ACTIVE 0x10000000 -#define BCM43xx_DMA64_TXSTAT_IDLEWAIT 0x20000000 -#define BCM43xx_DMA64_TXSTAT_STOPPED 0x30000000 -#define BCM43xx_DMA64_TXSTAT_SUSP 0x40000000 -#define BCM43xx_DMA64_TXERROR 0x14 -#define BCM43xx_DMA64_TXERRDPTR 0x0001FFFF -#define BCM43xx_DMA64_TXERR 0xF0000000 -#define BCM43xx_DMA64_TXERR_NOERR 0x00000000 -#define BCM43xx_DMA64_TXERR_PROT 0x10000000 -#define BCM43xx_DMA64_TXERR_UNDERRUN 0x20000000 -#define BCM43xx_DMA64_TXERR_TRANSFER 0x30000000 -#define BCM43xx_DMA64_TXERR_DESCREAD 0x40000000 -#define BCM43xx_DMA64_TXERR_CORE 0x50000000 -#define BCM43xx_DMA64_RXCTL 0x20 -#define BCM43xx_DMA64_RXENABLE 0x00000001 -#define BCM43xx_DMA64_RXFROFF_MASK 0x000000FE -#define BCM43xx_DMA64_RXFROFF_SHIFT 1 -#define BCM43xx_DMA64_RXDIRECTFIFO 0x00000100 -#define BCM43xx_DMA64_RXADDREXT_MASK 0x00030000 -#define BCM43xx_DMA64_RXADDREXT_SHIFT 16 -#define BCM43xx_DMA64_RXINDEX 0x24 -#define BCM43xx_DMA64_RXRINGLO 0x28 -#define BCM43xx_DMA64_RXRINGHI 0x2C -#define BCM43xx_DMA64_RXSTATUS 0x30 -#define BCM43xx_DMA64_RXSTATDPTR 0x00001FFF -#define BCM43xx_DMA64_RXSTAT 0xF0000000 -#define BCM43xx_DMA64_RXSTAT_DISABLED 0x00000000 -#define BCM43xx_DMA64_RXSTAT_ACTIVE 0x10000000 -#define BCM43xx_DMA64_RXSTAT_IDLEWAIT 0x20000000 -#define BCM43xx_DMA64_RXSTAT_STOPPED 0x30000000 -#define BCM43xx_DMA64_RXSTAT_SUSP 0x40000000 -#define BCM43xx_DMA64_RXERROR 0x34 -#define BCM43xx_DMA64_RXERRDPTR 0x0001FFFF -#define BCM43xx_DMA64_RXERR 0xF0000000 -#define BCM43xx_DMA64_RXERR_NOERR 0x00000000 -#define BCM43xx_DMA64_RXERR_PROT 0x10000000 -#define BCM43xx_DMA64_RXERR_UNDERRUN 0x20000000 -#define BCM43xx_DMA64_RXERR_TRANSFER 0x30000000 -#define BCM43xx_DMA64_RXERR_DESCREAD 0x40000000 -#define BCM43xx_DMA64_RXERR_CORE 0x50000000 - -/* 64-bit DMA descriptor. */ -struct bcm43xx_dmadesc64 { - __le32 control0; - __le32 control1; - __le32 address_low; - __le32 address_high; -} __attribute__((__packed__)); -#define BCM43xx_DMA64_DCTL0_DTABLEEND 0x10000000 -#define BCM43xx_DMA64_DCTL0_IRQ 0x20000000 -#define BCM43xx_DMA64_DCTL0_FRAMEEND 0x40000000 -#define BCM43xx_DMA64_DCTL0_FRAMESTART 0x80000000 -#define BCM43xx_DMA64_DCTL1_BYTECNT 0x00001FFF -#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK 0x00030000 -#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT 16 - -/* Address field Routing value. */ -#define BCM43xx_DMA64_ROUTING 0xC0000000 -#define BCM43xx_DMA64_ROUTING_SHIFT 30 -#define BCM43xx_DMA64_NOTRANS 0x00000000 -#define BCM43xx_DMA64_CLIENTTRANS 0x80000000 - - - -struct bcm43xx_dmadesc_generic { - union { - struct bcm43xx_dmadesc32 dma32; - struct bcm43xx_dmadesc64 dma64; - } __attribute__((__packed__)); -} __attribute__((__packed__)); - - -/* Misc DMA constants */ -#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE -#define BCM43xx_DMA0_RX_FRAMEOFFSET 30 -#define BCM43xx_DMA3_RX_FRAMEOFFSET 0 - - -/* DMA engine tuning knobs */ -#define BCM43xx_TXRING_SLOTS 512 -#define BCM43xx_RXRING_SLOTS 64 -#define BCM43xx_DMA0_RX_BUFFERSIZE (2304 + 100) -#define BCM43xx_DMA3_RX_BUFFERSIZE 16 -/* Suspend the tx queue, if less than this percent slots are free. */ -#define BCM43xx_TXSUSPEND_PERCENT 20 -/* Resume the tx queue, if more than this percent slots are free. */ -#define BCM43xx_TXRESUME_PERCENT 50 - - - -#ifdef CONFIG_BCM43XX_DMA - - -struct sk_buff; -struct bcm43xx_private; -struct bcm43xx_xmitstatus; - - -struct bcm43xx_dmadesc_meta { - /* The kernel DMA-able buffer. */ - struct sk_buff *skb; - /* DMA base bus-address of the descriptor buffer. */ - dma_addr_t dmaaddr; -}; - -struct bcm43xx_dmaring { - /* Kernel virtual base address of the ring memory. */ - void *descbase; - /* Meta data about all descriptors. */ - struct bcm43xx_dmadesc_meta *meta; - /* DMA Routing value. */ - u32 routing; - /* (Unadjusted) DMA base bus-address of the ring memory. */ - dma_addr_t dmabase; - /* Number of descriptor slots in the ring. */ - int nr_slots; - /* Number of used descriptor slots. */ - int used_slots; - /* Currently used slot in the ring. */ - int current_slot; - /* Marks to suspend/resume the queue. */ - int suspend_mark; - int resume_mark; - /* Frameoffset in octets. */ - u32 frameoffset; - /* Descriptor buffer size. */ - u16 rx_buffersize; - /* The MMIO base register of the DMA controller. */ - u16 mmio_base; - /* DMA controller index number (0-5). */ - int index; - /* Boolean. Is this a TX ring? */ - u8 tx; - /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ - u8 dma64; - /* Boolean. Are transfers suspended on this ring? */ - u8 suspended; - struct bcm43xx_private *bcm; -#ifdef CONFIG_BCM43XX_DEBUG - /* Maximum number of used slots. */ - int max_used_slots; -#endif /* CONFIG_BCM43XX_DEBUG*/ -}; - - -static inline -int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring, - struct bcm43xx_dmadesc_generic *desc) -{ - if (ring->dma64) { - struct bcm43xx_dmadesc64 *dd64 = ring->descbase; - return (int)(&(desc->dma64) - dd64); - } else { - struct bcm43xx_dmadesc32 *dd32 = ring->descbase; - return (int)(&(desc->dma32) - dd32); - } -} - -static inline -struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring, - int slot, - struct bcm43xx_dmadesc_meta **meta) -{ - *meta = &(ring->meta[slot]); - if (ring->dma64) { - struct bcm43xx_dmadesc64 *dd64 = ring->descbase; - return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot])); - } else { - struct bcm43xx_dmadesc32 *dd32 = ring->descbase; - return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot])); - } -} - -static inline -u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring, - u16 offset) -{ - return bcm43xx_read32(ring->bcm, ring->mmio_base + offset); -} - -static inline -void bcm43xx_dma_write(struct bcm43xx_dmaring *ring, - u16 offset, u32 value) -{ - bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value); -} - - -int bcm43xx_dma_init(struct bcm43xx_private *bcm); -void bcm43xx_dma_free(struct bcm43xx_private *bcm); - -int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, - u16 dmacontroller_mmio_base, - int dma64); -int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, - u16 dmacontroller_mmio_base, - int dma64); - -u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx); - -void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); -void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); - -void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status); - -int bcm43xx_dma_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb); -void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); - -/* Helper function that returns the dma mask for this device. */ -static inline -u64 bcm43xx_get_supported_dma_mask(struct bcm43xx_private *bcm) -{ - int dma64 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH) & - BCM43xx_SBTMSTATEHIGH_DMA64BIT; - u16 mmio_base = bcm43xx_dmacontroller_base(dma64, 0); - u32 mask = BCM43xx_DMA32_TXADDREXT_MASK; - - if (dma64) - return DMA_64BIT_MASK; - bcm43xx_write32(bcm, mmio_base + BCM43xx_DMA32_TXCTL, mask); - if (bcm43xx_read32(bcm, mmio_base + BCM43xx_DMA32_TXCTL) & mask) - return DMA_32BIT_MASK; - return DMA_30BIT_MASK; -} - -#else /* CONFIG_BCM43XX_DMA */ - - -static inline -int bcm43xx_dma_init(struct bcm43xx_private *bcm) -{ - return 0; -} -static inline -void bcm43xx_dma_free(struct bcm43xx_private *bcm) -{ -} -static inline -int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, - u16 dmacontroller_mmio_base, - int dma64) -{ - return 0; -} -static inline -int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, - u16 dmacontroller_mmio_base, - int dma64) -{ - return 0; -} -static inline -int bcm43xx_dma_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - return 0; -} -static inline -void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) -{ -} -static inline -void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) -{ -} -static inline -void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) -{ -} -static inline -void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) -{ -} - -#endif /* CONFIG_BCM43XX_DMA */ -#endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c deleted file mode 100644 index d2df6a0100a..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - ethtool support - - Copyright (c) 2006 Jason Lunz <lunz@falooley.org> - - Some code in this file is derived from the 8139too.c driver - Copyright (C) 2002 Jeff Garzik - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx.h" -#include "bcm43xx_ethtool.h" - -#include <linux/netdevice.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/utsname.h> - - -static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(dev); - - strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strncpy(info->version, utsname()->release, sizeof(info->version)); - strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); -} - -const struct ethtool_ops bcm43xx_ethtool_ops = { - .get_drvinfo = bcm43xx_get_drvinfo, - .get_link = ethtool_op_get_link, -}; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h deleted file mode 100644 index 6f8d42d3cdf..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef BCM43xx_ETHTOOL_H_ -#define BCM43xx_ETHTOOL_H_ - -#include <linux/ethtool.h> - -extern const struct ethtool_ops bcm43xx_ethtool_ops; - -#endif /* BCM43xx_ETHTOOL_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c deleted file mode 100644 index f2b8dbac55a..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx.h" -#include "bcm43xx_ilt.h" -#include "bcm43xx_phy.h" - - -/**** Initial Internal Lookup Tables ****/ - -const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = { - 0xFEB93FFD, 0xFEC63FFD, /* 0 */ - 0xFED23FFD, 0xFEDF3FFD, - 0xFEEC3FFE, 0xFEF83FFE, - 0xFF053FFE, 0xFF113FFE, - 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ - 0xFF373FFF, 0xFF443FFF, - 0xFF503FFF, 0xFF5D3FFF, - 0xFF693FFF, 0xFF763FFF, - 0xFF824000, 0xFF8F4000, /* 16 */ - 0xFF9B4000, 0xFFA84000, - 0xFFB54000, 0xFFC14000, - 0xFFCE4000, 0xFFDA4000, - 0xFFE74000, 0xFFF34000, /* 24 */ - 0x00004000, 0x000D4000, - 0x00194000, 0x00264000, - 0x00324000, 0x003F4000, - 0x004B4000, 0x00584000, /* 32 */ - 0x00654000, 0x00714000, - 0x007E4000, 0x008A3FFF, - 0x00973FFF, 0x00A33FFF, - 0x00B03FFF, 0x00BC3FFF, /* 40 */ - 0x00C93FFF, 0x00D63FFF, - 0x00E23FFE, 0x00EF3FFE, - 0x00FB3FFE, 0x01083FFE, - 0x01143FFE, 0x01213FFD, /* 48 */ - 0x012E3FFD, 0x013A3FFD, - 0x01473FFD, -}; - -const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = { - 0xDB93CB87, 0xD666CF64, /* 0 */ - 0xD1FDD358, 0xCDA6D826, - 0xCA38DD9F, 0xC729E2B4, - 0xC469E88E, 0xC26AEE2B, - 0xC0DEF46C, 0xC073FA62, /* 8 */ - 0xC01D00D5, 0xC0760743, - 0xC1560D1E, 0xC2E51369, - 0xC4ED18FF, 0xC7AC1ED7, - 0xCB2823B2, 0xCEFA28D9, /* 16 */ - 0xD2F62D3F, 0xD7BB3197, - 0xDCE53568, 0xE1FE3875, - 0xE7D13B35, 0xED663D35, - 0xF39B3EC4, 0xF98E3FA7, /* 24 */ - 0x00004000, 0x06723FA7, - 0x0C653EC4, 0x129A3D35, - 0x182F3B35, 0x1E023875, - 0x231B3568, 0x28453197, /* 32 */ - 0x2D0A2D3F, 0x310628D9, - 0x34D823B2, 0x38541ED7, - 0x3B1318FF, 0x3D1B1369, - 0x3EAA0D1E, 0x3F8A0743, /* 40 */ - 0x3FE300D5, 0x3F8DFA62, - 0x3F22F46C, 0x3D96EE2B, - 0x3B97E88E, 0x38D7E2B4, - 0x35C8DD9F, 0x325AD826, /* 48 */ - 0x2E03D358, 0x299ACF64, - 0x246DCB87, -}; - -const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = { - 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ - 0x0202, 0x0282, 0x0302, 0x0382, - 0x0402, 0x0482, 0x0502, 0x0582, - 0x05E2, 0x0662, 0x06E2, 0x0762, - 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ - 0x09C2, 0x0A22, 0x0AA2, 0x0B02, - 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, - 0x0D42, 0x0DA2, 0x0E02, 0x0E62, - 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ - 0x1062, 0x10C2, 0x1122, 0x1182, - 0x11E2, 0x1242, 0x12A2, 0x12E2, - 0x1342, 0x13A2, 0x1402, 0x1442, - 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ - 0x15E2, 0x1622, 0x1662, 0x16C1, - 0x1701, 0x1741, 0x1781, 0x17E1, - 0x1821, 0x1861, 0x18A1, 0x18E1, - 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ - 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, - 0x1B01, 0x1B41, 0x1B81, 0x1BA1, - 0x1BE1, 0x1C21, 0x1C41, 0x1C81, - 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ - 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, - 0x1E21, 0x1E61, 0x1E81, 0x1EA1, - 0x1EE1, 0x1F01, 0x1F21, 0x1F41, - 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ - 0x2001, 0x2041, 0x2061, 0x2081, - 0x20A1, 0x20C1, 0x20E1, 0x2101, - 0x2121, 0x2141, 0x2161, 0x2181, - 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ - 0x2221, 0x2241, 0x2261, 0x2281, - 0x22A1, 0x22C1, 0x22C1, 0x22E1, - 0x2301, 0x2321, 0x2341, 0x2361, - 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ - 0x23E1, 0x23E1, 0x2401, 0x2421, - 0x2441, 0x2441, 0x2461, 0x2481, - 0x2481, 0x24A1, 0x24C1, 0x24C1, - 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ - 0x2541, 0x2541, 0x2561, 0x2561, - 0x2581, 0x25A1, 0x25A1, 0x25C1, - 0x25C1, 0x25E1, 0x2601, 0x2601, - 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ - 0x2661, 0x2661, 0x2681, 0x2681, - 0x26A1, 0x26A1, 0x26C1, 0x26C1, - 0x26E1, 0x26E1, 0x2701, 0x2701, - 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ - 0x2760, 0x2760, 0x2780, 0x2780, - 0x2780, 0x27A0, 0x27A0, 0x27C0, - 0x27C0, 0x27E0, 0x27E0, 0x27E0, - 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ - 0x2820, 0x2840, 0x2840, 0x2840, - 0x2860, 0x2860, 0x2880, 0x2880, - 0x2880, 0x28A0, 0x28A0, 0x28A0, - 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ - 0x28E0, 0x28E0, 0x2900, 0x2900, - 0x2900, 0x2920, 0x2920, 0x2920, - 0x2940, 0x2940, 0x2940, 0x2960, - 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ - 0x2980, 0x2980, 0x29A0, 0x29A0, - 0x29A0, 0x29A0, 0x29C0, 0x29C0, - 0x29C0, 0x29E0, 0x29E0, 0x29E0, - 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ - 0x2A00, 0x2A20, 0x2A20, 0x2A20, - 0x2A20, 0x2A40, 0x2A40, 0x2A40, - 0x2A40, 0x2A60, 0x2A60, 0x2A60, -}; - -const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = { - 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ - 0x05A9, 0x0669, 0x0709, 0x0789, - 0x0829, 0x08A9, 0x0929, 0x0989, - 0x0A09, 0x0A69, 0x0AC9, 0x0B29, - 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ - 0x0D09, 0x0D69, 0x0DA9, 0x0E09, - 0x0E69, 0x0EA9, 0x0F09, 0x0F49, - 0x0FA9, 0x0FE9, 0x1029, 0x1089, - 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ - 0x11E9, 0x1229, 0x1289, 0x12C9, - 0x1309, 0x1349, 0x1389, 0x13C9, - 0x1409, 0x1449, 0x14A9, 0x14E9, - 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ - 0x1629, 0x1669, 0x16A9, 0x16E8, - 0x1728, 0x1768, 0x17A8, 0x17E8, - 0x1828, 0x1868, 0x18A8, 0x18E8, - 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ - 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, - 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, - 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, - 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ - 0x1E48, 0x1E88, 0x1EC8, 0x1F08, - 0x1F48, 0x1F88, 0x1FE8, 0x2028, - 0x2068, 0x20A8, 0x2108, 0x2148, - 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ - 0x22C8, 0x2308, 0x2348, 0x23A8, - 0x23E8, 0x2448, 0x24A8, 0x24E8, - 0x2548, 0x25A8, 0x2608, 0x2668, - 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ - 0x2847, 0x28C7, 0x2947, 0x29A7, - 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, - 0x2CA7, 0x2D67, 0x2E47, 0x2F67, - 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ - 0x3806, 0x38A6, 0x3946, 0x39E6, - 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, - 0x3C45, 0x3CA5, 0x3D05, 0x3D85, - 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ - 0x3F45, 0x3FA5, 0x4005, 0x4045, - 0x40A5, 0x40E5, 0x4145, 0x4185, - 0x41E5, 0x4225, 0x4265, 0x42C5, - 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ - 0x4424, 0x4464, 0x44C4, 0x4504, - 0x4544, 0x4584, 0x45C4, 0x4604, - 0x4644, 0x46A4, 0x46E4, 0x4724, - 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ - 0x4864, 0x48A4, 0x48E4, 0x4924, - 0x4964, 0x49A4, 0x49E4, 0x4A24, - 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, - 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ - 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, - 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, - 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, - 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ - 0x5083, 0x50C3, 0x5103, 0x5143, - 0x5183, 0x51E2, 0x5222, 0x5262, - 0x52A2, 0x52E2, 0x5342, 0x5382, - 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ - 0x5502, 0x5542, 0x55A2, 0x55E2, - 0x5642, 0x5682, 0x56E2, 0x5722, - 0x5782, 0x57E1, 0x5841, 0x58A1, - 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ - 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, - 0x5C61, 0x5D01, 0x5D80, 0x5E20, - 0x5EE0, 0x5FA0, 0x6080, 0x61C0, -}; - -const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = { - 0x0001, 0x0001, 0x0001, 0xFFFE, - 0xFFFE, 0x3FFF, 0x1000, 0x0393, -}; - -const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = { - 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, - 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, -}; - -const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = { - 0x013C, 0x01F5, 0x031A, 0x0631, - 0x0001, 0x0001, 0x0001, 0x0001, -}; - -const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = { - 0x5484, 0x3C40, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, -}; - -const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = { - 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ - 0x2F2D, 0x2A2A, 0x2527, 0x1F21, - 0x1A1D, 0x1719, 0x1616, 0x1414, - 0x1414, 0x1400, 0x1414, 0x1614, - 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ - 0x2A27, 0x2F2A, 0x332D, 0x3B35, - 0x5140, 0x6C62, 0x0077, -}; - -const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = { - 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ - 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, - 0x969B, 0x9195, 0x8F8F, 0x8A8A, - 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, - 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ - 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, - 0xCBC0, 0xD8D4, 0x00DD, -}; - -const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = { - 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ - 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, - 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, - 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, - 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ - 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, - 0xA4A4, 0xA4A4, 0x00A4, -}; - -const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = { - 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ - 0x0067, 0x0063, 0x005E, 0x0059, - 0x0054, 0x0050, 0x004B, 0x0046, - 0x0042, 0x003D, 0x003D, 0x003D, - 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ - 0x003D, 0x003D, 0x003D, 0x003D, - 0x003D, 0x003D, 0x0000, 0x003D, - 0x003D, 0x003D, 0x003D, 0x003D, - 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ - 0x003D, 0x003D, 0x003D, 0x003D, - 0x0042, 0x0046, 0x004B, 0x0050, - 0x0054, 0x0059, 0x005E, 0x0063, - 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ - 0x007A, -}; - -const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { - 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ - 0x00D6, 0x00D4, 0x00D2, 0x00CF, - 0x00CD, 0x00CA, 0x00C7, 0x00C4, - 0x00C1, 0x00BE, 0x00BE, 0x00BE, - 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ - 0x00BE, 0x00BE, 0x00BE, 0x00BE, - 0x00BE, 0x00BE, 0x0000, 0x00BE, - 0x00BE, 0x00BE, 0x00BE, 0x00BE, - 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ - 0x00BE, 0x00BE, 0x00BE, 0x00BE, - 0x00C1, 0x00C4, 0x00C7, 0x00CA, - 0x00CD, 0x00CF, 0x00D2, 0x00D4, - 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ - 0x00DE, -}; - -/**** Helper functions to access the device Internal Lookup Tables ****/ - -void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) -{ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - mmiowb(); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - mmiowb(); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); - } -} - -void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val) -{ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - mmiowb(); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (val & 0xFFFF0000) >> 16); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val & 0x0000FFFF); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - mmiowb(); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (val & 0xFFFF0000) >> 16); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val & 0x0000FFFF); - } -} - -u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) -{ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); - } -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h deleted file mode 100644 index d7eaf5f25b7..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef BCM43xx_ILT_H_ -#define BCM43xx_ILT_H_ - -#define BCM43xx_ILT_ROTOR_SIZE 53 -extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE]; -#define BCM43xx_ILT_RETARD_SIZE 53 -extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE]; -#define BCM43xx_ILT_FINEFREQA_SIZE 256 -extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE]; -#define BCM43xx_ILT_FINEFREQG_SIZE 256 -extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE]; -#define BCM43xx_ILT_NOISEA2_SIZE 8 -extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE]; -#define BCM43xx_ILT_NOISEA3_SIZE 8 -extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE]; -#define BCM43xx_ILT_NOISEG1_SIZE 8 -extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE]; -#define BCM43xx_ILT_NOISEG2_SIZE 8 -extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE]; -#define BCM43xx_ILT_NOISESCALEG_SIZE 27 -extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE]; -extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE]; -extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE]; -#define BCM43xx_ILT_SIGMASQR_SIZE 53 -extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; -extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; - - -void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val); -void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val); -u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset); - -#endif /* BCM43xx_ILT_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c deleted file mode 100644 index cb51dc51cce..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx_leds.h" -#include "bcm43xx_radio.h" -#include "bcm43xx.h" - -#include <linux/bitops.h> - - -static void bcm43xx_led_changestate(struct bcm43xx_led *led) -{ - struct bcm43xx_private *bcm = led->bcm; - const int index = bcm43xx_led_index(led); - const u16 mask = (1 << index); - u16 ledctl; - - assert(index >= 0 && index < BCM43xx_NR_LEDS); - assert(led->blink_interval); - ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); -} - -static void bcm43xx_led_blink(unsigned long d) -{ - struct bcm43xx_led *led = (struct bcm43xx_led *)d; - struct bcm43xx_private *bcm = led->bcm; - unsigned long flags; - - spin_lock_irqsave(&bcm->leds_lock, flags); - if (led->blink_interval) { - bcm43xx_led_changestate(led); - mod_timer(&led->blink_timer, jiffies + led->blink_interval); - } - spin_unlock_irqrestore(&bcm->leds_lock, flags); -} - -static void bcm43xx_led_blink_start(struct bcm43xx_led *led, - unsigned long interval) -{ - if (led->blink_interval) - return; - led->blink_interval = interval; - bcm43xx_led_changestate(led); - led->blink_timer.expires = jiffies + interval; - add_timer(&led->blink_timer); -} - -static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) -{ - struct bcm43xx_private *bcm = led->bcm; - const int index = bcm43xx_led_index(led); - u16 ledctl; - - if (!led->blink_interval) - return; - if (unlikely(sync)) - del_timer_sync(&led->blink_timer); - else - del_timer(&led->blink_timer); - led->blink_interval = 0; - - /* Make sure the LED is turned off. */ - assert(index >= 0 && index < BCM43xx_NR_LEDS); - ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - if (led->activelow) - ledctl |= (1 << index); - else - ledctl &= ~(1 << index); - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); -} - -static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm, - struct bcm43xx_led *led, - int led_index) -{ - /* This function is called, if the behaviour (and activelow) - * information for a LED is missing in the SPROM. - * We hardcode the behaviour values for various devices here. - * Note that the BCM43xx_LED_TEST_XXX behaviour values can - * be used to figure out which led is mapped to which index. - */ - - switch (led_index) { - case 0: - led->behaviour = BCM43xx_LED_ACTIVITY; - led->activelow = 1; - if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = BCM43xx_LED_RADIO_ALL; - break; - case 1: - led->behaviour = BCM43xx_LED_RADIO_B; - if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK) - led->behaviour = BCM43xx_LED_ASSOC; - break; - case 2: - led->behaviour = BCM43xx_LED_RADIO_A; - break; - case 3: - led->behaviour = BCM43xx_LED_OFF; - break; - default: - assert(0); - } -} - -int bcm43xx_leds_init(struct bcm43xx_private *bcm) -{ - struct bcm43xx_led *led; - u8 sprom[4]; - int i; - - sprom[0] = bcm->sprom.wl0gpio0; - sprom[1] = bcm->sprom.wl0gpio1; - sprom[2] = bcm->sprom.wl0gpio2; - sprom[3] = bcm->sprom.wl0gpio3; - - for (i = 0; i < BCM43xx_NR_LEDS; i++) { - led = &(bcm->leds[i]); - led->bcm = bcm; - setup_timer(&led->blink_timer, - bcm43xx_led_blink, - (unsigned long)led); - - if (sprom[i] == 0xFF) { - bcm43xx_led_init_hardcoded(bcm, led, i); - } else { - led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; - led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); - } - } - - return 0; -} - -void bcm43xx_leds_exit(struct bcm43xx_private *bcm) -{ - struct bcm43xx_led *led; - int i; - - for (i = 0; i < BCM43xx_NR_LEDS; i++) { - led = &(bcm->leds[i]); - bcm43xx_led_blink_stop(led, 1); - } - bcm43xx_leds_switch_all(bcm, 0); -} - -void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) -{ - struct bcm43xx_led *led; - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; - int i, turn_on; - unsigned long interval = 0; - u16 ledctl; - unsigned long flags; - - spin_lock_irqsave(&bcm->leds_lock, flags); - ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - for (i = 0; i < BCM43xx_NR_LEDS; i++) { - led = &(bcm->leds[i]); - - turn_on = 0; - switch (led->behaviour) { - case BCM43xx_LED_INACTIVE: - continue; - case BCM43xx_LED_OFF: - case BCM43xx_LED_BCM4303_3: - break; - case BCM43xx_LED_ON: - turn_on = 1; - break; - case BCM43xx_LED_ACTIVITY: - case BCM43xx_LED_BCM4303_0: - turn_on = activity; - break; - case BCM43xx_LED_RADIO_ALL: - turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm); - break; - case BCM43xx_LED_RADIO_A: - case BCM43xx_LED_BCM4303_2: - turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) && - phy->type == BCM43xx_PHYTYPE_A); - break; - case BCM43xx_LED_RADIO_B: - case BCM43xx_LED_BCM4303_1: - turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) && - (phy->type == BCM43xx_PHYTYPE_B || - phy->type == BCM43xx_PHYTYPE_G)); - break; - case BCM43xx_LED_MODE_BG: - if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) && - 1/*FIXME: using G rates.*/) - turn_on = 1; - break; - case BCM43xx_LED_TRANSFER: - if (transferring) - bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); - else - bcm43xx_led_blink_stop(led, 0); - continue; - case BCM43xx_LED_APTRANSFER: - if (bcm->ieee->iw_mode == IW_MODE_MASTER) { - if (transferring) { - interval = BCM43xx_LEDBLINK_FAST; - turn_on = 1; - } - } else { - turn_on = 1; - if (0/*TODO: not assoc*/) - interval = BCM43xx_LEDBLINK_SLOW; - else if (transferring) - interval = BCM43xx_LEDBLINK_FAST; - else - turn_on = 0; - } - if (turn_on) - bcm43xx_led_blink_start(led, interval); - else - bcm43xx_led_blink_stop(led, 0); - continue; - case BCM43xx_LED_WEIRD: - //TODO - break; - case BCM43xx_LED_ASSOC: - if (bcm->softmac->associnfo.associated) - turn_on = 1; - break; -#ifdef CONFIG_BCM43XX_DEBUG - case BCM43xx_LED_TEST_BLINKSLOW: - bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW); - continue; - case BCM43xx_LED_TEST_BLINKMEDIUM: - bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); - continue; - case BCM43xx_LED_TEST_BLINKFAST: - bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST); - continue; -#endif /* CONFIG_BCM43XX_DEBUG */ - default: - dprintkl(KERN_INFO PFX "Bad value in leds_update," - " led->behaviour: 0x%x\n", led->behaviour); - }; - - if (led->activelow) - turn_on = !turn_on; - if (turn_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&bcm->leds_lock, flags); -} - -void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) -{ - struct bcm43xx_led *led; - u16 ledctl; - int i; - int bit_on; - unsigned long flags; - - spin_lock_irqsave(&bcm->leds_lock, flags); - ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - for (i = 0; i < BCM43xx_NR_LEDS; i++) { - led = &(bcm->leds[i]); - if (led->behaviour == BCM43xx_LED_INACTIVE) - continue; - if (on) - bit_on = led->activelow ? 0 : 1; - else - bit_on = led->activelow ? 1 : 0; - if (bit_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&bcm->leds_lock, flags); -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h deleted file mode 100644 index 811e14a8119..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef BCM43xx_LEDS_H_ -#define BCM43xx_LEDS_H_ - -#include <linux/types.h> -#include <linux/timer.h> - - -struct bcm43xx_led { - u8 behaviour:7; - u8 activelow:1; - - struct bcm43xx_private *bcm; - struct timer_list blink_timer; - unsigned long blink_interval; -}; -#define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) - -/* Delay between state changes when blinking in jiffies */ -#define BCM43xx_LEDBLINK_SLOW (HZ / 1) -#define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) -#define BCM43xx_LEDBLINK_FAST (HZ / 8) - -#define BCM43xx_LED_XFER_THRES (HZ / 100) - -#define BCM43xx_LED_BEHAVIOUR 0x7F -#define BCM43xx_LED_ACTIVELOW 0x80 -enum { /* LED behaviour values */ - BCM43xx_LED_OFF, - BCM43xx_LED_ON, - BCM43xx_LED_ACTIVITY, - BCM43xx_LED_RADIO_ALL, - BCM43xx_LED_RADIO_A, - BCM43xx_LED_RADIO_B, - BCM43xx_LED_MODE_BG, - BCM43xx_LED_TRANSFER, - BCM43xx_LED_APTRANSFER, - BCM43xx_LED_WEIRD,//FIXME - BCM43xx_LED_ASSOC, - BCM43xx_LED_INACTIVE, - - /* Behaviour values for testing. - * With these values it is easier to figure out - * the real behaviour of leds, in case the SPROM - * is missing information. - */ - BCM43xx_LED_TEST_BLINKSLOW, - BCM43xx_LED_TEST_BLINKMEDIUM, - BCM43xx_LED_TEST_BLINKFAST, - - /* Misc values for BCM4303 */ - BCM43xx_LED_BCM4303_0 = 0x2B, - BCM43xx_LED_BCM4303_1 = 0x78, - BCM43xx_LED_BCM4303_2 = 0x2E, - BCM43xx_LED_BCM4303_3 = 0x19, -}; - -int bcm43xx_leds_init(struct bcm43xx_private *bcm); -void bcm43xx_leds_exit(struct bcm43xx_private *bcm); -void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); -void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on); - -#endif /* BCM43xx_LEDS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c deleted file mode 100644 index b96a325b6ec..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ /dev/null @@ -1,4281 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/moduleparam.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/version.h> -#include <linux/firmware.h> -#include <linux/wireless.h> -#include <linux/workqueue.h> -#include <linux/skbuff.h> -#include <linux/dma-mapping.h> -#include <net/iw_handler.h> - -#include "bcm43xx.h" -#include "bcm43xx_main.h" -#include "bcm43xx_debugfs.h" -#include "bcm43xx_radio.h" -#include "bcm43xx_phy.h" -#include "bcm43xx_dma.h" -#include "bcm43xx_pio.h" -#include "bcm43xx_power.h" -#include "bcm43xx_wx.h" -#include "bcm43xx_ethtool.h" -#include "bcm43xx_xmit.h" -#include "bcm43xx_sysfs.h" - - -MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); -MODULE_AUTHOR("Martin Langer"); -MODULE_AUTHOR("Stefano Brivio"); -MODULE_AUTHOR("Michael Buesch"); -MODULE_LICENSE("GPL"); - -#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) -static int modparam_pio; -module_param_named(pio, modparam_pio, int, 0444); -MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); -#elif defined(CONFIG_BCM43XX_DMA) -# define modparam_pio 0 -#elif defined(CONFIG_BCM43XX_PIO) -# define modparam_pio 1 -#endif - -static int modparam_bad_frames_preempt; -module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); -MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); - -static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT; -module_param_named(short_retry, modparam_short_retry, int, 0444); -MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); - -static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT; -module_param_named(long_retry, modparam_long_retry, int, 0444); -MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); - -static int modparam_locale = -1; -module_param_named(locale, modparam_locale, int, 0444); -MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); - -static int modparam_noleds; -module_param_named(noleds, modparam_noleds, int, 0444); -MODULE_PARM_DESC(noleds, "Turn off all LED activity"); - -static char modparam_fwpostfix[64]; -module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); -MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions."); - - -/* If you want to debug with just a single device, enable this, - * where the string is the pci device ID (as given by the kernel's - * pci_name function) of the device to be used. - */ -//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0" - -/* If you want to enable printing of each MMIO access, enable this. */ -//#define DEBUG_ENABLE_MMIO_PRINT - -/* If you want to enable printing of MMIO access within - * ucode/pcm upload, initvals write, enable this. - */ -//#define DEBUG_ENABLE_UCODE_MMIO_PRINT - -/* If you want to enable printing of PCI Config Space access, enable this */ -//#define DEBUG_ENABLE_PCILOG - - -/* Detailed list maintained at: - * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices - */ - static struct pci_device_id bcm43xx_pci_tbl[] = { - /* Broadcom 4303 802.11b */ - { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4307 802.11b */ - { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4311 802.11(a)/b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4312 802.11a/b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4318 802.11b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4319 802.11a/b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4306 802.11b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4306 802.11a */ -// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4309 802.11a/b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 43XG 802.11b/g */ - { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0 }, -}; -MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); - -static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) -{ - u32 status; - - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP)) - val = swab32(val); - - bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); - mmiowb(); - bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); -} - -static inline -void bcm43xx_shm_control_word(struct bcm43xx_private *bcm, - u16 routing, u16 offset) -{ - u32 control; - - /* "offset" is the WORD offset. */ - - control = routing; - control <<= 16; - control |= offset; - bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control); -} - -u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, - u16 routing, u16 offset) -{ - u32 ret; - - if (routing == BCM43xx_SHM_SHARED) { - if (offset & 0x0003) { - /* Unaligned access */ - bcm43xx_shm_control_word(bcm, routing, offset >> 2); - ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); - ret <<= 16; - bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); - ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); - - return ret; - } - offset >>= 2; - } - bcm43xx_shm_control_word(bcm, routing, offset); - ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA); - - return ret; -} - -u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, - u16 routing, u16 offset) -{ - u16 ret; - - if (routing == BCM43xx_SHM_SHARED) { - if (offset & 0x0003) { - /* Unaligned access */ - bcm43xx_shm_control_word(bcm, routing, offset >> 2); - ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); - - return ret; - } - offset >>= 2; - } - bcm43xx_shm_control_word(bcm, routing, offset); - ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); - - return ret; -} - -void bcm43xx_shm_write32(struct bcm43xx_private *bcm, - u16 routing, u16 offset, - u32 value) -{ - if (routing == BCM43xx_SHM_SHARED) { - if (offset & 0x0003) { - /* Unaligned access */ - bcm43xx_shm_control_word(bcm, routing, offset >> 2); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, - (value >> 16) & 0xffff); - mmiowb(); - bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, - value & 0xffff); - return; - } - offset >>= 2; - } - bcm43xx_shm_control_word(bcm, routing, offset); - mmiowb(); - bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); -} - -void bcm43xx_shm_write16(struct bcm43xx_private *bcm, - u16 routing, u16 offset, - u16 value) -{ - if (routing == BCM43xx_SHM_SHARED) { - if (offset & 0x0003) { - /* Unaligned access */ - bcm43xx_shm_control_word(bcm, routing, offset >> 2); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, - value); - return; - } - offset >>= 2; - } - bcm43xx_shm_control_word(bcm, routing, offset); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); -} - -void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf) -{ - /* We need to be careful. As we read the TSF from multiple - * registers, we should take care of register overflows. - * In theory, the whole tsf read process should be atomic. - * We try to be atomic here, by restaring the read process, - * if any of the high registers changed (overflew). - */ - if (bcm->current_core->rev >= 3) { - u32 low, high, high2; - - do { - high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); - low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW); - high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); - } while (unlikely(high != high2)); - - *tsf = high; - *tsf <<= 32; - *tsf |= low; - } else { - u64 tmp; - u16 v0, v1, v2, v3; - u16 test1, test2, test3; - - do { - v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); - v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); - v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); - v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0); - - test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); - test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); - test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); - } while (v3 != test3 || v2 != test2 || v1 != test1); - - *tsf = v3; - *tsf <<= 48; - tmp = v2; - tmp <<= 32; - *tsf |= tmp; - tmp = v1; - tmp <<= 16; - *tsf |= tmp; - *tsf |= v0; - } -} - -void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) -{ - u32 status; - - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - status |= BCM43xx_SBF_TIME_UPDATE; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - mmiowb(); - - /* Be careful with the in-progress timer. - * First zero out the low register, so we have a full - * register-overflow duration to complete the operation. - */ - if (bcm->current_core->rev >= 3) { - u32 lo = (tsf & 0x00000000FFFFFFFFULL); - u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; - - bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); - mmiowb(); - bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); - mmiowb(); - bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); - } else { - u16 v0 = (tsf & 0x000000000000FFFFULL); - u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; - u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; - u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; - - bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); - } - - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - status &= ~BCM43xx_SBF_TIME_UPDATE; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); -} - -static -void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, - u16 offset, - const u8 *mac) -{ - u16 data; - - offset |= 0x0020; - bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset); - - data = mac[0]; - data |= mac[1] << 8; - bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); - data = mac[2]; - data |= mac[3] << 8; - bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); - data = mac[4]; - data |= mac[5] << 8; - bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); -} - -static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, - u16 offset) -{ - const u8 zero_addr[ETH_ALEN] = { 0 }; - - bcm43xx_macfilter_set(bcm, offset, zero_addr); -} - -static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) -{ - const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); - const u8 *bssid = (const u8 *)(bcm->ieee->bssid); - u8 mac_bssid[ETH_ALEN * 2]; - int i; - - memcpy(mac_bssid, mac, ETH_ALEN); - memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); - - /* Write our MAC address and BSSID to template ram */ - for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) - bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i))); - for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) - bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i))); - for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) - bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); -} - -//FIXME: Well, we should probably call them from somewhere. -#if 0 -static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) -{ - /* slot_time is in usec. */ - if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G) - return; - bcm43xx_write16(bcm, 0x684, 510 + slot_time); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); -} - -static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) -{ - bcm43xx_set_slot_time(bcm, 9); -} - -static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) -{ - bcm43xx_set_slot_time(bcm, 20); -} -#endif - -/* FIXME: To get the MAC-filter working, we need to implement the - * following functions (and rename them :) - */ -#if 0 -static void bcm43xx_disassociate(struct bcm43xx_private *bcm) -{ - bcm43xx_mac_suspend(bcm); - bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); - - bcm43xx_ram_write(bcm, 0x0026, 0x0000); - bcm43xx_ram_write(bcm, 0x0028, 0x0000); - bcm43xx_ram_write(bcm, 0x007E, 0x0000); - bcm43xx_ram_write(bcm, 0x0080, 0x0000); - bcm43xx_ram_write(bcm, 0x047E, 0x0000); - bcm43xx_ram_write(bcm, 0x0480, 0x0000); - - if (bcm->current_core->rev < 3) { - bcm43xx_write16(bcm, 0x0610, 0x8000); - bcm43xx_write16(bcm, 0x060E, 0x0000); - } else - bcm43xx_write32(bcm, 0x0188, 0x80000000); - - bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); - - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G && - ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) - bcm43xx_short_slot_timing_enable(bcm); - - bcm43xx_mac_enable(bcm); -} - -static void bcm43xx_associate(struct bcm43xx_private *bcm, - const u8 *mac) -{ - memcpy(bcm->ieee->bssid, mac, ETH_ALEN); - - bcm43xx_mac_suspend(bcm); - bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac); - bcm43xx_write_mac_bssid_templates(bcm); - bcm43xx_mac_enable(bcm); -} -#endif - -/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask) -{ - u32 old_mask; - - old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask); - - return old_mask; -} - -/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask) -{ - u32 old_mask; - - old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask); - - return old_mask; -} - -/* Synchronize IRQ top- and bottom-half. - * IRQs must be masked before calling this. - * This must not be called with the irq_lock held. - */ -static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm) -{ - synchronize_irq(bcm->irq); - tasklet_disable(&bcm->isr_tasklet); -} - -/* Make sure we don't receive more data from the device. */ -static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm) -{ - unsigned long flags; - - spin_lock_irqsave(&bcm->irq_lock, flags); - if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { - spin_unlock_irqrestore(&bcm->irq_lock, flags); - return -EBUSY; - } - bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */ - spin_unlock_irqrestore(&bcm->irq_lock, flags); - bcm43xx_synchronize_irq(bcm); - - return 0; -} - -static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u32 radio_id; - u16 manufact; - u16 version; - u8 revision; - - if (bcm->chip_id == 0x4317) { - if (bcm->chip_rev == 0x00) - radio_id = 0x3205017F; - else if (bcm->chip_rev == 0x01) - radio_id = 0x4205017F; - else - radio_id = 0x5205017F; - } else { - bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); - radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH); - radio_id <<= 16; - bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); - radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); - } - - manufact = (radio_id & 0x00000FFF); - version = (radio_id & 0x0FFFF000) >> 12; - revision = (radio_id & 0xF0000000) >> 28; - - dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", - radio_id, manufact, version, revision); - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) - goto err_unsupported_radio; - break; - case BCM43xx_PHYTYPE_B: - if ((version & 0xFFF0) != 0x2050) - goto err_unsupported_radio; - break; - case BCM43xx_PHYTYPE_G: - if (version != 0x2050) - goto err_unsupported_radio; - break; - } - - radio->manufact = manufact; - radio->version = version; - radio->revision = revision; - - if (phy->type == BCM43xx_PHYTYPE_A) - radio->txpower_desired = bcm->sprom.maxpower_aphy; - else - radio->txpower_desired = bcm->sprom.maxpower_bgphy; - - return 0; - -err_unsupported_radio: - printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n"); - return -ENODEV; -} - -static const char * bcm43xx_locale_iso(u8 locale) -{ - /* ISO 3166-1 country codes. - * Note that there aren't ISO 3166-1 codes for - * all or locales. (Not all locales are countries) - */ - switch (locale) { - case BCM43xx_LOCALE_WORLD: - case BCM43xx_LOCALE_ALL: - return "XX"; - case BCM43xx_LOCALE_THAILAND: - return "TH"; - case BCM43xx_LOCALE_ISRAEL: - return "IL"; - case BCM43xx_LOCALE_JORDAN: - return "JO"; - case BCM43xx_LOCALE_CHINA: - return "CN"; - case BCM43xx_LOCALE_JAPAN: - case BCM43xx_LOCALE_JAPAN_HIGH: - return "JP"; - case BCM43xx_LOCALE_USA_CANADA_ANZ: - case BCM43xx_LOCALE_USA_LOW: - return "US"; - case BCM43xx_LOCALE_EUROPE: - return "EU"; - case BCM43xx_LOCALE_NONE: - return " "; - } - assert(0); - return " "; -} - -static const char * bcm43xx_locale_string(u8 locale) -{ - switch (locale) { - case BCM43xx_LOCALE_WORLD: - return "World"; - case BCM43xx_LOCALE_THAILAND: - return "Thailand"; - case BCM43xx_LOCALE_ISRAEL: - return "Israel"; - case BCM43xx_LOCALE_JORDAN: - return "Jordan"; - case BCM43xx_LOCALE_CHINA: - return "China"; - case BCM43xx_LOCALE_JAPAN: - return "Japan"; - case BCM43xx_LOCALE_USA_CANADA_ANZ: - return "USA/Canada/ANZ"; - case BCM43xx_LOCALE_EUROPE: - return "Europe"; - case BCM43xx_LOCALE_USA_LOW: - return "USAlow"; - case BCM43xx_LOCALE_JAPAN_HIGH: - return "JapanHigh"; - case BCM43xx_LOCALE_ALL: - return "All"; - case BCM43xx_LOCALE_NONE: - return "None"; - } - assert(0); - return ""; -} - -static inline u8 bcm43xx_crc8(u8 crc, u8 data) -{ - static const u8 t[] = { - 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, - 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, - 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, - 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, - 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, - 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, - 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, - 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, - 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, - 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, - 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, - 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, - 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, - 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, - 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, - 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, - 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, - 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, - 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, - 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, - 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, - 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, - 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, - 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, - 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, - 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, - 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, - 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, - 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, - 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, - 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, - 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, - }; - return t[crc ^ data]; -} - -static u8 bcm43xx_sprom_crc(const u16 *sprom) -{ - int word; - u8 crc = 0xFF; - - for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) { - crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF); - crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8); - } - crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF); - crc ^= 0xFF; - - return crc; -} - -int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom) -{ - int i; - u8 crc, expected_crc; - - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) - sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); - /* CRC-8 check. */ - crc = bcm43xx_sprom_crc(sprom); - expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; - if (crc != expected_crc) { - printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " - "(0x%02X, expected: 0x%02X)\n", - crc, expected_crc); - return -EINVAL; - } - - return 0; -} - -int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) -{ - int i, err; - u8 crc, expected_crc; - u32 spromctl; - - /* CRC-8 validation of the input data. */ - crc = bcm43xx_sprom_crc(sprom); - expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; - if (crc != expected_crc) { - printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); - return -EINVAL; - } - - printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); - if (err) - goto err_ctlreg; - spromctl |= 0x10; /* SPROM WRITE enable. */ - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); - if (err) - goto err_ctlreg; - /* We must burn lots of CPU cycles here, but that does not - * really matter as one does not write the SPROM every other minute... - */ - printk(KERN_INFO PFX "[ 0%%"); - mdelay(500); - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - if (i == 16) - printk("25%%"); - else if (i == 32) - printk("50%%"); - else if (i == 48) - printk("75%%"); - else if (i % 2) - printk("."); - bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); - mmiowb(); - mdelay(20); - } - spromctl &= ~0x10; /* SPROM WRITE enable. */ - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); - if (err) - goto err_ctlreg; - mdelay(500); - printk("100%% ]\n"); - printk(KERN_INFO PFX "SPROM written.\n"); - bcm43xx_controller_restart(bcm, "SPROM update"); - - return 0; -err_ctlreg: - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); - return -ENODEV; -} - -static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) -{ - u16 value; - u16 *sprom; - - sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), - GFP_KERNEL); - if (!sprom) { - printk(KERN_ERR PFX "sprom_extract OOM\n"); - return -ENOMEM; - } - bcm43xx_sprom_read(bcm, sprom); - - /* boardflags2 */ - value = sprom[BCM43xx_SPROM_BOARDFLAGS2]; - bcm->sprom.boardflags2 = value; - - /* il0macaddr */ - value = sprom[BCM43xx_SPROM_IL0MACADDR + 0]; - *(((__be16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); - value = sprom[BCM43xx_SPROM_IL0MACADDR + 1]; - *(((__be16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); - value = sprom[BCM43xx_SPROM_IL0MACADDR + 2]; - *(((__be16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); - - /* et0macaddr */ - value = sprom[BCM43xx_SPROM_ET0MACADDR + 0]; - *(((__be16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); - value = sprom[BCM43xx_SPROM_ET0MACADDR + 1]; - *(((__be16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); - value = sprom[BCM43xx_SPROM_ET0MACADDR + 2]; - *(((__be16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); - - /* et1macaddr */ - value = sprom[BCM43xx_SPROM_ET1MACADDR + 0]; - *(((__be16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); - value = sprom[BCM43xx_SPROM_ET1MACADDR + 1]; - *(((__be16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); - value = sprom[BCM43xx_SPROM_ET1MACADDR + 2]; - *(((__be16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); - - /* ethernet phy settings */ - value = sprom[BCM43xx_SPROM_ETHPHY]; - bcm->sprom.et0phyaddr = (value & 0x001F); - bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5; - - /* boardrev, antennas, locale */ - value = sprom[BCM43xx_SPROM_BOARDREV]; - bcm->sprom.boardrev = (value & 0x00FF); - bcm->sprom.locale = (value & 0x0F00) >> 8; - bcm->sprom.antennas_aphy = (value & 0x3000) >> 12; - bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14; - if (modparam_locale != -1) { - if (modparam_locale >= 0 && modparam_locale <= 11) { - bcm->sprom.locale = modparam_locale; - printk(KERN_WARNING PFX "Operating with modified " - "LocaleCode %u (%s)\n", - bcm->sprom.locale, - bcm43xx_locale_string(bcm->sprom.locale)); - } else { - printk(KERN_WARNING PFX "Module parameter \"locale\" " - "invalid value. (0 - 11)\n"); - } - } - - /* pa0b* */ - value = sprom[BCM43xx_SPROM_PA0B0]; - bcm->sprom.pa0b0 = value; - value = sprom[BCM43xx_SPROM_PA0B1]; - bcm->sprom.pa0b1 = value; - value = sprom[BCM43xx_SPROM_PA0B2]; - bcm->sprom.pa0b2 = value; - - /* wl0gpio* */ - value = sprom[BCM43xx_SPROM_WL0GPIO0]; - if (value == 0x0000) - value = 0xFFFF; - bcm->sprom.wl0gpio0 = value & 0x00FF; - bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8; - value = sprom[BCM43xx_SPROM_WL0GPIO2]; - if (value == 0x0000) - value = 0xFFFF; - bcm->sprom.wl0gpio2 = value & 0x00FF; - bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8; - - /* maxpower */ - value = sprom[BCM43xx_SPROM_MAXPWR]; - bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8; - bcm->sprom.maxpower_bgphy = value & 0x00FF; - - /* pa1b* */ - value = sprom[BCM43xx_SPROM_PA1B0]; - bcm->sprom.pa1b0 = value; - value = sprom[BCM43xx_SPROM_PA1B1]; - bcm->sprom.pa1b1 = value; - value = sprom[BCM43xx_SPROM_PA1B2]; - bcm->sprom.pa1b2 = value; - - /* idle tssi target */ - value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT]; - bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF; - bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8; - - /* boardflags */ - value = sprom[BCM43xx_SPROM_BOARDFLAGS]; - if (value == 0xFFFF) - value = 0x0000; - bcm->sprom.boardflags = value; - /* boardflags workarounds */ - if (bcm->board_vendor == PCI_VENDOR_ID_DELL && - bcm->chip_id == 0x4301 && - bcm->board_revision == 0x74) - bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST; - if (bcm->board_vendor == PCI_VENDOR_ID_APPLE && - bcm->board_type == 0x4E && - bcm->board_revision > 0x40) - bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL; - - /* antenna gain */ - value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; - if (value == 0x0000 || value == 0xFFFF) - value = 0x0202; - /* convert values to Q5.2 */ - bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4; - bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4; - - kfree(sprom); - - return 0; -} - -static int bcm43xx_geo_init(struct bcm43xx_private *bcm) -{ - struct ieee80211_geo *geo; - struct ieee80211_channel *chan; - int have_a = 0, have_bg = 0; - int i; - u8 channel; - struct bcm43xx_phyinfo *phy; - const char *iso_country; - u8 max_bg_channel; - - geo = kzalloc(sizeof(*geo), GFP_KERNEL); - if (!geo) - return -ENOMEM; - - for (i = 0; i < bcm->nr_80211_available; i++) { - phy = &(bcm->core_80211_ext[i].phy); - switch (phy->type) { - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - have_bg = 1; - break; - case BCM43xx_PHYTYPE_A: - have_a = 1; - break; - default: - assert(0); - } - } - iso_country = bcm43xx_locale_iso(bcm->sprom.locale); - -/* set the maximum channel based on locale set in sprom or witle locale option */ - switch (bcm->sprom.locale) { - case BCM43xx_LOCALE_THAILAND: - case BCM43xx_LOCALE_ISRAEL: - case BCM43xx_LOCALE_JORDAN: - case BCM43xx_LOCALE_USA_CANADA_ANZ: - case BCM43xx_LOCALE_USA_LOW: - max_bg_channel = 11; - break; - case BCM43xx_LOCALE_JAPAN: - case BCM43xx_LOCALE_JAPAN_HIGH: - max_bg_channel = 14; - break; - default: - max_bg_channel = 13; - } - - if (have_a) { - for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL; - channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) { - chan = &geo->a[i++]; - chan->freq = bcm43xx_channel_to_freq_a(channel); - chan->channel = channel; - } - geo->a_channels = i; - } - if (have_bg) { - for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL; - channel <= max_bg_channel; channel++) { - chan = &geo->bg[i++]; - chan->freq = bcm43xx_channel_to_freq_bg(channel); - chan->channel = channel; - } - geo->bg_channels = i; - } - memcpy(geo->name, iso_country, 2); - if (0 /*TODO: Outdoor use only */) - geo->name[2] = 'O'; - else if (0 /*TODO: Indoor use only */) - geo->name[2] = 'I'; - else - geo->name[2] = ' '; - geo->name[3] = '\0'; - - ieee80211_set_geo(bcm->ieee, geo); - kfree(geo); - - return 0; -} - -/* DummyTransmission function, as documented on - * http://bcm-specs.sipsolutions.net/DummyTransmission - */ -void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - unsigned int i, max_loop; - u16 value = 0; - u32 buffer[5] = { - 0x00000000, - 0x0000D400, - 0x00000000, - 0x00000001, - 0x00000000, - }; - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - max_loop = 0x1E; - buffer[0] = 0xCC010200; - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - max_loop = 0xFA; - buffer[0] = 0x6E840B00; - break; - default: - assert(0); - return; - } - - for (i = 0; i < 5; i++) - bcm43xx_ram_write(bcm, i * 4, buffer[i]); - - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ - - bcm43xx_write16(bcm, 0x0568, 0x0000); - bcm43xx_write16(bcm, 0x07C0, 0x0000); - bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); - bcm43xx_write16(bcm, 0x0508, 0x0000); - bcm43xx_write16(bcm, 0x050A, 0x0000); - bcm43xx_write16(bcm, 0x054C, 0x0000); - bcm43xx_write16(bcm, 0x056A, 0x0014); - bcm43xx_write16(bcm, 0x0568, 0x0826); - bcm43xx_write16(bcm, 0x0500, 0x0000); - bcm43xx_write16(bcm, 0x0502, 0x0030); - - if (radio->version == 0x2050 && radio->revision <= 0x5) - bcm43xx_radio_write16(bcm, 0x0051, 0x0017); - for (i = 0x00; i < max_loop; i++) { - value = bcm43xx_read16(bcm, 0x050E); - if (value & 0x0080) - break; - udelay(10); - } - for (i = 0x00; i < 0x0A; i++) { - value = bcm43xx_read16(bcm, 0x050E); - if (value & 0x0400) - break; - udelay(10); - } - for (i = 0x00; i < 0x0A; i++) { - value = bcm43xx_read16(bcm, 0x0690); - if (!(value & 0x0100)) - break; - udelay(10); - } - if (radio->version == 0x2050 && radio->revision <= 0x5) - bcm43xx_radio_write16(bcm, 0x0051, 0x0037); -} - -static void key_write(struct bcm43xx_private *bcm, - u8 index, u8 algorithm, const __le16 *key) -{ - unsigned int i, basic_wep = 0; - u32 offset; - u16 value; - - /* Write associated key information */ - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2), - ((index << 4) | (algorithm & 0x0F))); - - /* The first 4 WEP keys need extra love */ - if (((algorithm == BCM43xx_SEC_ALGO_WEP) || - (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4)) - basic_wep = 1; - - /* Write key payload, 8 little endian words */ - offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); - for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { - value = le16_to_cpu(key[i]); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, - offset + (i * 2), value); - - if (!basic_wep) - continue; - - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, - offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE, - value); - } -} - -static void keymac_write(struct bcm43xx_private *bcm, - u8 index, const __be32 *addr) -{ - /* for keys 0-3 there is no associated mac address */ - if (index < 4) - return; - - index -= 4; - if (bcm->current_core->rev >= 5) { - bcm43xx_shm_write32(bcm, - BCM43xx_SHM_HWMAC, - index * 2, - be32_to_cpu(*addr)); - bcm43xx_shm_write16(bcm, - BCM43xx_SHM_HWMAC, - (index * 2) + 1, - be16_to_cpu(*((__be16 *)(addr + 1)))); - } else { - if (index < 8) { - TODO(); /* Put them in the macaddress filter */ - } else { - TODO(); - /* Put them BCM43xx_SHM_SHARED, stating index 0x0120. - Keep in mind to update the count of keymacs in 0x003E as well! */ - } - } -} - -static int bcm43xx_key_write(struct bcm43xx_private *bcm, - u8 index, u8 algorithm, - const u8 *_key, int key_len, - const u8 *mac_addr) -{ - u8 key[BCM43xx_SEC_KEYSIZE] = { 0 }; - - if (index >= ARRAY_SIZE(bcm->key)) - return -EINVAL; - if (key_len > ARRAY_SIZE(key)) - return -EINVAL; - if (algorithm < 1 || algorithm > 5) - return -EINVAL; - - memcpy(key, _key, key_len); - key_write(bcm, index, algorithm, (const __le16 *)key); - keymac_write(bcm, index, (const __be32 *)mac_addr); - - bcm->key[index].algorithm = algorithm; - - return 0; -} - -static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) -{ - static const __be32 zero_mac[2] = { 0 }; - unsigned int i,j, nr_keys = 54; - u16 offset; - - if (bcm->current_core->rev < 5) - nr_keys = 16; - assert(nr_keys <= ARRAY_SIZE(bcm->key)); - - for (i = 0; i < nr_keys; i++) { - bcm->key[i].enabled = 0; - /* returns for i < 4 immediately */ - keymac_write(bcm, i, zero_mac); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, - 0x100 + (i * 2), 0x0000); - for (j = 0; j < 8; j++) { - offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, - offset, 0x0000); - } - } - dprintk(KERN_INFO PFX "Keys cleared\n"); -} - -/* Lowlevel core-switch function. This is only to be used in - * bcm43xx_switch_core() and bcm43xx_probe_cores() - */ -static int _switch_core(struct bcm43xx_private *bcm, int core) -{ - int err; - int attempts = 0; - u32 current_core; - - assert(core >= 0); - while (1) { - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, - (core * 0x1000) + 0x18000000); - if (unlikely(err)) - goto error; - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, - ¤t_core); - if (unlikely(err)) - goto error; - current_core = (current_core - 0x18000000) / 0x1000; - if (current_core == core) - break; - - if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) - goto error; - udelay(10); - } - - return 0; -error: - printk(KERN_ERR PFX "Failed to switch to core %d\n", core); - return -ENODEV; -} - -int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) -{ - int err; - - if (unlikely(!new_core)) - return 0; - if (!new_core->available) - return -ENODEV; - if (bcm->current_core == new_core) - return 0; - err = _switch_core(bcm, new_core->index); - if (unlikely(err)) - goto out; - - bcm->current_core = new_core; -out: - return err; -} - -static int bcm43xx_core_enabled(struct bcm43xx_private *bcm) -{ - u32 value; - - value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET - | BCM43xx_SBTMSTATELOW_REJECT; - - return (value == BCM43xx_SBTMSTATELOW_CLOCK); -} - -/* disable current core */ -static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) -{ - u32 sbtmstatelow; - u32 sbtmstatehigh; - int i; - - /* fetch sbtmstatelow from core information registers */ - sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - - /* core is already in reset */ - if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET) - goto out; - - if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) { - sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | - BCM43xx_SBTMSTATELOW_REJECT; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - - for (i = 0; i < 1000; i++) { - sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) { - i = -1; - break; - } - udelay(10); - } - if (i != -1) { - printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n"); - return -EBUSY; - } - - for (i = 0; i < 1000; i++) { - sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); - if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) { - i = -1; - break; - } - udelay(10); - } - if (i != -1) { - printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n"); - return -EBUSY; - } - - sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | - BCM43xx_SBTMSTATELOW_REJECT | - BCM43xx_SBTMSTATELOW_RESET | - BCM43xx_SBTMSTATELOW_CLOCK | - core_flags; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - udelay(10); - } - - sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET | - BCM43xx_SBTMSTATELOW_REJECT | - core_flags; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - -out: - bcm->current_core->enabled = 0; - - return 0; -} - -/* enable (reset) current core */ -static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) -{ - u32 sbtmstatelow; - u32 sbtmstatehigh; - u32 sbimstate; - int err; - - err = bcm43xx_core_disable(bcm, core_flags); - if (err) - goto out; - - sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | - BCM43xx_SBTMSTATELOW_RESET | - BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | - core_flags; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - udelay(1); - - sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); - if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) { - sbtmstatehigh = 0x00000000; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh); - } - - sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE); - if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) { - sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT); - bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate); - } - - sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | - BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | - core_flags; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - udelay(1); - - sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - udelay(1); - - bcm->current_core->enabled = 1; - assert(err == 0); -out: - return err; -} - -/* http://bcm-specs.sipsolutions.net/80211CoreReset */ -void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) -{ - u32 flags = 0x00040000; - - if ((bcm43xx_core_enabled(bcm)) && - !bcm43xx_using_pio(bcm)) { - } - if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) { - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); - } else { - if (connect_phy) - flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; - bcm43xx_phy_connect(bcm, connect_phy); - bcm43xx_core_enable(bcm, flags); - bcm43xx_write16(bcm, 0x03E6, 0x0000); - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - | BCM43xx_SBF_400); - } -} - -static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) -{ - bcm43xx_radio_turn_off(bcm); - bcm43xx_write16(bcm, 0x03E6, 0x00F4); - bcm43xx_core_disable(bcm, 0); -} - -/* Mark the current 80211 core inactive. */ -static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm) -{ - u32 sbtmstatelow; - - bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_radio_turn_off(bcm); - sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow &= 0xDFF5FFFF; - sbtmstatelow |= 0x000A0000; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - udelay(1); - sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow &= 0xFFF5FFFF; - sbtmstatelow |= 0x00080000; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - udelay(1); -} - -static void handle_irq_transmit_status(struct bcm43xx_private *bcm) -{ - u32 v0, v1; - u16 tmp; - struct bcm43xx_xmitstatus stat; - - while (1) { - v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); - if (!v0) - break; - v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); - - stat.cookie = (v0 >> 16) & 0x0000FFFF; - tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1)); - stat.flags = tmp & 0xFF; - stat.cnt1 = (tmp & 0x0F00) >> 8; - stat.cnt2 = (tmp & 0xF000) >> 12; - stat.seq = (u16)(v1 & 0xFFFF); - stat.unknown = (u16)((v1 >> 16) & 0xFF); - - bcm43xx_debugfs_log_txstat(bcm, &stat); - - if (stat.flags & BCM43xx_TXSTAT_FLAG_AMPDU) - continue; - if (stat.flags & BCM43xx_TXSTAT_FLAG_INTER) - continue; - - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_handle_xmitstatus(bcm, &stat); - else - bcm43xx_dma_handle_xmitstatus(bcm, &stat); - } -} - -static void drain_txstatus_queue(struct bcm43xx_private *bcm) -{ - u32 dummy; - - if (bcm->current_core->rev < 5) - return; - /* Read all entries from the microcode TXstatus FIFO - * and throw them away. - */ - while (1) { - dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); - if (!dummy) - break; - dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); - } -} - -static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) -{ - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); - assert(bcm->noisecalc.core_at_start == bcm->current_core); - assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel); -} - -static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) -{ - /* Top half of Link Quality calculation. */ - - if (bcm->noisecalc.calculation_running) - return; - bcm->noisecalc.core_at_start = bcm->current_core; - bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel; - bcm->noisecalc.calculation_running = 1; - bcm->noisecalc.nr_samples = 0; - - bcm43xx_generate_noise_sample(bcm); -} - -static void handle_irq_noise(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 tmp; - u8 noise[4]; - u8 i, j; - s32 average; - - /* Bottom half of Link Quality calculation. */ - - assert(bcm->noisecalc.calculation_running); - if (bcm->noisecalc.core_at_start != bcm->current_core || - bcm->noisecalc.channel_at_start != radio->channel) - goto drop_calculation; - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408); - noise[0] = (tmp & 0x00FF); - noise[1] = (tmp & 0xFF00) >> 8; - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A); - noise[2] = (tmp & 0x00FF); - noise[3] = (tmp & 0xFF00) >> 8; - if (noise[0] == 0x7F || noise[1] == 0x7F || - noise[2] == 0x7F || noise[3] == 0x7F) - goto generate_new; - - /* Get the noise samples. */ - assert(bcm->noisecalc.nr_samples < 8); - i = bcm->noisecalc.nr_samples; - noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); - noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); - noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); - noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); - bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]]; - bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]]; - bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]]; - bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]]; - bcm->noisecalc.nr_samples++; - if (bcm->noisecalc.nr_samples == 8) { - /* Calculate the Link Quality by the noise samples. */ - average = 0; - for (i = 0; i < 8; i++) { - for (j = 0; j < 4; j++) - average += bcm->noisecalc.samples[i][j]; - } - average /= (8 * 4); - average *= 125; - average += 64; - average /= 128; - - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); - tmp = (tmp / 128) & 0x1F; - if (tmp >= 8) - average += 2; - else - average -= 25; - if (tmp == 8) - average -= 72; - else - average -= 48; - - bcm->stats.noise = average; -drop_calculation: - bcm->noisecalc.calculation_running = 0; - return; - } -generate_new: - bcm43xx_generate_noise_sample(bcm); -} - -static void handle_irq_ps(struct bcm43xx_private *bcm) -{ - if (bcm->ieee->iw_mode == IW_MODE_MASTER) { - ///TODO: PS TBTT - } else { - if (1/*FIXME: the last PSpoll frame was sent successfully */) - bcm43xx_power_saving_ctl_bits(bcm, -1, -1); - } - if (bcm->ieee->iw_mode == IW_MODE_ADHOC) - bcm->reg124_set_0x4 = 1; - //FIXME else set to false? -} - -static void handle_irq_reg124(struct bcm43xx_private *bcm) -{ - if (!bcm->reg124_set_0x4) - return; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) - | 0x4); - //FIXME: reset reg124_set_0x4 to false? -} - -static void handle_irq_pmq(struct bcm43xx_private *bcm) -{ - u32 tmp; - - //TODO: AP mode. - - while (1) { - tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS); - if (!(tmp & 0x00000008)) - break; - } - /* 16bit write is odd, but correct. */ - bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002); -} - -static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, - u16 ram_offset, u16 shm_size_offset) -{ - u32 value; - u16 size = 0; - - /* Timestamp. */ - //FIXME: assumption: The chip sets the timestamp - value = 0; - bcm43xx_ram_write(bcm, ram_offset++, value); - bcm43xx_ram_write(bcm, ram_offset++, value); - size += 8; - - /* Beacon Interval / Capability Information */ - value = 0x0000;//FIXME: Which interval? - value |= (1 << 0) << 16; /* ESS */ - value |= (1 << 2) << 16; /* CF Pollable */ //FIXME? - value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME? - if (!bcm->ieee->open_wep) - value |= (1 << 4) << 16; /* Privacy */ - bcm43xx_ram_write(bcm, ram_offset++, value); - size += 4; - - /* SSID */ - //TODO - - /* FH Parameter Set */ - //TODO - - /* DS Parameter Set */ - //TODO - - /* CF Parameter Set */ - //TODO - - /* TIM */ - //TODO - - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); -} - -static void handle_irq_beacon(struct bcm43xx_private *bcm) -{ - u32 status; - - bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON; - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD); - - if ((status & 0x1) && (status & 0x2)) { - /* ACK beacon IRQ. */ - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, - BCM43xx_IRQ_BEACON); - bcm->irq_savedstate |= BCM43xx_IRQ_BEACON; - return; - } - if (!(status & 0x1)) { - bcm43xx_generate_beacon_template(bcm, 0x68, 0x18); - status |= 0x1; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); - } - if (!(status & 0x2)) { - bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A); - status |= 0x2; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); - } -} - -/* Interrupt handler bottom-half */ -static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) -{ - u32 reason; - u32 dma_reason[6]; - u32 merged_dma_reason = 0; - int i, activity = 0; - unsigned long flags; - -#ifdef CONFIG_BCM43XX_DEBUG - u32 _handled = 0x00000000; -# define bcmirq_handled(irq) do { _handled |= (irq); } while (0) -#else -# define bcmirq_handled(irq) do { /* nothing */ } while (0) -#endif /* CONFIG_BCM43XX_DEBUG*/ - - spin_lock_irqsave(&bcm->irq_lock, flags); - reason = bcm->irq_reason; - for (i = 5; i >= 0; i--) { - dma_reason[i] = bcm->dma_reason[i]; - merged_dma_reason |= dma_reason[i]; - } - - if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { - /* TX error. We get this when Template Ram is written in wrong endianess - * in dummy_tx(). We also get this if something is wrong with the TX header - * on DMA or PIO queues. - * Maybe we get this in other error conditions, too. - */ - printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); - bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); - } - if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) { - printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " - "0x%08X, 0x%08X, 0x%08X, " - "0x%08X, 0x%08X, 0x%08X\n", - dma_reason[0], dma_reason[1], - dma_reason[2], dma_reason[3], - dma_reason[4], dma_reason[5]); - bcm43xx_controller_restart(bcm, "DMA error"); - mmiowb(); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - return; - } - if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) { - printkl(KERN_ERR PFX "DMA error: " - "0x%08X, 0x%08X, 0x%08X, " - "0x%08X, 0x%08X, 0x%08X\n", - dma_reason[0], dma_reason[1], - dma_reason[2], dma_reason[3], - dma_reason[4], dma_reason[5]); - } - - if (reason & BCM43xx_IRQ_PS) { - handle_irq_ps(bcm); - bcmirq_handled(BCM43xx_IRQ_PS); - } - - if (reason & BCM43xx_IRQ_REG124) { - handle_irq_reg124(bcm); - bcmirq_handled(BCM43xx_IRQ_REG124); - } - - if (reason & BCM43xx_IRQ_BEACON) { - if (bcm->ieee->iw_mode == IW_MODE_MASTER) - handle_irq_beacon(bcm); - bcmirq_handled(BCM43xx_IRQ_BEACON); - } - - if (reason & BCM43xx_IRQ_PMQ) { - handle_irq_pmq(bcm); - bcmirq_handled(BCM43xx_IRQ_PMQ); - } - - if (reason & BCM43xx_IRQ_SCAN) { - /*TODO*/ - //bcmirq_handled(BCM43xx_IRQ_SCAN); - } - - if (reason & BCM43xx_IRQ_NOISE) { - handle_irq_noise(bcm); - bcmirq_handled(BCM43xx_IRQ_NOISE); - } - - /* Check the DMA reason registers for received data. */ - if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); - else - bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); - /* We intentionally don't set "activity" to 1, here. */ - } - assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); - assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); - if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); - else - bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3); - activity = 1; - } - assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE)); - assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE)); - bcmirq_handled(BCM43xx_IRQ_RX); - - if (reason & BCM43xx_IRQ_XMIT_STATUS) { - handle_irq_transmit_status(bcm); - activity = 1; - //TODO: In AP mode, this also causes sending of powersave responses. - bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); - } - - /* IRQ_PIO_WORKAROUND is handled in the top-half. */ - bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); -#ifdef CONFIG_BCM43XX_DEBUG - if (unlikely(reason & ~_handled)) { - printkl(KERN_WARNING PFX - "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, " - "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", - reason, (reason & ~_handled), - dma_reason[0], dma_reason[1], - dma_reason[2], dma_reason[3]); - } -#endif -#undef bcmirq_handled - - if (!modparam_noleds) - bcm43xx_leds_update(bcm, activity); - bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - mmiowb(); - spin_unlock_irqrestore(&bcm->irq_lock, flags); -} - -static void pio_irq_workaround(struct bcm43xx_private *bcm, - u16 base, int queueidx) -{ - u16 rxctl; - - rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL); - if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE) - bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE; - else - bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE; -} - -static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) -{ - if (bcm43xx_using_pio(bcm) && - (bcm->current_core->rev < 3) && - (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { - /* Apply a PIO specific workaround to the dma_reasons */ - pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0); - pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1); - pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2); - pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3); - } - - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); - - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON, - bcm->dma_reason[0]); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, - bcm->dma_reason[1]); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, - bcm->dma_reason[2]); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, - bcm->dma_reason[3]); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, - bcm->dma_reason[4]); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON, - bcm->dma_reason[5]); -} - -/* Interrupt handler top-half */ -static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id) -{ - irqreturn_t ret = IRQ_HANDLED; - struct bcm43xx_private *bcm = dev_id; - u32 reason; - - if (!bcm) - return IRQ_NONE; - - spin_lock(&bcm->irq_lock); - - reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (reason == 0xffffffff) { - /* irq not for us (shared irq) */ - ret = IRQ_NONE; - goto out; - } - reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - if (!reason) - goto out; - - assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - assert(bcm->current_core->id == BCM43xx_COREID_80211); - - bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON) - & 0x0001DC00; - bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) - & 0x0000DC00; - bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) - & 0x0000DC00; - bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) - & 0x0001DC00; - bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) - & 0x0000DC00; - bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON) - & 0x0000DC00; - - bcm43xx_interrupt_ack(bcm, reason); - - /* disable all IRQs. They are enabled again in the bottom half. */ - bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - /* save the reason code and call our bottom half. */ - bcm->irq_reason = reason; - tasklet_schedule(&bcm->isr_tasklet); - -out: - mmiowb(); - spin_unlock(&bcm->irq_lock); - - return ret; -} - -static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - if (bcm->firmware_norelease && !force) - return; /* Suspending or controller reset. */ - release_firmware(phy->ucode); - phy->ucode = NULL; - release_firmware(phy->pcm); - phy->pcm = NULL; - release_firmware(phy->initvals0); - phy->initvals0 = NULL; - release_firmware(phy->initvals1); - phy->initvals1 = NULL; -} - -static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u8 rev = bcm->current_core->rev; - int err = 0; - int nr; - char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; - - if (!phy->ucode) { - snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", - (rev >= 5 ? 5 : rev), - modparam_fwpostfix); - err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev); - if (err) { - printk(KERN_ERR PFX - "Error: Microcode \"%s\" not available or load failed.\n", - buf); - goto error; - } - } - - if (!phy->pcm) { - snprintf(buf, ARRAY_SIZE(buf), - "bcm43xx_pcm%d%s.fw", - (rev < 5 ? 4 : 5), - modparam_fwpostfix); - err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev); - if (err) { - printk(KERN_ERR PFX - "Error: PCM \"%s\" not available or load failed.\n", - buf); - goto error; - } - } - - if (!phy->initvals0) { - if (rev == 2 || rev == 4) { - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - nr = 3; - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - nr = 1; - break; - default: - goto err_noinitval; - } - - } else if (rev >= 5) { - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - nr = 7; - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - nr = 5; - break; - default: - goto err_noinitval; - } - } else - goto err_noinitval; - snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", - nr, modparam_fwpostfix); - - err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev); - if (err) { - printk(KERN_ERR PFX - "Error: InitVals \"%s\" not available or load failed.\n", - buf); - goto error; - } - if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) { - printk(KERN_ERR PFX "InitVals fileformat error.\n"); - goto error; - } - } - - if (!phy->initvals1) { - if (rev >= 5) { - u32 sbtmstatehigh; - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); - if (sbtmstatehigh & 0x00010000) - nr = 9; - else - nr = 10; - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - nr = 6; - break; - default: - goto err_noinitval; - } - snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", - nr, modparam_fwpostfix); - - err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev); - if (err) { - printk(KERN_ERR PFX - "Error: InitVals \"%s\" not available or load failed.\n", - buf); - goto error; - } - if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) { - printk(KERN_ERR PFX "InitVals fileformat error.\n"); - goto error; - } - } - } - -out: - return err; -error: - bcm43xx_release_firmware(bcm, 1); - goto out; -err_noinitval: - printk(KERN_ERR PFX "Error: No InitVals available!\n"); - err = -ENOENT; - goto error; -} - -static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - const __be32 *data; - unsigned int i, len; - - /* Upload Microcode. */ - data = (__be32 *)(phy->ucode->data); - len = phy->ucode->size / sizeof(u32); - bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); - for (i = 0; i < len; i++) { - bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, - be32_to_cpu(data[i])); - udelay(10); - } - - /* Upload PCM data. */ - data = (__be32 *)(phy->pcm->data); - len = phy->pcm->size / sizeof(u32); - bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); - bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); - bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); - for (i = 0; i < len; i++) { - bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, - be32_to_cpu(data[i])); - udelay(10); - } -} - -static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, - const struct bcm43xx_initval *data, - const unsigned int len) -{ - u16 offset, size; - u32 value; - unsigned int i; - - for (i = 0; i < len; i++) { - offset = be16_to_cpu(data[i].offset); - size = be16_to_cpu(data[i].size); - value = be32_to_cpu(data[i].value); - - if (unlikely(offset >= 0x1000)) - goto err_format; - if (size == 2) { - if (unlikely(value & 0xFFFF0000)) - goto err_format; - bcm43xx_write16(bcm, offset, (u16)value); - } else if (size == 4) { - bcm43xx_write32(bcm, offset, value); - } else - goto err_format; - } - - return 0; - -err_format: - printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. " - "Please fix your bcm43xx firmware files.\n"); - return -EPROTO; -} - -static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - int err; - - err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data, - phy->initvals0->size / sizeof(struct bcm43xx_initval)); - if (err) - goto out; - if (phy->initvals1) { - err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data, - phy->initvals1->size / sizeof(struct bcm43xx_initval)); - if (err) - goto out; - } -out: - return err; -} - -static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) -{ - int err; - - bcm->irq = bcm->pci_dev->irq; - err = request_irq(bcm->irq, bcm43xx_interrupt_handler, - IRQF_SHARED, KBUILD_MODNAME, bcm); - if (err) - printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); - - return err; -} - -/* Switch to the core used to write the GPIO register. - * This is either the ChipCommon, or the PCI core. - */ -static int switch_to_gpio_core(struct bcm43xx_private *bcm) -{ - int err; - - /* Where to find the GPIO register depends on the chipset. - * If it has a ChipCommon, its register at offset 0x6c is the GPIO - * control register. Otherwise the register at offset 0x6c in the - * PCI core is the GPIO control register. - */ - err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - if (err == -ENODEV) { - err = bcm43xx_switch_core(bcm, &bcm->core_pci); - if (unlikely(err == -ENODEV)) { - printk(KERN_ERR PFX "gpio error: " - "Neither ChipCommon nor PCI core available!\n"); - } - } - - return err; -} - -/* Initialize the GPIOs - * http://bcm-specs.sipsolutions.net/GPIO - */ -static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) -{ - struct bcm43xx_coreinfo *old_core; - int err; - u32 mask, set; - - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - & 0xFFFF3FFF); - - bcm43xx_leds_switch_all(bcm, 0); - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, - bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); - - mask = 0x0000001F; - set = 0x0000000F; - if (bcm->chip_id == 0x4301) { - mask |= 0x0060; - set |= 0x0060; - } - if (0 /* FIXME: conditional unknown */) { - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, - bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) - | 0x0100); - mask |= 0x0180; - set |= 0x0180; - } - if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, - bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) - | 0x0200); - mask |= 0x0200; - set |= 0x0200; - } - if (bcm->current_core->rev >= 2) - mask |= 0x0010; /* FIXME: This is redundant. */ - - old_core = bcm->current_core; - err = switch_to_gpio_core(bcm); - if (err) - goto out; - bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, - (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set); - err = bcm43xx_switch_core(bcm, old_core); -out: - return err; -} - -/* Turn off all GPIO stuff. Call this on module unload, for example. */ -static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) -{ - struct bcm43xx_coreinfo *old_core; - int err; - - old_core = bcm->current_core; - err = switch_to_gpio_core(bcm); - if (err) - return err; - bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000); - err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - - return 0; -} - -/* http://bcm-specs.sipsolutions.net/EnableMac */ -void bcm43xx_mac_enable(struct bcm43xx_private *bcm) -{ - bcm->mac_suspended--; - assert(bcm->mac_suspended >= 0); - if (bcm->mac_suspended == 0) { - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - | BCM43xx_SBF_MAC_ENABLED); - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - bcm43xx_power_saving_ctl_bits(bcm, -1, -1); - } -} - -/* http://bcm-specs.sipsolutions.net/SuspendMAC */ -void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) -{ - int i; - u32 tmp; - - assert(bcm->mac_suspended >= 0); - if (bcm->mac_suspended == 0) { - bcm43xx_power_saving_ctl_bits(bcm, -1, 1); - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - & ~BCM43xx_SBF_MAC_ENABLED); - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - for (i = 10000; i; i--) { - tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (tmp & BCM43xx_IRQ_READY) - goto out; - udelay(1); - } - printkl(KERN_ERR PFX "MAC suspend failed\n"); - } -out: - bcm->mac_suspended++; -} - -void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, - int iw_mode) -{ - unsigned long flags; - struct net_device *net_dev = bcm->net_dev; - u32 status; - u16 value; - - spin_lock_irqsave(&bcm->ieee->lock, flags); - bcm->ieee->iw_mode = iw_mode; - spin_unlock_irqrestore(&bcm->ieee->lock, flags); - if (iw_mode == IW_MODE_MONITOR) - net_dev->type = ARPHRD_IEEE80211; - else - net_dev->type = ARPHRD_ETHER; - - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - /* Reset status to infrastructured mode */ - status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); - status &= ~BCM43xx_SBF_MODE_PROMISC; - status |= BCM43xx_SBF_MODE_NOTADHOC; - -/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ -status |= BCM43xx_SBF_MODE_PROMISC; - - switch (iw_mode) { - case IW_MODE_MONITOR: - status |= BCM43xx_SBF_MODE_MONITOR; - status |= BCM43xx_SBF_MODE_PROMISC; - break; - case IW_MODE_ADHOC: - status &= ~BCM43xx_SBF_MODE_NOTADHOC; - break; - case IW_MODE_MASTER: - status |= BCM43xx_SBF_MODE_AP; - break; - case IW_MODE_SECOND: - case IW_MODE_REPEAT: - TODO(); /* TODO */ - break; - case IW_MODE_INFRA: - /* nothing to be done here... */ - break; - default: - dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode); - } - if (net_dev->flags & IFF_PROMISC) - status |= BCM43xx_SBF_MODE_PROMISC; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - - value = 0x0002; - if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { - if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) - value = 0x0064; - else - value = 0x0032; - } - bcm43xx_write16(bcm, 0x0612, value); -} - -/* This is the opposite of bcm43xx_chip_init() */ -static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) -{ - bcm43xx_radio_turn_off(bcm); - if (!modparam_noleds) - bcm43xx_leds_exit(bcm); - bcm43xx_gpio_cleanup(bcm); - bcm43xx_release_firmware(bcm, 0); -} - -/* Initialize the chip - * http://bcm-specs.sipsolutions.net/ChipInit - */ -static int bcm43xx_chip_init(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - int err; - int i, tmp; - u32 value32; - u16 value16; - - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - BCM43xx_SBF_CORE_READY - | BCM43xx_SBF_400); - - err = bcm43xx_request_firmware(bcm); - if (err) - goto out; - bcm43xx_upload_microcode(bcm); - - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF); - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); - i = 0; - while (1) { - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (value32 == BCM43xx_IRQ_READY) - break; - i++; - if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { - printk(KERN_ERR PFX "IRQ_READY timeout\n"); - err = -ENODEV; - goto err_release_fw; - } - udelay(10); - } - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - - value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_REVISION); - - dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x " - "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", value16, - bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_PATCHLEVEL), - (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_DATE) >> 12) & 0xf, - (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_DATE) >> 8) & 0xf, - bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_DATE) & 0xff, - (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_TIME) >> 11) & 0x1f, - (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_TIME) >> 5) & 0x3f, - bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_TIME) & 0x1f); - - if ( value16 > 0x128 ) { - printk(KERN_ERR PFX - "Firmware: no support for microcode extracted " - "from version 4.x binary drivers.\n"); - err = -EOPNOTSUPP; - goto err_release_fw; - } - - err = bcm43xx_gpio_init(bcm); - if (err) - goto err_release_fw; - - err = bcm43xx_upload_initvals(bcm); - if (err) - goto err_gpio_cleanup; - bcm43xx_radio_turn_on(bcm); - bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); - printk(KERN_INFO PFX "Radio %s by hardware\n", - (bcm->radio_hw_enable == 0) ? "disabled" : "enabled"); - - bcm43xx_write16(bcm, 0x03E6, 0x0000); - err = bcm43xx_phy_init(bcm); - if (err) - goto err_radio_off; - - /* Select initial Interference Mitigation. */ - tmp = radio->interfmode; - radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; - bcm43xx_radio_set_interference_mitigation(bcm, tmp); - - bcm43xx_phy_set_antenna_diversity(bcm); - bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); - if (phy->type == BCM43xx_PHYTYPE_B) { - value16 = bcm43xx_read16(bcm, 0x005E); - value16 |= 0x0004; - bcm43xx_write16(bcm, 0x005E, value16); - } - bcm43xx_write32(bcm, 0x0100, 0x01000000); - if (bcm->current_core->rev < 5) - bcm43xx_write32(bcm, 0x010C, 0x01000000); - - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= BCM43xx_SBF_MODE_NOTADHOC; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= 0x100000; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - - if (bcm43xx_using_pio(bcm)) { - bcm43xx_write32(bcm, 0x0210, 0x00000100); - bcm43xx_write32(bcm, 0x0230, 0x00000100); - bcm43xx_write32(bcm, 0x0250, 0x00000100); - bcm43xx_write32(bcm, 0x0270, 0x00000100); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000); - } - - /* Probe Response Timeout value */ - /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); - - /* Initially set the wireless operation mode. */ - bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode); - - if (bcm->current_core->rev < 3) { - bcm43xx_write16(bcm, 0x060E, 0x0000); - bcm43xx_write16(bcm, 0x0610, 0x8000); - bcm43xx_write16(bcm, 0x0604, 0x0000); - bcm43xx_write16(bcm, 0x0606, 0x0200); - } else { - bcm43xx_write32(bcm, 0x0188, 0x80000000); - bcm43xx_write32(bcm, 0x018C, 0x02000000); - } - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_IRQ_MASK, 0x0001DC00); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00); - bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00); - - value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - value32 |= 0x00100000; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32); - - bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm)); - - assert(err == 0); - dprintk(KERN_INFO PFX "Chip initialized\n"); -out: - return err; - -err_radio_off: - bcm43xx_radio_turn_off(bcm); -err_gpio_cleanup: - bcm43xx_gpio_cleanup(bcm); -err_release_fw: - bcm43xx_release_firmware(bcm, 1); - goto out; -} - -/* Validate chip access - * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ -static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) -{ - u32 value; - u32 shm_backup; - - shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) - goto error; - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) - goto error; - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); - - value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - if ((value | 0x80000000) != 0x80000400) - goto error; - - value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (value != 0x00000000) - goto error; - - return 0; -error: - printk(KERN_ERR PFX "Failed to validate the chipaccess\n"); - return -ENODEV; -} - -static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) -{ - /* Initialize a "phyinfo" structure. The structure is already - * zeroed out. - * This is called on insmod time to initialize members. - */ - phy->savedpctlreg = 0xFFFF; - spin_lock_init(&phy->lock); -} - -static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) -{ - /* Initialize a "radioinfo" structure. The structure is already - * zeroed out. - * This is called on insmod time to initialize members. - */ - radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; - radio->channel = 0xFF; - radio->initial_channel = 0xFF; -} - -static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) -{ - int err, i; - int current_core; - u32 core_vendor, core_id, core_rev; - u32 sb_id_hi, chip_id_32 = 0; - u16 pci_device, chip_id_16; - u8 core_count; - - memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); - memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); - memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) - * BCM43xx_MAX_80211_CORES); - memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) - * BCM43xx_MAX_80211_CORES); - bcm->nr_80211_available = 0; - bcm->current_core = NULL; - bcm->active_80211_core = NULL; - - /* map core 0 */ - err = _switch_core(bcm, 0); - if (err) - goto out; - - /* fetch sb_id_hi from core information registers */ - sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); - - core_id = (sb_id_hi & 0x8FF0) >> 4; - core_rev = (sb_id_hi & 0x7000) >> 8; - core_rev |= (sb_id_hi & 0xF); - core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; - - /* if present, chipcommon is always core 0; read the chipid from it */ - if (core_id == BCM43xx_COREID_CHIPCOMMON) { - chip_id_32 = bcm43xx_read32(bcm, 0); - chip_id_16 = chip_id_32 & 0xFFFF; - bcm->core_chipcommon.available = 1; - bcm->core_chipcommon.id = core_id; - bcm->core_chipcommon.rev = core_rev; - bcm->core_chipcommon.index = 0; - /* While we are at it, also read the capabilities. */ - bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES); - } else { - /* without a chipCommon, use a hard coded table. */ - pci_device = bcm->pci_dev->device; - if (pci_device == 0x4301) - chip_id_16 = 0x4301; - else if ((pci_device >= 0x4305) && (pci_device <= 0x4307)) - chip_id_16 = 0x4307; - else if ((pci_device >= 0x4402) && (pci_device <= 0x4403)) - chip_id_16 = 0x4402; - else if ((pci_device >= 0x4610) && (pci_device <= 0x4615)) - chip_id_16 = 0x4610; - else if ((pci_device >= 0x4710) && (pci_device <= 0x4715)) - chip_id_16 = 0x4710; - else { - printk(KERN_ERR PFX "Could not determine Chip ID\n"); - return -ENODEV; - } - } - - /* ChipCommon with Core Rev >=4 encodes number of cores, - * otherwise consult hardcoded table */ - if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) { - core_count = (chip_id_32 & 0x0F000000) >> 24; - } else { - switch (chip_id_16) { - case 0x4610: - case 0x4704: - case 0x4710: - core_count = 9; - break; - case 0x4310: - core_count = 8; - break; - case 0x5365: - core_count = 7; - break; - case 0x4306: - core_count = 6; - break; - case 0x4301: - case 0x4307: - core_count = 5; - break; - case 0x4402: - core_count = 3; - break; - default: - /* SOL if we get here */ - assert(0); - core_count = 1; - } - } - - bcm->chip_id = chip_id_16; - bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16; - bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20; - - dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", - bcm->chip_id, bcm->chip_rev); - dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); - if (bcm->core_chipcommon.available) { - dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x\n", - core_id, core_rev, core_vendor); - current_core = 1; - } else - current_core = 0; - for ( ; current_core < core_count; current_core++) { - struct bcm43xx_coreinfo *core; - struct bcm43xx_coreinfo_80211 *ext_80211; - - err = _switch_core(bcm, current_core); - if (err) - goto out; - /* Gather information */ - /* fetch sb_id_hi from core information registers */ - sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); - - /* extract core_id, core_rev, core_vendor */ - core_id = (sb_id_hi & 0x8FF0) >> 4; - core_rev = ((sb_id_hi & 0xF) | ((sb_id_hi & 0x7000) >> 8)); - core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; - - dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x\n", - current_core, core_id, core_rev, core_vendor); - - core = NULL; - switch (core_id) { - case BCM43xx_COREID_PCI: - case BCM43xx_COREID_PCIE: - core = &bcm->core_pci; - if (core->available) { - printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); - continue; - } - break; - case BCM43xx_COREID_80211: - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - core = &(bcm->core_80211[i]); - ext_80211 = &(bcm->core_80211_ext[i]); - if (!core->available) - break; - core = NULL; - } - if (!core) { - printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n", - BCM43xx_MAX_80211_CORES); - continue; - } - if (i != 0) { - /* More than one 80211 core is only supported - * by special chips. - * There are chips with two 80211 cores, but with - * dangling pins on the second core. Be careful - * and ignore these cores here. - */ - if (1 /*bcm->pci_dev->device != 0x4324*/ ) { - /* TODO: A PHY */ - dprintk(KERN_INFO PFX "Ignoring additional 802.11a core.\n"); - continue; - } - } - switch (core_rev) { - case 2: - case 4: - case 5: - case 6: - case 7: - case 9: - case 10: - break; - default: - printk(KERN_WARNING PFX - "Unsupported 80211 core revision %u\n", - core_rev); - } - bcm->nr_80211_available++; - core->priv = ext_80211; - bcm43xx_init_struct_phyinfo(&ext_80211->phy); - bcm43xx_init_struct_radioinfo(&ext_80211->radio); - break; - case BCM43xx_COREID_CHIPCOMMON: - printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); - break; - } - if (core) { - core->available = 1; - core->id = core_id; - core->rev = core_rev; - core->index = current_core; - } - } - - if (!bcm->core_80211[0].available) { - printk(KERN_ERR PFX "Error: No 80211 core found!\n"); - err = -ENODEV; - goto out; - } - - err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]); - - assert(err == 0); -out: - return err; -} - -static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm) -{ - const u8 *mac = (const u8*)(bcm->net_dev->dev_addr); - u8 *bssid = bcm->ieee->bssid; - - switch (bcm->ieee->iw_mode) { - case IW_MODE_ADHOC: - random_ether_addr(bssid); - break; - case IW_MODE_MASTER: - case IW_MODE_INFRA: - case IW_MODE_REPEAT: - case IW_MODE_SECOND: - case IW_MODE_MONITOR: - memcpy(bssid, mac, ETH_ALEN); - break; - default: - assert(0); - } -} - -static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, - u16 rate, - int is_ofdm) -{ - u16 offset; - - if (is_ofdm) { - offset = 0x480; - offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; - } - else { - offset = 0x4C0; - offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2; - } - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20, - bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset)); -} - -static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) -{ - switch (bcm43xx_current_phy(bcm)->type) { - case BCM43xx_PHYTYPE_A: - case BCM43xx_PHYTYPE_G: - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1); - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1); - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1); - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1); - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1); - bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1); - case BCM43xx_PHYTYPE_B: - bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0); - bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0); - bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0); - bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0); - break; - default: - assert(0); - } -} - -static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) -{ - bcm43xx_chip_cleanup(bcm); - bcm43xx_pio_free(bcm); - bcm43xx_dma_free(bcm); - - bcm->current_core->initialized = 0; -} - -/* http://bcm-specs.sipsolutions.net/80211Init */ -static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, - int active_wlcore) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u32 ucodeflags; - int err; - u32 sbimconfiglow; - u8 limit; - - if (bcm->core_pci.rev <= 5 && bcm->core_pci.id != BCM43xx_COREID_PCIE) { - sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); - sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; - sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; - if (bcm->bustype == BCM43xx_BUSTYPE_PCI) - sbimconfiglow |= 0x32; - else - sbimconfiglow |= 0x53; - bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); - } - - bcm43xx_phy_calibrate(bcm); - err = bcm43xx_chip_init(bcm); - if (err) - goto out; - - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev); - ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET); - - if (0 /*FIXME: which condition has to be used here? */) - ucodeflags |= 0x00000010; - - /* HW decryption needs to be set now */ - ucodeflags |= 0x40000000; - - if (phy->type == BCM43xx_PHYTYPE_G) { - ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; - if (phy->rev == 1) - ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; - if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) - ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; - } else if (phy->type == BCM43xx_PHYTYPE_B) { - ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; - if (phy->rev >= 2 && radio->version == 0x2050) - ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; - } - - if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET)) { - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, ucodeflags); - } - - /* Short/Long Retry Limit. - * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. - */ - limit = limit_value(modparam_short_retry, 0, 0xF); - bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit); - limit = limit_value(modparam_long_retry, 0, 0xF); - bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit); - - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2); - - bcm43xx_rate_memory_init(bcm); - - /* Minimum Contention Window */ - if (phy->type == BCM43xx_PHYTYPE_B) - bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); - else - bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); - /* Maximum Contention Window */ - bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); - - bcm43xx_gen_bssid(bcm); - bcm43xx_write_mac_bssid_templates(bcm); - - if (bcm->current_core->rev >= 5) - bcm43xx_write16(bcm, 0x043C, 0x000C); - - if (active_wlcore) { - if (bcm43xx_using_pio(bcm)) { - err = bcm43xx_pio_init(bcm); - } else { - err = bcm43xx_dma_init(bcm); - if (err == -ENOSYS) - err = bcm43xx_pio_init(bcm); - } - if (err) - goto err_chip_cleanup; - } - bcm43xx_write16(bcm, 0x0612, 0x0050); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); - - if (active_wlcore) { - if (radio->initial_channel != 0xFF) - bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0); - } - - /* Don't enable MAC/IRQ here, as it will race with the IRQ handler. - * We enable it later. - */ - bcm->current_core->initialized = 1; -out: - return err; - -err_chip_cleanup: - bcm43xx_chip_cleanup(bcm); - goto out; -} - -static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) -{ - int err; - u16 pci_status; - - err = bcm43xx_pctl_set_crystal(bcm, 1); - if (err) - goto out; - err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); - if (err) - goto out; - err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); - -out: - return err; -} - -static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) -{ - bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); - bcm43xx_pctl_set_crystal(bcm, 0); -} - -static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, - u32 address, - u32 data) -{ - bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); - bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); -} - -static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) -{ - int err = 0; - - bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - - if (bcm->core_chipcommon.available) { - err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - if (err) - goto out; - - bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); - - /* this function is always called when a PCI core is mapped */ - err = bcm43xx_switch_core(bcm, &bcm->core_pci); - if (err) - goto out; - } else - bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); - - bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - -out: - return err; -} - -static u32 bcm43xx_pcie_reg_read(struct bcm43xx_private *bcm, u32 address) -{ - bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address); - return bcm43xx_read32(bcm, BCM43xx_PCIECORE_REG_DATA); -} - -static void bcm43xx_pcie_reg_write(struct bcm43xx_private *bcm, u32 address, - u32 data) -{ - bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address); - bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_DATA, data); -} - -static void bcm43xx_pcie_mdio_write(struct bcm43xx_private *bcm, u8 dev, u8 reg, - u16 data) -{ - int i; - - bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0x0082); - bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_DATA, BCM43xx_PCIE_MDIO_ST | - BCM43xx_PCIE_MDIO_WT | (dev << BCM43xx_PCIE_MDIO_DEV) | - (reg << BCM43xx_PCIE_MDIO_REG) | BCM43xx_PCIE_MDIO_TA | - data); - udelay(10); - - for (i = 0; i < 10; i++) { - if (bcm43xx_read32(bcm, BCM43xx_PCIECORE_MDIO_CTL) & - BCM43xx_PCIE_MDIO_TC) - break; - msleep(1); - } - bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0); -} - -/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable. - * To enable core 0, pass a core_mask of 1<<0 - */ -static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, - u32 core_mask) -{ - u32 backplane_flag_nr; - u32 value; - struct bcm43xx_coreinfo *old_core; - int err = 0; - - value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG); - backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK; - - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, &bcm->core_pci); - if (err) - goto out; - - if (bcm->current_core->rev < 6 && - bcm->current_core->id == BCM43xx_COREID_PCI) { - value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); - value |= (1 << backplane_flag_nr); - bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); - } else { - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value); - if (err) { - printk(KERN_ERR PFX "Error: ICR setup failure!\n"); - goto out_switch_back; - } - value |= core_mask << 8; - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value); - if (err) { - printk(KERN_ERR PFX "Error: ICR setup failure!\n"); - goto out_switch_back; - } - } - - if (bcm->current_core->id == BCM43xx_COREID_PCI) { - value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); - value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; - bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); - - if (bcm->current_core->rev < 5) { - value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); - value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) - & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; - value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) - & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; - bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); - err = bcm43xx_pcicore_commit_settings(bcm); - assert(err == 0); - } else if (bcm->current_core->rev >= 11) { - value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); - value |= BCM43xx_SBTOPCI2_MEMREAD_MULTI; - bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); - } - } else { - if (bcm->current_core->rev == 0 || bcm->current_core->rev == 1) { - value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_TLP_WORKAROUND); - value |= 0x8; - bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_TLP_WORKAROUND, - value); - } - if (bcm->current_core->rev == 0) { - bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX, - BCM43xx_SERDES_RXTIMER, 0x8128); - bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX, - BCM43xx_SERDES_CDR, 0x0100); - bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX, - BCM43xx_SERDES_CDR_BW, 0x1466); - } else if (bcm->current_core->rev == 1) { - value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_DLLP_LINKCTL); - value |= 0x40; - bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_DLLP_LINKCTL, - value); - } - } -out_switch_back: - err = bcm43xx_switch_core(bcm, old_core); -out: - return err; -} - -static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) - return; - - bcm43xx_mac_suspend(bcm); - bcm43xx_phy_lo_g_measure(bcm); - bcm43xx_mac_enable(bcm); -} - -static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm) -{ - bcm43xx_phy_lo_mark_all_unused(bcm); - if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { - bcm43xx_mac_suspend(bcm); - bcm43xx_calc_nrssi_slope(bcm); - bcm43xx_mac_enable(bcm); - } -} - -static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) -{ - /* Update device statistics. */ - bcm43xx_calculate_link_quality(bcm); -} - -static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) -{ - bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? - //TODO for APHY (temperature?) -} - -static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int radio_hw_enable; - - /* check if radio hardware enabled status changed */ - radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); - if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) { - bcm->radio_hw_enable = radio_hw_enable; - printk(KERN_INFO PFX "Radio hardware status changed to %s\n", - (radio_hw_enable == 0) ? "disabled" : "enabled"); - bcm43xx_leds_update(bcm, 0); - } - if (phy->type == BCM43xx_PHYTYPE_G) { - //TODO: update_aci_moving_average - if (radio->aci_enable && radio->aci_wlan_automatic) { - bcm43xx_mac_suspend(bcm); - if (!radio->aci_enable && 1 /*TODO: not scanning? */) { - if (0 /*TODO: bunch of conditions*/) { - bcm43xx_radio_set_interference_mitigation(bcm, - BCM43xx_RADIO_INTERFMODE_MANUALWLAN); - } - } else if (1/*TODO*/) { - /* - if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) { - bcm43xx_radio_set_interference_mitigation(bcm, - BCM43xx_RADIO_INTERFMODE_NONE); - } - */ - } - bcm43xx_mac_enable(bcm); - } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN && - phy->rev == 1) { - //TODO: implement rev1 workaround - } - } -} - -static void do_periodic_work(struct bcm43xx_private *bcm) -{ - if (bcm->periodic_state % 120 == 0) - bcm43xx_periodic_every120sec(bcm); - if (bcm->periodic_state % 60 == 0) - bcm43xx_periodic_every60sec(bcm); - if (bcm->periodic_state % 30 == 0) - bcm43xx_periodic_every30sec(bcm); - if (bcm->periodic_state % 15 == 0) - bcm43xx_periodic_every15sec(bcm); - bcm43xx_periodic_every1sec(bcm); - - schedule_delayed_work(&bcm->periodic_work, HZ); -} - -static void bcm43xx_periodic_work_handler(struct work_struct *work) -{ - struct bcm43xx_private *bcm = - container_of(work, struct bcm43xx_private, periodic_work.work); - struct net_device *net_dev = bcm->net_dev; - unsigned long flags; - u32 savedirqs = 0; - unsigned long orig_trans_start = 0; - - mutex_lock(&bcm->mutex); - /* keep from doing and rearming periodic work if shutting down */ - if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT) - goto unlock_mutex; - if (unlikely(bcm->periodic_state % 60 == 0)) { - /* Periodic work will take a long time, so we want it to - * be preemtible. - */ - - netif_tx_lock_bh(net_dev); - /* We must fake a started transmission here, as we are going to - * disable TX. If we wouldn't fake a TX, it would be possible to - * trigger the netdev watchdog, if the last real TX is already - * some time on the past (slightly less than 5secs) - */ - orig_trans_start = net_dev->trans_start; - net_dev->trans_start = jiffies; - netif_stop_queue(net_dev); - netif_tx_unlock_bh(net_dev); - - spin_lock_irqsave(&bcm->irq_lock, flags); - bcm43xx_mac_suspend(bcm); - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_freeze_txqueues(bcm); - savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - bcm43xx_synchronize_irq(bcm); - } else { - /* Periodic work should take short time, so we want low - * locking overhead. - */ - spin_lock_irqsave(&bcm->irq_lock, flags); - } - - do_periodic_work(bcm); - - if (unlikely(bcm->periodic_state % 60 == 0)) { - spin_lock_irqsave(&bcm->irq_lock, flags); - tasklet_enable(&bcm->isr_tasklet); - bcm43xx_interrupt_enable(bcm, savedirqs); - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_thaw_txqueues(bcm); - bcm43xx_mac_enable(bcm); - netif_wake_queue(bcm->net_dev); - net_dev->trans_start = orig_trans_start; - } - mmiowb(); - bcm->periodic_state++; - spin_unlock_irqrestore(&bcm->irq_lock, flags); -unlock_mutex: - mutex_unlock(&bcm->mutex); -} - -void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) -{ - struct delayed_work *work = &bcm->periodic_work; - - assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler); - schedule_delayed_work(work, 0); -} - -static void bcm43xx_security_init(struct bcm43xx_private *bcm) -{ - bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - 0x0056) * 2; - bcm43xx_clear_keys(bcm); -} - -static int bcm43xx_rng_read(struct hwrng *rng, u32 *data) -{ - struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; - unsigned long flags; - - spin_lock_irqsave(&(bcm)->irq_lock, flags); - *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); - spin_unlock_irqrestore(&(bcm)->irq_lock, flags); - - return (sizeof(u16)); -} - -static void bcm43xx_rng_exit(struct bcm43xx_private *bcm) -{ - hwrng_unregister(&bcm->rng); -} - -static int bcm43xx_rng_init(struct bcm43xx_private *bcm) -{ - int err; - - snprintf(bcm->rng_name, ARRAY_SIZE(bcm->rng_name), - "%s_%s", KBUILD_MODNAME, bcm->net_dev->name); - bcm->rng.name = bcm->rng_name; - bcm->rng.data_read = bcm43xx_rng_read; - bcm->rng.priv = (unsigned long)bcm; - err = hwrng_register(&bcm->rng); - if (err) - printk(KERN_ERR PFX "RNG init failed (%d)\n", err); - - return err; -} - -void bcm43xx_cancel_work(struct bcm43xx_private *bcm) -{ - /* The system must be unlocked when this routine is entered. - * If not, the next 2 steps may deadlock */ - cancel_work_sync(&bcm->restart_work); - cancel_delayed_work_sync(&bcm->periodic_work); -} - -static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) -{ - int ret = 0; - int i, err; - struct bcm43xx_coreinfo *core; - - bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); - for (i = 0; i < bcm->nr_80211_available; i++) { - core = &(bcm->core_80211[i]); - assert(core->available); - if (!core->initialized) - continue; - err = bcm43xx_switch_core(bcm, core); - if (err) { - dprintk(KERN_ERR PFX "shutdown_all_wireless_cores " - "switch_core failed (%d)\n", err); - ret = err; - continue; - } - bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - bcm43xx_wireless_core_cleanup(bcm); - if (core == bcm->active_80211_core) - bcm->active_80211_core = NULL; - } - free_irq(bcm->irq, bcm); - bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); - - return ret; -} - -/* This is the opposite of bcm43xx_init_board() */ -static void bcm43xx_free_board(struct bcm43xx_private *bcm) -{ - bcm43xx_rng_exit(bcm); - bcm43xx_sysfs_unregister(bcm); - - mutex_lock(&(bcm)->mutex); - bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); - mutex_unlock(&(bcm)->mutex); - - bcm43xx_cancel_work(bcm); - - mutex_lock(&(bcm)->mutex); - bcm43xx_shutdown_all_wireless_cores(bcm); - bcm43xx_pctl_set_crystal(bcm, 0); - mutex_unlock(&(bcm)->mutex); -} - -static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy) -{ - phy->antenna_diversity = 0xFFFF; - memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); - memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - - /* Flags */ - phy->calibrated = 0; - phy->is_locked = 0; - - if (phy->_lo_pairs) { - memset(phy->_lo_pairs, 0, - sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT); - } - memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain)); -} - -static void prepare_radiodata_for_init(struct bcm43xx_private *bcm, - struct bcm43xx_radioinfo *radio) -{ - int i; - - /* Set default attenuation values. */ - radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); - radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); - radio->txctl1 = bcm43xx_default_txctl1(bcm); - radio->txctl2 = 0xFFFF; - radio->txpwr_offset = 0; - - /* NRSSI */ - radio->nrssislope = 0; - for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++) - radio->nrssi[i] = -1000; - for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++) - radio->nrssi_lt[i] = i; - - radio->lofcal = 0xFFFF; - radio->initval = 0xFFFF; - - radio->aci_enable = 0; - radio->aci_wlan_automatic = 0; - radio->aci_hw_rssi = 0; -} - -static void prepare_priv_for_init(struct bcm43xx_private *bcm) -{ - int i; - struct bcm43xx_coreinfo *core; - struct bcm43xx_coreinfo_80211 *wlext; - - assert(!bcm->active_80211_core); - - bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); - - /* Flags */ - bcm->was_initialized = 0; - bcm->reg124_set_0x4 = 0; - - /* Stats */ - memset(&bcm->stats, 0, sizeof(bcm->stats)); - - /* Wireless core data */ - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - core = &(bcm->core_80211[i]); - wlext = core->priv; - - if (!core->available) - continue; - assert(wlext == &(bcm->core_80211_ext[i])); - - prepare_phydata_for_init(&wlext->phy); - prepare_radiodata_for_init(bcm, &wlext->radio); - } - - /* IRQ related flags */ - bcm->irq_reason = 0; - memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason)); - bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; - - bcm->mac_suspended = 1; - - /* Noise calculation context */ - memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc)); - - /* Periodic work context */ - bcm->periodic_state = 0; -} - -static int wireless_core_up(struct bcm43xx_private *bcm, - int active_wlcore) -{ - int err; - - if (!bcm43xx_core_enabled(bcm)) - bcm43xx_wireless_core_reset(bcm, 1); - if (!active_wlcore) - bcm43xx_wireless_core_mark_inactive(bcm); - err = bcm43xx_wireless_core_init(bcm, active_wlcore); - if (err) - goto out; - if (!active_wlcore) - bcm43xx_radio_turn_off(bcm); -out: - return err; -} - -/* Select and enable the "to be used" wireless core. - * Locking: bcm->mutex must be aquired before calling this. - * bcm->irq_lock must not be aquired. - */ -int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, - int phytype) -{ - int i, err; - struct bcm43xx_coreinfo *active_core = NULL; - struct bcm43xx_coreinfo_80211 *active_wlext = NULL; - struct bcm43xx_coreinfo *core; - struct bcm43xx_coreinfo_80211 *wlext; - int adjust_active_sbtmstatelow = 0; - - might_sleep(); - - if (phytype < 0) { - /* If no phytype is requested, select the first core. */ - assert(bcm->core_80211[0].available); - wlext = bcm->core_80211[0].priv; - phytype = wlext->phy.type; - } - /* Find the requested core. */ - for (i = 0; i < bcm->nr_80211_available; i++) { - core = &(bcm->core_80211[i]); - wlext = core->priv; - if (wlext->phy.type == phytype) { - active_core = core; - active_wlext = wlext; - break; - } - } - if (!active_core) - return -ESRCH; /* No such PHYTYPE on this board. */ - - if (bcm->active_80211_core) { - /* We already selected a wl core in the past. - * So first clean up everything. - */ - dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n"); - ieee80211softmac_stop(bcm->net_dev); - bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); - err = bcm43xx_disable_interrupts_sync(bcm); - assert(!err); - tasklet_enable(&bcm->isr_tasklet); - err = bcm43xx_shutdown_all_wireless_cores(bcm); - if (err) - goto error; - /* Ok, everything down, continue to re-initialize. */ - bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); - } - - /* Reset all data structures. */ - prepare_priv_for_init(bcm); - - err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); - if (err) - goto error; - - /* Mark all unused cores "inactive". */ - for (i = 0; i < bcm->nr_80211_available; i++) { - core = &(bcm->core_80211[i]); - wlext = core->priv; - - if (core == active_core) - continue; - err = bcm43xx_switch_core(bcm, core); - if (err) { - dprintk(KERN_ERR PFX "Could not switch to inactive " - "802.11 core (%d)\n", err); - goto error; - } - err = wireless_core_up(bcm, 0); - if (err) { - dprintk(KERN_ERR PFX "core_up for inactive 802.11 core " - "failed (%d)\n", err); - goto error; - } - adjust_active_sbtmstatelow = 1; - } - - /* Now initialize the active 802.11 core. */ - err = bcm43xx_switch_core(bcm, active_core); - if (err) { - dprintk(KERN_ERR PFX "Could not switch to active " - "802.11 core (%d)\n", err); - goto error; - } - if (adjust_active_sbtmstatelow && - active_wlext->phy.type == BCM43xx_PHYTYPE_G) { - u32 sbtmstatelow; - - sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - } - err = wireless_core_up(bcm, 1); - if (err) { - dprintk(KERN_ERR PFX "core_up for active 802.11 core " - "failed (%d)\n", err); - goto error; - } - err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); - if (err) - goto error; - bcm->active_80211_core = active_core; - - bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); - bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); - bcm43xx_security_init(bcm); - drain_txstatus_queue(bcm); - ieee80211softmac_start(bcm->net_dev); - - /* Let's go! Be careful after enabling the IRQs. - * Don't switch cores, for example. - */ - bcm43xx_mac_enable(bcm); - bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); - err = bcm43xx_initialize_irq(bcm); - if (err) - goto error; - bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - - dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n", - active_wlext->phy.type); - - return 0; - -error: - bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); - bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); - return err; -} - -static int bcm43xx_init_board(struct bcm43xx_private *bcm) -{ - int err; - - mutex_lock(&(bcm)->mutex); - - tasklet_enable(&bcm->isr_tasklet); - err = bcm43xx_pctl_set_crystal(bcm, 1); - if (err) - goto err_tasklet; - err = bcm43xx_pctl_init(bcm); - if (err) - goto err_crystal_off; - err = bcm43xx_select_wireless_core(bcm, -1); - if (err) - goto err_crystal_off; - err = bcm43xx_sysfs_register(bcm); - if (err) - goto err_wlshutdown; - err = bcm43xx_rng_init(bcm); - if (err) - goto err_sysfs_unreg; - bcm43xx_periodic_tasks_setup(bcm); - - /*FIXME: This should be handled by softmac instead. */ - schedule_delayed_work(&bcm->softmac->associnfo.work, 0); - -out: - mutex_unlock(&(bcm)->mutex); - - return err; - -err_sysfs_unreg: - bcm43xx_sysfs_unregister(bcm); -err_wlshutdown: - bcm43xx_shutdown_all_wireless_cores(bcm); -err_crystal_off: - bcm43xx_pctl_set_crystal(bcm, 0); -err_tasklet: - tasklet_disable(&bcm->isr_tasklet); - goto out; -} - -static void bcm43xx_detach_board(struct bcm43xx_private *bcm) -{ - struct pci_dev *pci_dev = bcm->pci_dev; - int i; - - bcm43xx_chipset_detach(bcm); - /* Do _not_ access the chip, after it is detached. */ - pci_iounmap(pci_dev, bcm->mmio_addr); - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); - - /* Free allocated structures/fields */ - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - kfree(bcm->core_80211_ext[i].phy._lo_pairs); - if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) - kfree(bcm->core_80211_ext[i].phy.tssi2dbm); - } -} - -static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 value; - u8 phy_analog; - u8 phy_type; - u8 phy_rev; - int phy_rev_ok = 1; - void *p; - - value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); - - phy_analog = (value & 0xF000) >> 12; - phy_type = (value & 0x0F00) >> 8; - phy_rev = (value & 0x000F); - - dprintk(KERN_INFO PFX "Detected PHY: Analog: %x, Type %x, Revision %x\n", - phy_analog, phy_type, phy_rev); - - switch (phy_type) { - case BCM43xx_PHYTYPE_A: - if (phy_rev >= 4) - phy_rev_ok = 0; - /*FIXME: We need to switch the ieee->modulation, etc.. flags, - * if we switch 80211 cores after init is done. - * As we do not implement on the fly switching between - * wireless cores, I will leave this as a future task. - */ - bcm->ieee->modulation = IEEE80211_OFDM_MODULATION; - bcm->ieee->mode = IEEE_A; - bcm->ieee->freq_band = IEEE80211_52GHZ_BAND | - IEEE80211_24GHZ_BAND; - break; - case BCM43xx_PHYTYPE_B: - if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7) - phy_rev_ok = 0; - bcm->ieee->modulation = IEEE80211_CCK_MODULATION; - bcm->ieee->mode = IEEE_B; - bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; - break; - case BCM43xx_PHYTYPE_G: - if (phy_rev > 8) - phy_rev_ok = 0; - bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - bcm->ieee->mode = IEEE_G; - bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; - break; - default: - printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n", - phy_type); - return -ENODEV; - }; - bcm->ieee->perfect_rssi = RX_RSSI_MAX; - bcm->ieee->worst_rssi = 0; - if (!phy_rev_ok) { - printk(KERN_WARNING PFX "Invalid PHY Revision %x\n", - phy_rev); - } - - phy->analog = phy_analog; - phy->type = phy_type; - phy->rev = phy_rev; - if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { - p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, - GFP_KERNEL); - if (!p) - return -ENOMEM; - phy->_lo_pairs = p; - } - - return 0; -} - -static int bcm43xx_attach_board(struct bcm43xx_private *bcm) -{ - struct pci_dev *pci_dev = bcm->pci_dev; - struct net_device *net_dev = bcm->net_dev; - int err; - int i; - u32 coremask; - - err = pci_enable_device(pci_dev); - if (err) { - printk(KERN_ERR PFX "pci_enable_device() failed\n"); - goto out; - } - err = pci_request_regions(pci_dev, KBUILD_MODNAME); - if (err) { - printk(KERN_ERR PFX "pci_request_regions() failed\n"); - goto err_pci_disable; - } - /* enable PCI bus-mastering */ - pci_set_master(pci_dev); - bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL); - if (!bcm->mmio_addr) { - printk(KERN_ERR PFX "pci_iomap() failed\n"); - err = -EIO; - goto err_pci_release; - } - net_dev->base_addr = (unsigned long)bcm->mmio_addr; - - err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, - &bcm->board_vendor); - if (err) - goto err_iounmap; - err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, - &bcm->board_type); - if (err) - goto err_iounmap; - - bcm->board_revision = bcm->pci_dev->revision; - - err = bcm43xx_chipset_attach(bcm); - if (err) - goto err_iounmap; - err = bcm43xx_pctl_init(bcm); - if (err) - goto err_chipset_detach; - err = bcm43xx_probe_cores(bcm); - if (err) - goto err_chipset_detach; - - /* Attach all IO cores to the backplane. */ - coremask = 0; - for (i = 0; i < bcm->nr_80211_available; i++) - coremask |= (1 << bcm->core_80211[i].index); - //FIXME: Also attach some non80211 cores? - err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); - if (err) { - printk(KERN_ERR PFX "Backplane->PCI connection failed!\n"); - goto err_chipset_detach; - } - - err = bcm43xx_sprom_extract(bcm); - if (err) - goto err_chipset_detach; - err = bcm43xx_leds_init(bcm); - if (err) - goto err_chipset_detach; - - for (i = 0; i < bcm->nr_80211_available; i++) { - err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); - assert(err != -ENODEV); - if (err) - goto err_80211_unwind; - - /* Enable the selected wireless core. - * Connect PHY only on the first core. - */ - bcm43xx_wireless_core_reset(bcm, (i == 0)); - - err = bcm43xx_read_phyinfo(bcm); - if (err && (i == 0)) - goto err_80211_unwind; - - err = bcm43xx_read_radioinfo(bcm); - if (err && (i == 0)) - goto err_80211_unwind; - - err = bcm43xx_validate_chip(bcm); - if (err && (i == 0)) - goto err_80211_unwind; - - bcm43xx_radio_turn_off(bcm); - err = bcm43xx_phy_init_tssi2dbm_table(bcm); - if (err) - goto err_80211_unwind; - bcm43xx_wireless_core_disable(bcm); - } - err = bcm43xx_geo_init(bcm); - if (err) - goto err_80211_unwind; - bcm43xx_pctl_set_crystal(bcm, 0); - - /* Set the MAC address in the networking subsystem */ - if (is_valid_ether_addr(bcm->sprom.et1macaddr)) - memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); - else - memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); - - snprintf(bcm->nick, IW_ESSID_MAX_SIZE, - "Broadcom %04X", bcm->chip_id); - - assert(err == 0); -out: - return err; - -err_80211_unwind: - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - kfree(bcm->core_80211_ext[i].phy._lo_pairs); - if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) - kfree(bcm->core_80211_ext[i].phy.tssi2dbm); - } -err_chipset_detach: - bcm43xx_chipset_detach(bcm); -err_iounmap: - pci_iounmap(pci_dev, bcm->mmio_addr); -err_pci_release: - pci_release_regions(pci_dev); -err_pci_disable: - pci_disable_device(pci_dev); - printk(KERN_ERR PFX "Unable to attach board\n"); - goto out; -} - -/* Do the Hardware IO operations to send the txb */ -static inline int bcm43xx_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - int err = -ENODEV; - - if (bcm43xx_using_pio(bcm)) - err = bcm43xx_pio_tx(bcm, txb); - else - err = bcm43xx_dma_tx(bcm, txb); - bcm->net_dev->trans_start = jiffies; - - return err; -} - -static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, - u8 channel) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct bcm43xx_radioinfo *radio; - unsigned long flags; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - bcm43xx_mac_suspend(bcm); - bcm43xx_radio_selectchannel(bcm, channel, 0); - bcm43xx_mac_enable(bcm); - } else { - radio = bcm43xx_current_radio(bcm); - radio->initial_channel = channel; - } - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); -} - -/* set_security() callback in struct ieee80211_device */ -static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, - struct ieee80211_security *sec) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct ieee80211_security *secinfo = &bcm->ieee->sec; - unsigned long flags; - int keyidx; - - dprintk(KERN_INFO PFX "set security called"); - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - - for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) - if (sec->flags & (1<<keyidx)) { - secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx]; - secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; - memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN); - } - - if (sec->flags & SEC_ACTIVE_KEY) { - secinfo->active_key = sec->active_key; - dprintk(", .active_key = %d", sec->active_key); - } - if (sec->flags & SEC_UNICAST_GROUP) { - secinfo->unicast_uses_group = sec->unicast_uses_group; - dprintk(", .unicast_uses_group = %d", sec->unicast_uses_group); - } - if (sec->flags & SEC_LEVEL) { - secinfo->level = sec->level; - dprintk(", .level = %d", sec->level); - } - if (sec->flags & SEC_ENABLED) { - secinfo->enabled = sec->enabled; - dprintk(", .enabled = %d", sec->enabled); - } - if (sec->flags & SEC_ENCRYPT) { - secinfo->encrypt = sec->encrypt; - dprintk(", .encrypt = %d", sec->encrypt); - } - if (sec->flags & SEC_AUTH_MODE) { - secinfo->auth_mode = sec->auth_mode; - dprintk(", .auth_mode = %d", sec->auth_mode); - } - dprintk("\n"); - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED && - !bcm->ieee->host_encrypt) { - if (secinfo->enabled) { - /* upload WEP keys to hardware */ - char null_address[6] = { 0 }; - u8 algorithm = 0; - for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) { - if (!(sec->flags & (1<<keyidx))) - continue; - switch (sec->encode_alg[keyidx]) { - case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break; - case SEC_ALG_WEP: - algorithm = BCM43xx_SEC_ALGO_WEP; - if (secinfo->key_sizes[keyidx] == 13) - algorithm = BCM43xx_SEC_ALGO_WEP104; - break; - case SEC_ALG_TKIP: - FIXME(); - algorithm = BCM43xx_SEC_ALGO_TKIP; - break; - case SEC_ALG_CCMP: - FIXME(); - algorithm = BCM43xx_SEC_ALGO_AES; - break; - default: - assert(0); - break; - } - bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]); - bcm->key[keyidx].enabled = 1; - bcm->key[keyidx].algorithm = algorithm; - } - } else - bcm43xx_clear_keys(bcm); - } - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); -} - -/* hard_start_xmit() callback in struct ieee80211_device */ -static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, - struct net_device *net_dev, - int pri) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err = -ENODEV; - unsigned long flags; - - spin_lock_irqsave(&bcm->irq_lock, flags); - if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) - err = bcm43xx_tx(bcm, txb); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - - if (unlikely(err)) - return NETDEV_TX_BUSY; - return NETDEV_TX_OK; -} - -static void bcm43xx_net_tx_timeout(struct net_device *net_dev) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - - spin_lock_irqsave(&bcm->irq_lock, flags); - bcm43xx_controller_restart(bcm, "TX timeout"); - spin_unlock_irqrestore(&bcm->irq_lock, flags); -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void bcm43xx_net_poll_controller(struct net_device *net_dev) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - - local_irq_save(flags); - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) - bcm43xx_interrupt_handler(bcm->irq, bcm); - local_irq_restore(flags); -} -#endif /* CONFIG_NET_POLL_CONTROLLER */ - -static int bcm43xx_net_open(struct net_device *net_dev) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - - return bcm43xx_init_board(bcm); -} - -static int bcm43xx_net_stop(struct net_device *net_dev) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err; - - ieee80211softmac_stop(net_dev); - err = bcm43xx_disable_interrupts_sync(bcm); - assert(!err); - bcm43xx_free_board(bcm); - bcm43xx_cancel_work(bcm); - - return 0; -} - -static int bcm43xx_init_private(struct bcm43xx_private *bcm, - struct net_device *net_dev, - struct pci_dev *pci_dev) -{ - bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); - bcm->ieee = netdev_priv(net_dev); - bcm->softmac = ieee80211_priv(net_dev); - bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; - - bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; - bcm->mac_suspended = 1; - bcm->pci_dev = pci_dev; - bcm->net_dev = net_dev; - bcm->bad_frames_preempt = modparam_bad_frames_preempt; - spin_lock_init(&bcm->irq_lock); - spin_lock_init(&bcm->leds_lock); - mutex_init(&bcm->mutex); - tasklet_init(&bcm->isr_tasklet, - (void (*)(unsigned long))bcm43xx_interrupt_tasklet, - (unsigned long)bcm); - tasklet_disable_nosync(&bcm->isr_tasklet); - if (modparam_pio) - bcm->__using_pio = 1; - bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; - - /* default to sw encryption for now */ - bcm->ieee->host_build_iv = 0; - bcm->ieee->host_encrypt = 1; - bcm->ieee->host_decrypt = 1; - - bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE; - bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); - bcm->ieee->set_security = bcm43xx_ieee80211_set_security; - bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; - - return 0; -} - -static int __devinit bcm43xx_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *net_dev; - struct bcm43xx_private *bcm; - int err; - -#ifdef DEBUG_SINGLE_DEVICE_ONLY - if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY)) - return -ENODEV; -#endif - - net_dev = alloc_ieee80211softmac(sizeof(*bcm)); - if (!net_dev) { - printk(KERN_ERR PFX - "could not allocate ieee80211 device %s\n", - pci_name(pdev)); - err = -ENOMEM; - goto out; - } - /* initialize the net_device struct */ - SET_NETDEV_DEV(net_dev, &pdev->dev); - - net_dev->open = bcm43xx_net_open; - net_dev->stop = bcm43xx_net_stop; - net_dev->tx_timeout = bcm43xx_net_tx_timeout; -#ifdef CONFIG_NET_POLL_CONTROLLER - net_dev->poll_controller = bcm43xx_net_poll_controller; -#endif - net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; - net_dev->irq = pdev->irq; - SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops); - - /* initialize the bcm43xx_private struct */ - bcm = bcm43xx_priv(net_dev); - memset(bcm, 0, sizeof(*bcm)); - err = bcm43xx_init_private(bcm, net_dev, pdev); - if (err) - goto err_free_netdev; - - pci_set_drvdata(pdev, net_dev); - - err = bcm43xx_attach_board(bcm); - if (err) - goto err_free_netdev; - - err = register_netdev(net_dev); - if (err) { - printk(KERN_ERR PFX "Cannot register net device, " - "aborting.\n"); - err = -ENOMEM; - goto err_detach_board; - } - - bcm43xx_debugfs_add_device(bcm); - - assert(err == 0); -out: - return err; - -err_detach_board: - bcm43xx_detach_board(bcm); -err_free_netdev: - free_ieee80211softmac(net_dev); - goto out; -} - -static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) -{ - struct net_device *net_dev = pci_get_drvdata(pdev); - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - - bcm43xx_debugfs_remove_device(bcm); - unregister_netdev(net_dev); - bcm43xx_detach_board(bcm); - free_ieee80211softmac(net_dev); -} - -/* Hard-reset the chip. Do not call this directly. - * Use bcm43xx_controller_restart() - */ -static void bcm43xx_chip_reset(struct work_struct *work) -{ - struct bcm43xx_private *bcm = - container_of(work, struct bcm43xx_private, restart_work); - struct bcm43xx_phyinfo *phy; - int err = -ENODEV; - - bcm43xx_cancel_work(bcm); - mutex_lock(&(bcm)->mutex); - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - phy = bcm43xx_current_phy(bcm); - err = bcm43xx_select_wireless_core(bcm, phy->type); - if (!err) - bcm43xx_periodic_tasks_setup(bcm); - } - mutex_unlock(&(bcm)->mutex); - - printk(KERN_ERR PFX "Controller restart%s\n", - (err == 0) ? "ed" : " failed"); -} - -/* Hard-reset the chip. - * This can be called from interrupt or process context. - * bcm->irq_lock must be locked. - */ -void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) -{ - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) - return; - printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); - INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset); - schedule_work(&bcm->restart_work); -} - -#ifdef CONFIG_PM - -static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *net_dev = pci_get_drvdata(pdev); - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err; - - dprintk(KERN_INFO PFX "Suspending...\n"); - - netif_device_detach(net_dev); - bcm->was_initialized = 0; - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - bcm->was_initialized = 1; - ieee80211softmac_stop(net_dev); - err = bcm43xx_disable_interrupts_sync(bcm); - if (unlikely(err)) { - dprintk(KERN_ERR PFX "Suspend failed.\n"); - return -EAGAIN; - } - bcm->firmware_norelease = 1; - bcm43xx_free_board(bcm); - bcm->firmware_norelease = 0; - } - bcm43xx_chipset_detach(bcm); - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - dprintk(KERN_INFO PFX "Device suspended.\n"); - - return 0; -} - -static int bcm43xx_resume(struct pci_dev *pdev) -{ - struct net_device *net_dev = pci_get_drvdata(pdev); - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err = 0; - - dprintk(KERN_INFO PFX "Resuming...\n"); - - pci_set_power_state(pdev, 0); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Failure with pci_enable_device!\n"); - return err; - } - pci_restore_state(pdev); - - bcm43xx_chipset_attach(bcm); - if (bcm->was_initialized) - err = bcm43xx_init_board(bcm); - if (err) { - printk(KERN_ERR PFX "Resume failed!\n"); - return err; - } - netif_device_attach(net_dev); - - dprintk(KERN_INFO PFX "Device resumed.\n"); - - return 0; -} - -#endif /* CONFIG_PM */ - -static struct pci_driver bcm43xx_pci_driver = { - .name = KBUILD_MODNAME, - .id_table = bcm43xx_pci_tbl, - .probe = bcm43xx_init_one, - .remove = __devexit_p(bcm43xx_remove_one), -#ifdef CONFIG_PM - .suspend = bcm43xx_suspend, - .resume = bcm43xx_resume, -#endif /* CONFIG_PM */ -}; - -static int __init bcm43xx_init(void) -{ - printk(KERN_INFO KBUILD_MODNAME " driver\n"); - bcm43xx_debugfs_init(); - return pci_register_driver(&bcm43xx_pci_driver); -} - -static void __exit bcm43xx_exit(void) -{ - pci_unregister_driver(&bcm43xx_pci_driver); - bcm43xx_debugfs_exit(); -} - -module_init(bcm43xx_init) -module_exit(bcm43xx_exit) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h deleted file mode 100644 index 14cfbeb582e..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifndef BCM43xx_MAIN_H_ -#define BCM43xx_MAIN_H_ - -#include "bcm43xx.h" - -#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] -#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) -/* Magic helper macro to pad structures. Ignore those above. It's magic. */ -#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) - - -/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ -static inline -u8 bcm43xx_freq_to_channel_a(int freq) -{ - return ((freq - 5000) / 5); -} -static inline -u8 bcm43xx_freq_to_channel_bg(int freq) -{ - u8 channel; - - if (freq == 2484) - channel = 14; - else - channel = (freq - 2407) / 5; - - return channel; -} -static inline -u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, - int freq) -{ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) - return bcm43xx_freq_to_channel_a(freq); - return bcm43xx_freq_to_channel_bg(freq); -} - -/* Lightweight function to convert a channel number to a frequency (in Mhz). */ -static inline -int bcm43xx_channel_to_freq_a(u8 channel) -{ - return (5000 + (5 * channel)); -} -static inline -int bcm43xx_channel_to_freq_bg(u8 channel) -{ - int freq; - - if (channel == 14) - freq = 2484; - else - freq = 2407 + (5 * channel); - - return freq; -} -static inline -int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, - u8 channel) -{ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) - return bcm43xx_channel_to_freq_a(channel); - return bcm43xx_channel_to_freq_bg(channel); -} - -void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); -void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); - -void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, - int iw_mode); - -u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, - u16 routing, u16 offset); -u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, - u16 routing, u16 offset); -void bcm43xx_shm_write32(struct bcm43xx_private *bcm, - u16 routing, u16 offset, - u32 value); -void bcm43xx_shm_write16(struct bcm43xx_private *bcm, - u16 routing, u16 offset, - u16 value); - -void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); - -int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); - -int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, - int phytype); - -void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); - -void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); -void bcm43xx_mac_enable(struct bcm43xx_private *bcm); - -void bcm43xx_cancel_work(struct bcm43xx_private *bcm); -void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm); - -void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); - -int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); -int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom); - -#endif /* BCM43xx_MAIN_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c deleted file mode 100644 index af3de334365..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ /dev/null @@ -1,2346 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/types.h> - -#include "bcm43xx.h" -#include "bcm43xx_phy.h" -#include "bcm43xx_main.h" -#include "bcm43xx_radio.h" -#include "bcm43xx_ilt.h" -#include "bcm43xx_power.h" - - -static const s8 bcm43xx_tssi2dbm_b_table[] = { - 0x4D, 0x4C, 0x4B, 0x4A, - 0x4A, 0x49, 0x48, 0x47, - 0x47, 0x46, 0x45, 0x45, - 0x44, 0x43, 0x42, 0x42, - 0x41, 0x40, 0x3F, 0x3E, - 0x3D, 0x3C, 0x3B, 0x3A, - 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x32, 0x31, - 0x30, 0x2F, 0x2D, 0x2C, - 0x2B, 0x29, 0x28, 0x26, - 0x25, 0x23, 0x21, 0x1F, - 0x1D, 0x1A, 0x17, 0x14, - 0x10, 0x0C, 0x06, 0x00, - -7, -7, -7, -7, - -7, -7, -7, -7, - -7, -7, -7, -7, -}; - -static const s8 bcm43xx_tssi2dbm_g_table[] = { - 77, 77, 77, 76, - 76, 76, 75, 75, - 74, 74, 73, 73, - 73, 72, 72, 71, - 71, 70, 70, 69, - 68, 68, 67, 67, - 66, 65, 65, 64, - 63, 63, 62, 61, - 60, 59, 58, 57, - 56, 55, 54, 53, - 52, 50, 49, 47, - 45, 43, 40, 37, - 33, 28, 22, 14, - 5, -7, -20, -20, - -20, -20, -20, -20, - -20, -20, -20, -20, -}; - -static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); - - -static inline -void bcm43xx_voluntary_preempt(void) -{ - assert(!in_atomic() && !in_irq() && - !in_interrupt() && !irqs_disabled()); -#ifndef CONFIG_PREEMPT - cond_resched(); -#endif /* CONFIG_PREEMPT */ -} - -void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - assert(irqs_disabled()); - if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { - phy->is_locked = 0; - return; - } - if (bcm->current_core->rev < 3) { - bcm43xx_mac_suspend(bcm); - spin_lock(&phy->lock); - } else { - if (bcm->ieee->iw_mode != IW_MODE_MASTER) - bcm43xx_power_saving_ctl_bits(bcm, -1, 1); - } - phy->is_locked = 1; -} - -void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - assert(irqs_disabled()); - if (bcm->current_core->rev < 3) { - if (phy->is_locked) { - spin_unlock(&phy->lock); - bcm43xx_mac_enable(bcm); - } - } else { - if (bcm->ieee->iw_mode != IW_MODE_MASTER) - bcm43xx_power_saving_ctl_bits(bcm, -1, -1); - } - phy->is_locked = 0; -} - -u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) -{ - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); - return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA); -} - -void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) -{ - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); -} - -void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ - if (phy->calibrated) - return; - if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { - bcm43xx_wireless_core_reset(bcm, 0); - bcm43xx_phy_initg(bcm); - bcm43xx_wireless_core_reset(bcm, 1); - } - phy->calibrated = 1; -} - -/* Connect the PHY - * http://bcm-specs.sipsolutions.net/SetPHY - */ -int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u32 flags; - - if (bcm->current_core->rev < 5) - goto out; - - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); - if (connect) { - if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL)) - return -ENODEV; - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); - } else { - if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL)) - return -ENODEV; - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); - } -out: - phy->connected = connect; - if (connect) - dprintk(KERN_INFO PFX "PHY connected\n"); - else - dprintk(KERN_INFO PFX "PHY disconnected\n"); - - return 0; -} - -/* intialize B PHY power control - * as described in http://bcm-specs.sipsolutions.net/InitPowerControl - */ -static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; - int must_reset_txpower = 0; - - assert(phy->type != BCM43xx_PHYTYPE_A); - if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && - (bcm->board_type == 0x0416)) - return; - - bcm43xx_phy_write(bcm, 0x0028, 0x8018); - bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); - - if (phy->type == BCM43xx_PHYTYPE_G) { - if (!phy->connected) - return; - bcm43xx_phy_write(bcm, 0x047A, 0xC111); - } - if (phy->savedpctlreg != 0xFFFF) - return; - - if (phy->type == BCM43xx_PHYTYPE_B && - phy->rev >= 2 && - radio->version == 0x2050) { - bcm43xx_radio_write16(bcm, 0x0076, - bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); - } else { - saved_batt = radio->baseband_atten; - saved_ratt = radio->radio_atten; - saved_txctl1 = radio->txctl1; - if ((radio->revision >= 6) && (radio->revision <= 8) - && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) - bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); - else - bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0); - must_reset_txpower = 1; - } - bcm43xx_dummy_transmission(bcm); - - phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL); - - if (must_reset_txpower) - bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1); - else - bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B); - bcm43xx_radio_clear_tssi(bcm); -} - -static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 offset = 0x0000; - - if (phy->rev == 1) - offset = 0x4C00; - - bcm43xx_ilt_write(bcm, offset, 0x00FE); - bcm43xx_ilt_write(bcm, offset + 1, 0x000D); - bcm43xx_ilt_write(bcm, offset + 2, 0x0013); - bcm43xx_ilt_write(bcm, offset + 3, 0x0019); - - if (phy->rev == 1) { - bcm43xx_ilt_write(bcm, 0x1800, 0x2710); - bcm43xx_ilt_write(bcm, 0x1801, 0x9B83); - bcm43xx_ilt_write(bcm, 0x1802, 0x9B83); - bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D); - bcm43xx_phy_write(bcm, 0x0455, 0x0004); - } - - bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700); - bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F); - bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80); - bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300); - - bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008); - - bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008); - bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600); - bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700); - bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100); - - if (phy->rev == 1) - bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007); - - bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C); - bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200); - bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C); - bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020); - bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200); - bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E); - bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00); - bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028); - bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00); - - if (phy->rev == 1) { - bcm43xx_phy_write(bcm, 0x0430, 0x092B); - bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002); - } else { - bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1); - bcm43xx_phy_write(bcm, 0x041F, 0x287A); - bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004); - } - - if (phy->rev > 2) { - bcm43xx_phy_write(bcm, 0x0422, 0x287A); - bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) - & 0x0FFF) | 0x3000); - } - - bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) - | 0x7874); - bcm43xx_phy_write(bcm, 0x048E, 0x1C00); - - if (phy->rev == 1) { - bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) - & 0xF0FF) | 0x0600); - bcm43xx_phy_write(bcm, 0x048B, 0x005E); - bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) - & 0xFF00) | 0x001E); - bcm43xx_phy_write(bcm, 0x048D, 0x0002); - } - - bcm43xx_ilt_write(bcm, offset + 0x0800, 0); - bcm43xx_ilt_write(bcm, offset + 0x0801, 7); - bcm43xx_ilt_write(bcm, offset + 0x0802, 16); - bcm43xx_ilt_write(bcm, offset + 0x0803, 28); - - if (phy->rev >= 6) { - bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426) - & 0xFFFC)); - bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426) - & 0xEFFF)); - } -} - -static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 i; - - assert(phy->type == BCM43xx_PHYTYPE_G); - if (phy->rev == 1) { - bcm43xx_phy_write(bcm, 0x0406, 0x4F19); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) - & 0xFC3F) | 0x0340); - bcm43xx_phy_write(bcm, 0x042C, 0x005A); - bcm43xx_phy_write(bcm, 0x0427, 0x001A); - - for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); - for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); - for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) - bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); - } else { - /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ - bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); - - if (phy->rev == 2) { - bcm43xx_phy_write(bcm, 0x04C0, 0x1861); - bcm43xx_phy_write(bcm, 0x04C1, 0x0271); - } else if (phy->rev > 2) { - bcm43xx_phy_write(bcm, 0x04C0, 0x0098); - bcm43xx_phy_write(bcm, 0x04C1, 0x0070); - bcm43xx_phy_write(bcm, 0x04C9, 0x0080); - } - bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); - - for (i = 0; i < 64; i++) - bcm43xx_ilt_write(bcm, 0x4000 + i, i); - for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); - } - - if (phy->rev <= 2) - for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); - else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) - for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); - else - for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); - - if (phy->rev == 2) - for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); - else if ((phy->rev > 2) && (phy->rev <= 8)) - for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); - - if (phy->rev == 1) { - for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) - bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); - for (i = 0; i < 4; i++) { - bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020); - bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020); - bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020); - bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020); - } - bcm43xx_phy_agcsetup(bcm); - - if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && - (bcm->board_type == 0x0416) && - (bcm->board_revision == 0x0017)) - return; - - bcm43xx_ilt_write(bcm, 0x5001, 0x0002); - bcm43xx_ilt_write(bcm, 0x5002, 0x0001); - } else { - for (i = 0; i <= 0x2F; i++) - bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820); - bcm43xx_phy_agcsetup(bcm); - bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ - bcm43xx_phy_write(bcm, 0x0403, 0x1000); - bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); - bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); - - if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && - (bcm->board_type == 0x0416) && - (bcm->board_revision == 0x0017)) - return; - - bcm43xx_ilt_write(bcm, 0x0401, 0x0002); - bcm43xx_ilt_write(bcm, 0x0402, 0x0001); - } -} - -/* Initialize the noisescaletable for APHY */ -static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - int i; - - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); - for (i = 0; i < 12; i++) { - if (phy->rev == 2) - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); - else - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); - } - if (phy->rev == 2) - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700); - else - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300); - for (i = 0; i < 11; i++) { - if (phy->rev == 2) - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); - else - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); - } - if (phy->rev == 2) - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067); - else - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023); -} - -static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 i; - - assert(phy->type == BCM43xx_PHYTYPE_A); - switch (phy->rev) { - case 2: - bcm43xx_phy_write(bcm, 0x008E, 0x3800); - bcm43xx_phy_write(bcm, 0x0035, 0x03FF); - bcm43xx_phy_write(bcm, 0x0036, 0x0400); - - bcm43xx_ilt_write(bcm, 0x3807, 0x0051); - - bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); - bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); - bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF); - bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); - - bcm43xx_phy_write(bcm, 0x0024, 0x4680); - bcm43xx_phy_write(bcm, 0x0020, 0x0003); - bcm43xx_phy_write(bcm, 0x001D, 0x0F40); - bcm43xx_phy_write(bcm, 0x001F, 0x1C00); - - bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); - bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); - bcm43xx_phy_write(bcm, 0x008E, 0x58C1); - - bcm43xx_ilt_write(bcm, 0x0803, 0x000F); - bcm43xx_ilt_write(bcm, 0x0804, 0x001F); - bcm43xx_ilt_write(bcm, 0x0805, 0x002A); - bcm43xx_ilt_write(bcm, 0x0805, 0x0030); - bcm43xx_ilt_write(bcm, 0x0807, 0x003A); - - bcm43xx_ilt_write(bcm, 0x0000, 0x0013); - bcm43xx_ilt_write(bcm, 0x0001, 0x0013); - bcm43xx_ilt_write(bcm, 0x0002, 0x0013); - bcm43xx_ilt_write(bcm, 0x0003, 0x0013); - bcm43xx_ilt_write(bcm, 0x0004, 0x0015); - bcm43xx_ilt_write(bcm, 0x0005, 0x0015); - bcm43xx_ilt_write(bcm, 0x0006, 0x0019); - - bcm43xx_ilt_write(bcm, 0x0404, 0x0003); - bcm43xx_ilt_write(bcm, 0x0405, 0x0003); - bcm43xx_ilt_write(bcm, 0x0406, 0x0007); - - for (i = 0; i < 16; i++) - bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F); - - bcm43xx_ilt_write(bcm, 0x3003, 0x1044); - bcm43xx_ilt_write(bcm, 0x3004, 0x7201); - bcm43xx_ilt_write(bcm, 0x3006, 0x0040); - bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); - - for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); - for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); - for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) - bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); - bcm43xx_phy_init_noisescaletbl(bcm); - for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) - bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); - break; - case 3: - for (i = 0; i < 64; i++) - bcm43xx_ilt_write(bcm, 0x4000 + i, i); - - bcm43xx_ilt_write(bcm, 0x3807, 0x0051); - - bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); - bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); - bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); - - bcm43xx_phy_write(bcm, 0x0024, 0x4680); - bcm43xx_phy_write(bcm, 0x0020, 0x0003); - bcm43xx_phy_write(bcm, 0x001D, 0x0F40); - bcm43xx_phy_write(bcm, 0x001F, 0x1C00); - bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); - - bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); - for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); - bcm43xx_phy_init_noisescaletbl(bcm); - for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); - - bcm43xx_phy_write(bcm, 0x0003, 0x1808); - - bcm43xx_ilt_write(bcm, 0x0803, 0x000F); - bcm43xx_ilt_write(bcm, 0x0804, 0x001F); - bcm43xx_ilt_write(bcm, 0x0805, 0x002A); - bcm43xx_ilt_write(bcm, 0x0805, 0x0030); - bcm43xx_ilt_write(bcm, 0x0807, 0x003A); - - bcm43xx_ilt_write(bcm, 0x0000, 0x0013); - bcm43xx_ilt_write(bcm, 0x0001, 0x0013); - bcm43xx_ilt_write(bcm, 0x0002, 0x0013); - bcm43xx_ilt_write(bcm, 0x0003, 0x0013); - bcm43xx_ilt_write(bcm, 0x0004, 0x0015); - bcm43xx_ilt_write(bcm, 0x0005, 0x0015); - bcm43xx_ilt_write(bcm, 0x0006, 0x0019); - - bcm43xx_ilt_write(bcm, 0x0404, 0x0003); - bcm43xx_ilt_write(bcm, 0x0405, 0x0003); - bcm43xx_ilt_write(bcm, 0x0406, 0x0007); - - bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); - bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); - break; - default: - assert(0); - } -} - -/* Initialize APHY. This is also called for the GPHY in some cases. */ -static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 tval; - - if (phy->type == BCM43xx_PHYTYPE_A) { - bcm43xx_phy_setupa(bcm); - } else { - bcm43xx_phy_setupg(bcm); - if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) - bcm43xx_phy_write(bcm, 0x046E, 0x03CF); - return; - } - - bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340); - bcm43xx_phy_write(bcm, 0x0034, 0x0001); - - TODO();//TODO: RSSI AGC - bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14)); - bcm43xx_radio_init2060(bcm); - - if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) - && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { - if (radio->lofcal == 0xFFFF) { - TODO();//TODO: LOF Cal - bcm43xx_radio_set_tx_iq(bcm); - } else - bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal); - } - - bcm43xx_phy_write(bcm, 0x007A, 0xF111); - - if (phy->savedpctlreg == 0xFFFF) { - bcm43xx_radio_write16(bcm, 0x0019, 0x0000); - bcm43xx_radio_write16(bcm, 0x0017, 0x0020); - - tval = bcm43xx_ilt_read(bcm, 0x3001); - if (phy->rev == 1) { - bcm43xx_ilt_write(bcm, 0x3001, - (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87) - | 0x0058); - } else { - bcm43xx_ilt_write(bcm, 0x3001, - (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3) - | 0x002C); - } - bcm43xx_dummy_transmission(bcm); - phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); - bcm43xx_ilt_write(bcm, 0x3001, tval); - - bcm43xx_radio_set_txpower_a(bcm, 0x0018); - } - bcm43xx_radio_clear_tssi(bcm); -} - -static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 offset, val; - - bcm43xx_write16(bcm, 0x03EC, 0x3F22); - bcm43xx_phy_write(bcm, 0x0020, 0x301C); - bcm43xx_phy_write(bcm, 0x0026, 0x0000); - bcm43xx_phy_write(bcm, 0x0030, 0x00C6); - bcm43xx_phy_write(bcm, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - bcm43xx_phy_write(bcm, offset, val); - val -= 0x0202; - } - bcm43xx_phy_write(bcm, 0x03E4, 0x3000); - if (radio->channel == 0xFF) - bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); - else - bcm43xx_radio_selectchannel(bcm, radio->channel, 0); - if (radio->version != 0x2050) { - bcm43xx_radio_write16(bcm, 0x0075, 0x0080); - bcm43xx_radio_write16(bcm, 0x0079, 0x0081); - } - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x0050, 0x0023); - if (radio->version == 0x2050) { - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x005A, 0x0070); - bcm43xx_radio_write16(bcm, 0x005B, 0x007B); - bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); - bcm43xx_radio_write16(bcm, 0x007A, 0x000F); - bcm43xx_phy_write(bcm, 0x0038, 0x0677); - bcm43xx_radio_init2050(bcm); - } - bcm43xx_phy_write(bcm, 0x0014, 0x0080); - bcm43xx_phy_write(bcm, 0x0032, 0x00CA); - bcm43xx_phy_write(bcm, 0x0032, 0x00CC); - bcm43xx_phy_write(bcm, 0x0035, 0x07C2); - bcm43xx_phy_lo_b_measure(bcm); - bcm43xx_phy_write(bcm, 0x0026, 0xCC00); - if (radio->version != 0x2050) - bcm43xx_phy_write(bcm, 0x0026, 0xCE00); - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000); - bcm43xx_phy_write(bcm, 0x002A, 0x88A3); - if (radio->version != 0x2050) - bcm43xx_phy_write(bcm, 0x002A, 0x88C2); - bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); - bcm43xx_phy_init_pctl(bcm); -} - -static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 offset, val; - - bcm43xx_write16(bcm, 0x03EC, 0x3F22); - bcm43xx_phy_write(bcm, 0x0020, 0x301C); - bcm43xx_phy_write(bcm, 0x0026, 0x0000); - bcm43xx_phy_write(bcm, 0x0030, 0x00C6); - bcm43xx_phy_write(bcm, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - bcm43xx_phy_write(bcm, offset, val); - val -= 0x0202; - } - bcm43xx_phy_write(bcm, 0x03E4, 0x3000); - if (radio->channel == 0xFF) - bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); - else - bcm43xx_radio_selectchannel(bcm, radio->channel, 0); - if (radio->version != 0x2050) { - bcm43xx_radio_write16(bcm, 0x0075, 0x0080); - bcm43xx_radio_write16(bcm, 0x0079, 0x0081); - } - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x0050, 0x0023); - if (radio->version == 0x2050) { - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x005A, 0x0070); - bcm43xx_radio_write16(bcm, 0x005B, 0x007B); - bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); - bcm43xx_radio_write16(bcm, 0x007A, 0x000F); - bcm43xx_phy_write(bcm, 0x0038, 0x0677); - bcm43xx_radio_init2050(bcm); - } - bcm43xx_phy_write(bcm, 0x0014, 0x0080); - bcm43xx_phy_write(bcm, 0x0032, 0x00CA); - if (radio->version == 0x2050) - bcm43xx_phy_write(bcm, 0x0032, 0x00E0); - bcm43xx_phy_write(bcm, 0x0035, 0x07C2); - - bcm43xx_phy_lo_b_measure(bcm); - - bcm43xx_phy_write(bcm, 0x0026, 0xCC00); - if (radio->version == 0x2050) - bcm43xx_phy_write(bcm, 0x0026, 0xCE00); - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100); - bcm43xx_phy_write(bcm, 0x002A, 0x88A3); - if (radio->version == 0x2050) - bcm43xx_phy_write(bcm, 0x002A, 0x88C2); - bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); - if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { - bcm43xx_calc_nrssi_slope(bcm); - bcm43xx_calc_nrssi_threshold(bcm); - } - bcm43xx_phy_init_pctl(bcm); -} - -static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 offset; - u16 value; - u8 old_channel; - - if (phy->analog == 1) - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) - | 0x0050); - if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) && - (bcm->board_type != 0x0416)) { - value = 0x2120; - for (offset = 0x00A8 ; offset < 0x00C7; offset++) { - bcm43xx_phy_write(bcm, offset, value); - value += 0x0202; - } - } - bcm43xx_phy_write(bcm, 0x0035, - (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF) - | 0x0700); - if (radio->version == 0x2050) - bcm43xx_phy_write(bcm, 0x0038, 0x0667); - - if (phy->connected) { - if (radio->version == 0x2050) { - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) - | 0x0020); - bcm43xx_radio_write16(bcm, 0x0051, - bcm43xx_radio_read16(bcm, 0x0051) - | 0x0004); - } - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000); - - bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100); - bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000); - - bcm43xx_phy_write(bcm, 0x001C, 0x186A); - - bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900); - bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064); - bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A); - } - - if (bcm->bad_frames_preempt) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11)); - } - - if (phy->analog == 1) { - bcm43xx_phy_write(bcm, 0x0026, 0xCE00); - bcm43xx_phy_write(bcm, 0x0021, 0x3763); - bcm43xx_phy_write(bcm, 0x0022, 0x1BC3); - bcm43xx_phy_write(bcm, 0x0023, 0x06F9); - bcm43xx_phy_write(bcm, 0x0024, 0x037E); - } else - bcm43xx_phy_write(bcm, 0x0026, 0xCC00); - bcm43xx_phy_write(bcm, 0x0030, 0x00C6); - bcm43xx_write16(bcm, 0x03EC, 0x3F22); - - if (phy->analog == 1) - bcm43xx_phy_write(bcm, 0x0020, 0x3E1C); - else - bcm43xx_phy_write(bcm, 0x0020, 0x301C); - - if (phy->analog == 0) - bcm43xx_write16(bcm, 0x03E4, 0x3000); - - old_channel = radio->channel; - /* Force to channel 7, even if not supported. */ - bcm43xx_radio_selectchannel(bcm, 7, 0); - - if (radio->version != 0x2050) { - bcm43xx_radio_write16(bcm, 0x0075, 0x0080); - bcm43xx_radio_write16(bcm, 0x0079, 0x0081); - } - - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x0050, 0x0023); - - if (radio->version == 0x2050) { - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x005A, 0x0070); - } - - bcm43xx_radio_write16(bcm, 0x005B, 0x007B); - bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); - - bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007); - - bcm43xx_radio_selectchannel(bcm, old_channel, 0); - - bcm43xx_phy_write(bcm, 0x0014, 0x0080); - bcm43xx_phy_write(bcm, 0x0032, 0x00CA); - bcm43xx_phy_write(bcm, 0x002A, 0x88A3); - - bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); - - if (radio->version == 0x2050) - bcm43xx_radio_write16(bcm, 0x005D, 0x000D); - - bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004); -} - -static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 offset, val; - u8 old_channel; - - bcm43xx_phy_write(bcm, 0x003E, 0x817A); - bcm43xx_radio_write16(bcm, 0x007A, - (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058)); - if (radio->revision == 4 || - radio->revision == 5) { - bcm43xx_radio_write16(bcm, 0x0051, 0x0037); - bcm43xx_radio_write16(bcm, 0x0052, 0x0070); - bcm43xx_radio_write16(bcm, 0x0053, 0x00B3); - bcm43xx_radio_write16(bcm, 0x0054, 0x009B); - bcm43xx_radio_write16(bcm, 0x005A, 0x0088); - bcm43xx_radio_write16(bcm, 0x005B, 0x0088); - bcm43xx_radio_write16(bcm, 0x005D, 0x0088); - bcm43xx_radio_write16(bcm, 0x005E, 0x0088); - bcm43xx_radio_write16(bcm, 0x007D, 0x0088); - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET) - | 0x00000200)); - } - if (radio->revision == 8) { - bcm43xx_radio_write16(bcm, 0x0051, 0x0000); - bcm43xx_radio_write16(bcm, 0x0052, 0x0040); - bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); - bcm43xx_radio_write16(bcm, 0x0054, 0x0098); - bcm43xx_radio_write16(bcm, 0x005A, 0x0088); - bcm43xx_radio_write16(bcm, 0x005B, 0x006B); - bcm43xx_radio_write16(bcm, 0x005C, 0x000F); - if (bcm->sprom.boardflags & 0x8000) { - bcm43xx_radio_write16(bcm, 0x005D, 0x00FA); - bcm43xx_radio_write16(bcm, 0x005E, 0x00D8); - } else { - bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); - bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); - } - bcm43xx_radio_write16(bcm, 0x0073, 0x0003); - bcm43xx_radio_write16(bcm, 0x007D, 0x00A8); - bcm43xx_radio_write16(bcm, 0x007C, 0x0001); - bcm43xx_radio_write16(bcm, 0x007E, 0x0008); - } - val = 0x1E1F; - for (offset = 0x0088; offset < 0x0098; offset++) { - bcm43xx_phy_write(bcm, offset, val); - val -= 0x0202; - } - val = 0x3E3F; - for (offset = 0x0098; offset < 0x00A8; offset++) { - bcm43xx_phy_write(bcm, offset, val); - val -= 0x0202; - } - val = 0x2120; - for (offset = 0x00A8; offset < 0x00C8; offset++) { - bcm43xx_phy_write(bcm, offset, (val & 0x3F3F)); - val += 0x0202; - } - if (phy->type == BCM43xx_PHYTYPE_G) { - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x0020); - bcm43xx_radio_write16(bcm, 0x0051, - bcm43xx_radio_read16(bcm, 0x0051) | 0x0004); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) | 0x0100); - bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) | 0x2000); - bcm43xx_phy_write(bcm, 0x5B, 0x0000); - bcm43xx_phy_write(bcm, 0x5C, 0x0000); - } - - old_channel = radio->channel; - if (old_channel >= 8) - bcm43xx_radio_selectchannel(bcm, 1, 0); - else - bcm43xx_radio_selectchannel(bcm, 13, 0); - - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - bcm43xx_radio_write16(bcm, 0x0050, 0x0023); - udelay(40); - if (radio->revision < 6 || radio-> revision == 8) { - bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) - | 0x0002)); - bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - } - if (radio->revision <= 2) { - bcm43xx_radio_write16(bcm, 0x007C, 0x0020); - bcm43xx_radio_write16(bcm, 0x005A, 0x0070); - bcm43xx_radio_write16(bcm, 0x005B, 0x007B); - bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); - } - bcm43xx_radio_write16(bcm, 0x007A, - (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007); - - bcm43xx_radio_selectchannel(bcm, old_channel, 0); - - bcm43xx_phy_write(bcm, 0x0014, 0x0200); - if (radio->revision >= 6) - bcm43xx_phy_write(bcm, 0x002A, 0x88C2); - else - bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); - bcm43xx_phy_write(bcm, 0x0038, 0x0668); - bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); - if (radio->revision <= 5) - bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) - & 0xFF80) | 0x0003); - if (radio->revision <= 2) - bcm43xx_radio_write16(bcm, 0x005D, 0x000D); - - if (phy->analog == 4){ - bcm43xx_write16(bcm, 0x03E4, 0x0009); - bcm43xx_phy_write(bcm, 0x61, bcm43xx_phy_read(bcm, 0x61) & 0xFFF); - } else { - bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); - } - if (phy->type == BCM43xx_PHYTYPE_G) - bcm43xx_write16(bcm, 0x03E6, 0x0); - if (phy->type == BCM43xx_PHYTYPE_B) { - bcm43xx_write16(bcm, 0x03E6, 0x8140); - bcm43xx_phy_write(bcm, 0x0016, 0x0410); - bcm43xx_phy_write(bcm, 0x0017, 0x0820); - bcm43xx_phy_write(bcm, 0x0062, 0x0007); - bcm43xx_radio_init2050(bcm); - bcm43xx_phy_lo_g_measure(bcm); - if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { - bcm43xx_calc_nrssi_slope(bcm); - bcm43xx_calc_nrssi_threshold(bcm); - } - bcm43xx_phy_init_pctl(bcm); - } -} - -static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 backup_phy[15] = {0}; - u16 backup_radio[3]; - u16 backup_bband; - u16 i; - u16 loop1_cnt, loop1_done, loop1_omitted; - u16 loop2_done; - - backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429); - backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001); - backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811); - backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812); - if (phy->rev != 1) { - backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814); - backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815); - } - backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A); - backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059); - backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058); - backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A); - backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003); - backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F); - backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810); - backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B); - backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015); - bcm43xx_phy_read(bcm, 0x002D); /* dummy read */ - backup_bband = radio->baseband_atten; - backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052); - backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043); - backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A); - - bcm43xx_phy_write(bcm, 0x0429, - bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF); - bcm43xx_phy_write(bcm, 0x0001, - bcm43xx_phy_read(bcm, 0x0001) & 0x8000); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x0002); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x0001); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE); - if (phy->rev != 1) { - bcm43xx_phy_write(bcm, 0x0814, - bcm43xx_phy_read(bcm, 0x0814) | 0x0001); - bcm43xx_phy_write(bcm, 0x0815, - bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); - bcm43xx_phy_write(bcm, 0x0814, - bcm43xx_phy_read(bcm, 0x0814) | 0x0002); - bcm43xx_phy_write(bcm, 0x0815, - bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD); - } - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x000C); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) | 0x000C); - - bcm43xx_phy_write(bcm, 0x0811, - (bcm43xx_phy_read(bcm, 0x0811) - & 0xFFCF) | 0x0030); - bcm43xx_phy_write(bcm, 0x0812, - (bcm43xx_phy_read(bcm, 0x0812) - & 0xFFCF) | 0x0010); - - bcm43xx_phy_write(bcm, 0x005A, 0x0780); - bcm43xx_phy_write(bcm, 0x0059, 0xC810); - bcm43xx_phy_write(bcm, 0x0058, 0x000D); - if (phy->analog == 0) { - bcm43xx_phy_write(bcm, 0x0003, 0x0122); - } else { - bcm43xx_phy_write(bcm, 0x000A, - bcm43xx_phy_read(bcm, 0x000A) - | 0x2000); - } - if (phy->rev != 1) { - bcm43xx_phy_write(bcm, 0x0814, - bcm43xx_phy_read(bcm, 0x0814) | 0x0004); - bcm43xx_phy_write(bcm, 0x0815, - bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); - } - bcm43xx_phy_write(bcm, 0x0003, - (bcm43xx_phy_read(bcm, 0x0003) - & 0xFF9F) | 0x0040); - if (radio->version == 0x2050 && radio->revision == 2) { - bcm43xx_radio_write16(bcm, 0x0052, 0x0000); - bcm43xx_radio_write16(bcm, 0x0043, - (bcm43xx_radio_read16(bcm, 0x0043) - & 0xFFF0) | 0x0009); - loop1_cnt = 9; - } else if (radio->revision == 8) { - bcm43xx_radio_write16(bcm, 0x0043, 0x000F); - loop1_cnt = 15; - } else - loop1_cnt = 0; - - bcm43xx_phy_set_baseband_attenuation(bcm, 11); - - if (phy->rev >= 3) - bcm43xx_phy_write(bcm, 0x080F, 0xC020); - else - bcm43xx_phy_write(bcm, 0x080F, 0x8020); - bcm43xx_phy_write(bcm, 0x0810, 0x0000); - - bcm43xx_phy_write(bcm, 0x002B, - (bcm43xx_phy_read(bcm, 0x002B) - & 0xFFC0) | 0x0001); - bcm43xx_phy_write(bcm, 0x002B, - (bcm43xx_phy_read(bcm, 0x002B) - & 0xC0FF) | 0x0800); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x0100); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF); - if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) { - if (phy->rev >= 7) { - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) - | 0x0800); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) - | 0x8000); - } - } - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) - & 0x00F7); - - for (i = 0; i < loop1_cnt; i++) { - bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt); - bcm43xx_phy_write(bcm, 0x0812, - (bcm43xx_phy_read(bcm, 0x0812) - & 0xF0FF) | (i << 8)); - bcm43xx_phy_write(bcm, 0x0015, - (bcm43xx_phy_read(bcm, 0x0015) - & 0x0FFF) | 0xA000); - bcm43xx_phy_write(bcm, 0x0015, - (bcm43xx_phy_read(bcm, 0x0015) - & 0x0FFF) | 0xF000); - udelay(20); - if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) - break; - } - loop1_done = i; - loop1_omitted = loop1_cnt - loop1_done; - - loop2_done = 0; - if (loop1_done >= 8) { - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) - | 0x0030); - for (i = loop1_done - 8; i < 16; i++) { - bcm43xx_phy_write(bcm, 0x0812, - (bcm43xx_phy_read(bcm, 0x0812) - & 0xF0FF) | (i << 8)); - bcm43xx_phy_write(bcm, 0x0015, - (bcm43xx_phy_read(bcm, 0x0015) - & 0x0FFF) | 0xA000); - bcm43xx_phy_write(bcm, 0x0015, - (bcm43xx_phy_read(bcm, 0x0015) - & 0x0FFF) | 0xF000); - udelay(20); - if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) - break; - } - } - - if (phy->rev != 1) { - bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]); - bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]); - } - bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]); - bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]); - bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]); - bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]); - bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]); - bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]); - bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]); - bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]); - bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]); - - bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband); - - bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]); - bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]); - bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]); - - bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003); - udelay(10); - bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]); - bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]); - bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]); - bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]); - - phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; - phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; -} - -static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 tmp; - - if (phy->rev == 1) - bcm43xx_phy_initb5(bcm); - else - bcm43xx_phy_initb6(bcm); - if (phy->rev >= 2 || phy->connected) - bcm43xx_phy_inita(bcm); - - if (phy->rev >= 2) { - bcm43xx_phy_write(bcm, 0x0814, 0x0000); - bcm43xx_phy_write(bcm, 0x0815, 0x0000); - } - if (phy->rev == 2) { - bcm43xx_phy_write(bcm, 0x0811, 0x0000); - bcm43xx_phy_write(bcm, 0x0015, 0x00C0); - } - if (phy->rev > 5) { - bcm43xx_phy_write(bcm, 0x0811, 0x0400); - bcm43xx_phy_write(bcm, 0x0015, 0x00C0); - } - if (phy->rev >= 2 && phy->connected) { - tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; - if (tmp ==3 || tmp == 5) { - bcm43xx_phy_write(bcm, 0x04C2, 0x1816); - bcm43xx_phy_write(bcm, 0x04C3, 0x8006); - if (tmp == 5) { - bcm43xx_phy_write(bcm, 0x04CC, - (bcm43xx_phy_read(bcm, 0x04CC) - & 0x00FF) | 0x1F00); - } - } - bcm43xx_phy_write(bcm, 0x047E, 0x0078); - } - if (radio->revision == 8) { - bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); - bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); - } - if (phy->rev >= 2 && phy->connected) - bcm43xx_calc_loopback_gain(bcm); - if (radio->revision != 8) { - if (radio->initval == 0xFFFF) - radio->initval = bcm43xx_radio_init2050(bcm); - else - bcm43xx_radio_write16(bcm, 0x0078, radio->initval); - } - if (radio->txctl2 == 0xFFFF) { - bcm43xx_phy_lo_g_measure(bcm); - } else { - if (radio->version == 0x2050 && radio->revision == 8) { - bcm43xx_radio_write16(bcm, 0x0052, - (radio->txctl1 << 4) | radio->txctl2); - } else { - bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) - & 0xFFF0) | radio->txctl1); - } - if (phy->rev >= 6) { - bcm43xx_phy_write(bcm, 0x0036, - (bcm43xx_phy_read(bcm, 0x0036) - & 0x0FFF) | (radio->txctl2 << 12)); - } - if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) - bcm43xx_phy_write(bcm, 0x002E, 0x8075); - else - bcm43xx_phy_write(bcm, 0x002E, 0x807F); - if (phy->rev < 2) - bcm43xx_phy_write(bcm, 0x002F, 0x0101); - else - bcm43xx_phy_write(bcm, 0x002F, 0x0202); - } - if (phy->connected || phy->rev >= 2) { - bcm43xx_phy_lo_adjust(bcm, 0); - bcm43xx_phy_write(bcm, 0x080F, 0x8078); - } - - if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { - /* The specs state to update the NRSSI LT with - * the value 0x7FFFFFFF here. I think that is some weird - * compiler optimization in the original driver. - * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the limit_value() in nrssi_hw_update()) - */ - bcm43xx_nrssi_hw_update(bcm, 0xFFFF); - bcm43xx_calc_nrssi_threshold(bcm); - } else if (phy->connected || phy->rev >= 2) { - if (radio->nrssi[0] == -1000) { - assert(radio->nrssi[1] == -1000); - bcm43xx_calc_nrssi_slope(bcm); - } else { - assert(radio->nrssi[1] != -1000); - bcm43xx_calc_nrssi_threshold(bcm); - } - } - if (radio->revision == 8) - bcm43xx_phy_write(bcm, 0x0805, 0x3230); - bcm43xx_phy_init_pctl(bcm); - if (bcm->chip_id == 0x4306 && bcm->chip_package == 2) { - bcm43xx_phy_write(bcm, 0x0429, - bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); - bcm43xx_phy_write(bcm, 0x04C3, - bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF); - } -} - -static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) -{ - int i; - u16 ret = 0; - unsigned long flags; - - local_irq_save(flags); - for (i = 0; i < 10; i++){ - bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); - udelay(1); - bcm43xx_phy_write(bcm, 0x0015, 0xEFA0); - udelay(10); - bcm43xx_phy_write(bcm, 0x0015, 0xFFA0); - udelay(40); - ret += bcm43xx_phy_read(bcm, 0x002C); - } - local_irq_restore(flags); - bcm43xx_voluntary_preempt(); - - return ret; -} - -void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 regstack[12] = { 0 }; - u16 mls; - u16 fval; - int i, j; - - regstack[0] = bcm43xx_phy_read(bcm, 0x0015); - regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0; - - if (radio->version == 0x2053) { - regstack[2] = bcm43xx_phy_read(bcm, 0x000A); - regstack[3] = bcm43xx_phy_read(bcm, 0x002A); - regstack[4] = bcm43xx_phy_read(bcm, 0x0035); - regstack[5] = bcm43xx_phy_read(bcm, 0x0003); - regstack[6] = bcm43xx_phy_read(bcm, 0x0001); - regstack[7] = bcm43xx_phy_read(bcm, 0x0030); - - regstack[8] = bcm43xx_radio_read16(bcm, 0x0043); - regstack[9] = bcm43xx_radio_read16(bcm, 0x007A); - regstack[10] = bcm43xx_read16(bcm, 0x03EC); - regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0; - - bcm43xx_phy_write(bcm, 0x0030, 0x00FF); - bcm43xx_write16(bcm, 0x03EC, 0x3F3F); - bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F); - bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0); - } - bcm43xx_phy_write(bcm, 0x0015, 0xB000); - bcm43xx_phy_write(bcm, 0x002B, 0x0004); - - if (radio->version == 0x2053) { - bcm43xx_phy_write(bcm, 0x002B, 0x0203); - bcm43xx_phy_write(bcm, 0x002A, 0x08A3); - } - - phy->minlowsig[0] = 0xFFFF; - - for (i = 0; i < 4; i++) { - bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); - bcm43xx_phy_lo_b_r15_loop(bcm); - } - for (i = 0; i < 10; i++) { - bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); - mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; - if (mls < phy->minlowsig[0]) { - phy->minlowsig[0] = mls; - phy->minlowsigpos[0] = i; - } - } - bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]); - - phy->minlowsig[1] = 0xFFFF; - - for (i = -4; i < 5; i += 2) { - for (j = -4; j < 5; j += 2) { - if (j < 0) - fval = (0x0100 * i) + j + 0x0100; - else - fval = (0x0100 * i) + j; - bcm43xx_phy_write(bcm, 0x002F, fval); - mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; - if (mls < phy->minlowsig[1]) { - phy->minlowsig[1] = mls; - phy->minlowsigpos[1] = fval; - } - } - } - phy->minlowsigpos[1] += 0x0101; - - bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); - if (radio->version == 0x2053) { - bcm43xx_phy_write(bcm, 0x000A, regstack[2]); - bcm43xx_phy_write(bcm, 0x002A, regstack[3]); - bcm43xx_phy_write(bcm, 0x0035, regstack[4]); - bcm43xx_phy_write(bcm, 0x0003, regstack[5]); - bcm43xx_phy_write(bcm, 0x0001, regstack[6]); - bcm43xx_phy_write(bcm, 0x0030, regstack[7]); - - bcm43xx_radio_write16(bcm, 0x0043, regstack[8]); - bcm43xx_radio_write16(bcm, 0x007A, regstack[9]); - - bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F) - | regstack[11]); - - bcm43xx_write16(bcm, 0x03EC, regstack[10]); - } - bcm43xx_phy_write(bcm, 0x0015, regstack[0]); -} - -static inline -u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 ret; - unsigned long flags; - - local_irq_save(flags); - if (phy->connected) { - bcm43xx_phy_write(bcm, 0x15, 0xE300); - control <<= 8; - bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); - udelay(5); - bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2); - udelay(2); - bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3); - udelay(4); - bcm43xx_phy_write(bcm, 0x0015, 0xF300); - udelay(8); - } else { - bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0); - udelay(2); - bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0); - udelay(4); - bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); - udelay(8); - } - ret = bcm43xx_phy_read(bcm, 0x002D); - local_irq_restore(flags); - bcm43xx_voluntary_preempt(); - - return ret; -} - -static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) -{ - int i; - u32 ret = 0; - - for (i = 0; i < 8; i++) - ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control); - - return ret; -} - -/* Write the LocalOscillator CONTROL */ -static inline -void bcm43xx_lo_write(struct bcm43xx_private *bcm, - struct bcm43xx_lopair *pair) -{ - u16 value; - - value = (u8)(pair->low); - value |= ((u8)(pair->high)) << 8; - -#ifdef CONFIG_BCM43XX_DEBUG - /* Sanity check. */ - if (pair->low < -8 || pair->low > 8 || - pair->high < -8 || pair->high > 8) { - printk(KERN_WARNING PFX - "WARNING: Writing invalid LOpair " - "(low: %d, high: %d, index: %lu)\n", - pair->low, pair->high, - (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs)); - dump_stack(); - } -#endif - - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value); -} - -static inline -struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, - u16 baseband_attenuation, - u16 radio_attenuation, - u16 tx) -{ - static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - if (baseband_attenuation > 6) - baseband_attenuation = 6; - assert(radio_attenuation < 10); - - if (tx == 3) { - return bcm43xx_get_lopair(phy, - radio_attenuation, - baseband_attenuation); - } - return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation); -} - -static inline -struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - - return bcm43xx_find_lopair(bcm, - radio->baseband_atten, - radio->radio_atten, - radio->txctl1); -} - -/* Adjust B/G LO */ -void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) -{ - struct bcm43xx_lopair *pair; - - if (fixed) { - /* Use fixed values. Only for initialization. */ - pair = bcm43xx_find_lopair(bcm, 2, 3, 0); - } else - pair = bcm43xx_current_lopair(bcm); - bcm43xx_lo_write(bcm, pair); -} - -static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 txctl2 = 0, i; - u32 smallest, tmp; - - bcm43xx_radio_write16(bcm, 0x0052, 0x0000); - udelay(10); - smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0); - for (i = 0; i < 16; i++) { - bcm43xx_radio_write16(bcm, 0x0052, i); - udelay(10); - tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0); - if (tmp < smallest) { - smallest = tmp; - txctl2 = i; - } - } - radio->txctl2 = txctl2; -} - -static -void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, - const struct bcm43xx_lopair *in_pair, - struct bcm43xx_lopair *out_pair, - u16 r27) -{ - static const struct bcm43xx_lopair transitions[8] = { - { .high = 1, .low = 1, }, - { .high = 1, .low = 0, }, - { .high = 1, .low = -1, }, - { .high = 0, .low = -1, }, - { .high = -1, .low = -1, }, - { .high = -1, .low = 0, }, - { .high = -1, .low = 1, }, - { .high = 0, .low = 1, }, - }; - struct bcm43xx_lopair lowest_transition = { - .high = in_pair->high, - .low = in_pair->low, - }; - struct bcm43xx_lopair tmp_pair; - struct bcm43xx_lopair transition; - int i = 12; - int state = 0; - int found_lower; - int j, begin, end; - u32 lowest_deviation; - u32 tmp; - - /* Note that in_pair and out_pair can point to the same pair. Be careful. */ - - bcm43xx_lo_write(bcm, &lowest_transition); - lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27); - do { - found_lower = 0; - assert(state >= 0 && state <= 8); - if (state == 0) { - begin = 1; - end = 8; - } else if (state % 2 == 0) { - begin = state - 1; - end = state + 1; - } else { - begin = state - 2; - end = state + 2; - } - if (begin < 1) - begin += 8; - if (end > 8) - end -= 8; - - j = begin; - tmp_pair.high = lowest_transition.high; - tmp_pair.low = lowest_transition.low; - while (1) { - assert(j >= 1 && j <= 8); - transition.high = tmp_pair.high + transitions[j - 1].high; - transition.low = tmp_pair.low + transitions[j - 1].low; - if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) { - bcm43xx_lo_write(bcm, &transition); - tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27); - if (tmp < lowest_deviation) { - lowest_deviation = tmp; - state = j; - found_lower = 1; - - lowest_transition.high = transition.high; - lowest_transition.low = transition.low; - } - } - if (j == end) - break; - if (j == 8) - j = 1; - else - j++; - } - } while (i-- && found_lower); - - out_pair->high = lowest_transition.high; - out_pair->low = lowest_transition.low; -} - -/* Set the baseband attenuation value on chip. */ -void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, - u16 baseband_attenuation) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 value; - - if (phy->analog == 0) { - value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); - value |= (baseband_attenuation & 0x000F); - bcm43xx_write16(bcm, 0x03E6, value); - return; - } - - if (phy->analog > 1) { - value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; - value |= (baseband_attenuation << 2) & 0x003C; - } else { - value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078; - value |= (baseband_attenuation << 3) & 0x0078; - } - bcm43xx_phy_write(bcm, 0x0060, value); -} - -/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ -void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) -{ - static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; - const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 h, i, oldi = 0, j; - struct bcm43xx_lopair control; - struct bcm43xx_lopair *tmp_control; - u16 tmp; - u16 regstack[16] = { 0 }; - u8 oldchannel; - - //XXX: What are these? - u8 r27 = 0, r31; - - oldchannel = radio->channel; - /* Setup */ - if (phy->connected) { - regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); - regstack[1] = bcm43xx_phy_read(bcm, 0x0802); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); - bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); - } - regstack[3] = bcm43xx_read16(bcm, 0x03E2); - bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000); - regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); - regstack[5] = bcm43xx_phy_read(bcm, 0x15); - regstack[6] = bcm43xx_phy_read(bcm, 0x2A); - regstack[7] = bcm43xx_phy_read(bcm, 0x35); - regstack[8] = bcm43xx_phy_read(bcm, 0x60); - regstack[9] = bcm43xx_radio_read16(bcm, 0x43); - regstack[10] = bcm43xx_radio_read16(bcm, 0x7A); - regstack[11] = bcm43xx_radio_read16(bcm, 0x52); - if (phy->connected) { - regstack[12] = bcm43xx_phy_read(bcm, 0x0811); - regstack[13] = bcm43xx_phy_read(bcm, 0x0812); - regstack[14] = bcm43xx_phy_read(bcm, 0x0814); - regstack[15] = bcm43xx_phy_read(bcm, 0x0815); - } - bcm43xx_radio_selectchannel(bcm, 6, 0); - if (phy->connected) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); - bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); - bcm43xx_dummy_transmission(bcm); - } - bcm43xx_radio_write16(bcm, 0x0043, 0x0006); - - bcm43xx_phy_set_baseband_attenuation(bcm, 2); - - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000); - bcm43xx_phy_write(bcm, 0x002E, 0x007F); - bcm43xx_phy_write(bcm, 0x080F, 0x0078); - bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7)); - bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0); - bcm43xx_phy_write(bcm, 0x002B, 0x0203); - bcm43xx_phy_write(bcm, 0x002A, 0x08A3); - if (phy->connected) { - bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003); - bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC); - bcm43xx_phy_write(bcm, 0x0811, 0x01B3); - bcm43xx_phy_write(bcm, 0x0812, 0x00B2); - } - if (is_initializing) - bcm43xx_phy_lo_g_measure_txctl2(bcm); - bcm43xx_phy_write(bcm, 0x080F, 0x8078); - - /* Measure */ - control.low = 0; - control.high = 0; - for (h = 0; h < 10; h++) { - /* Loop over each possible RadioAttenuation (0-9) */ - i = pairorder[h]; - if (is_initializing) { - if (i == 3) { - control.low = 0; - control.high = 0; - } else if (((i % 2 == 1) && (oldi % 2 == 1)) || - ((i % 2 == 0) && (oldi % 2 == 0))) { - tmp_control = bcm43xx_get_lopair(phy, oldi, 0); - memcpy(&control, tmp_control, sizeof(control)); - } else { - tmp_control = bcm43xx_get_lopair(phy, 3, 0); - memcpy(&control, tmp_control, sizeof(control)); - } - } - /* Loop over each possible BasebandAttenuation/2 */ - for (j = 0; j < 4; j++) { - if (is_initializing) { - tmp = i * 2 + j; - r27 = 0; - r31 = 0; - if (tmp > 14) { - r31 = 1; - if (tmp > 17) - r27 = 1; - if (tmp > 19) - r27 = 2; - } - } else { - tmp_control = bcm43xx_get_lopair(phy, i, j * 2); - if (!tmp_control->used) - continue; - memcpy(&control, tmp_control, sizeof(control)); - r27 = 3; - r31 = 0; - } - bcm43xx_radio_write16(bcm, 0x43, i); - bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); - udelay(10); - bcm43xx_voluntary_preempt(); - - bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); - - tmp = (regstack[10] & 0xFFF0); - if (r31) - tmp |= 0x0008; - bcm43xx_radio_write16(bcm, 0x007A, tmp); - - tmp_control = bcm43xx_get_lopair(phy, i, j * 2); - bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); - } - oldi = i; - } - /* Loop over each possible RadioAttenuation (10-13) */ - for (i = 10; i < 14; i++) { - /* Loop over each possible BasebandAttenuation/2 */ - for (j = 0; j < 4; j++) { - if (is_initializing) { - tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); - memcpy(&control, tmp_control, sizeof(control)); - tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger. - r27 = 0; - r31 = 0; - if (tmp > 14) { - r31 = 1; - if (tmp > 17) - r27 = 1; - if (tmp > 19) - r27 = 2; - } - } else { - tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); - if (!tmp_control->used) - continue; - memcpy(&control, tmp_control, sizeof(control)); - r27 = 3; - r31 = 0; - } - bcm43xx_radio_write16(bcm, 0x43, i - 9); - bcm43xx_radio_write16(bcm, 0x52, - radio->txctl2 - | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? - udelay(10); - bcm43xx_voluntary_preempt(); - - bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); - - tmp = (regstack[10] & 0xFFF0); - if (r31) - tmp |= 0x0008; - bcm43xx_radio_write16(bcm, 0x7A, tmp); - - tmp_control = bcm43xx_get_lopair(phy, i, j * 2); - bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); - } - } - - /* Restoration */ - if (phy->connected) { - bcm43xx_phy_write(bcm, 0x0015, 0xE300); - bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0); - udelay(5); - bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); - udelay(2); - bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); - bcm43xx_voluntary_preempt(); - } else - bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); - bcm43xx_phy_lo_adjust(bcm, is_initializing); - bcm43xx_phy_write(bcm, 0x002E, 0x807F); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x002F, 0x0202); - else - bcm43xx_phy_write(bcm, 0x002F, 0x0101); - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]); - bcm43xx_phy_write(bcm, 0x0015, regstack[5]); - bcm43xx_phy_write(bcm, 0x002A, regstack[6]); - bcm43xx_phy_write(bcm, 0x0035, regstack[7]); - bcm43xx_phy_write(bcm, 0x0060, regstack[8]); - bcm43xx_radio_write16(bcm, 0x0043, regstack[9]); - bcm43xx_radio_write16(bcm, 0x007A, regstack[10]); - regstack[11] &= 0x00F0; - regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F); - bcm43xx_radio_write16(bcm, 0x52, regstack[11]); - bcm43xx_write16(bcm, 0x03E2, regstack[3]); - if (phy->connected) { - bcm43xx_phy_write(bcm, 0x0811, regstack[12]); - bcm43xx_phy_write(bcm, 0x0812, regstack[13]); - bcm43xx_phy_write(bcm, 0x0814, regstack[14]); - bcm43xx_phy_write(bcm, 0x0815, regstack[15]); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]); - bcm43xx_phy_write(bcm, 0x0802, regstack[1]); - } - bcm43xx_radio_selectchannel(bcm, oldchannel, 1); - -#ifdef CONFIG_BCM43XX_DEBUG - { - /* Sanity check for all lopairs. */ - for (i = 0; i < BCM43xx_LO_COUNT; i++) { - tmp_control = phy->_lo_pairs + i; - if (tmp_control->low < -8 || tmp_control->low > 8 || - tmp_control->high < -8 || tmp_control->high > 8) { - printk(KERN_WARNING PFX - "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n", - tmp_control->low, tmp_control->high, i); - } - } - } -#endif /* CONFIG_BCM43XX_DEBUG */ -} - -static -void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) -{ - struct bcm43xx_lopair *pair; - - pair = bcm43xx_current_lopair(bcm); - pair->used = 1; -} - -void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_lopair *pair; - int i; - - for (i = 0; i < BCM43xx_LO_COUNT; i++) { - pair = phy->_lo_pairs + i; - pair->used = 0; - } -} - -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut - * This function converts a TSSI value to dBm in Q5.2 - */ -static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - s8 dbm = 0; - s32 tmp; - - tmp = phy->idle_tssi; - tmp += tssi; - tmp -= phy->savedpctlreg; - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - tmp += 0x80; - tmp = limit_value(tmp, 0x00, 0xFF); - dbm = phy->tssi2dbm[tmp]; - TODO(); //TODO: There's a FIXME on the specs - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - tmp = limit_value(tmp, 0x00, 0x3F); - dbm = phy->tssi2dbm[tmp]; - break; - default: - assert(0); - } - - return dbm; -} - -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ -void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - if (phy->savedpctlreg == 0xFFFF) - return; - if ((bcm->board_type == 0x0416) && - (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)) - return; - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: { - - TODO(); //TODO: Nothing for A PHYs yet :-/ - - break; - } - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: { - u16 tmp; - u16 txpower; - s8 v0, v1, v2, v3; - s8 average; - u8 max_pwr; - s16 desired_pwr, estimated_pwr, pwr_adjust; - s16 radio_att_delta, baseband_att_delta; - s16 radio_attenuation, baseband_attenuation; - unsigned long phylock_flags; - - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058); - v0 = (s8)(tmp & 0x00FF); - v1 = (s8)((tmp & 0xFF00) >> 8); - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A); - v2 = (s8)(tmp & 0x00FF); - v3 = (s8)((tmp & 0xFF00) >> 8); - tmp = 0; - - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070); - v0 = (s8)(tmp & 0x00FF); - v1 = (s8)((tmp & 0xFF00) >> 8); - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072); - v2 = (s8)(tmp & 0x00FF); - v3 = (s8)((tmp & 0xFF00) >> 8); - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) - return; - v0 = (v0 + 0x20) & 0x3F; - v1 = (v1 + 0x20) & 0x3F; - v2 = (v2 + 0x20) & 0x3F; - v3 = (v3 + 0x20) & 0x3F; - tmp = 1; - } - bcm43xx_radio_clear_tssi(bcm); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8)) - average -= 13; - - estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average); - - max_pwr = bcm->sprom.maxpower_bgphy; - - if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) && - (phy->type == BCM43xx_PHYTYPE_G)) - max_pwr -= 0x3; - - /*TODO: - max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr); - /* Check if we need to adjust the current power. */ - pwr_adjust = desired_pwr - estimated_pwr; - radio_att_delta = -(pwr_adjust + 7) >> 3; - baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); - if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { - bcm43xx_phy_lo_mark_current_used(bcm); - return; - } - - /* Calculate the new attenuation values. */ - baseband_attenuation = radio->baseband_atten; - baseband_attenuation += baseband_att_delta; - radio_attenuation = radio->radio_atten; - radio_attenuation += radio_att_delta; - - /* Get baseband and radio attenuation values into their permitted ranges. - * baseband 0-11, radio 0-9. - * Radio attenuation affects power level 4 times as much as baseband. - */ - if (radio_attenuation < 0) { - baseband_attenuation -= (4 * -radio_attenuation); - radio_attenuation = 0; - } else if (radio_attenuation > 9) { - baseband_attenuation += (4 * (radio_attenuation - 9)); - radio_attenuation = 9; - } else { - while (baseband_attenuation < 0 && radio_attenuation > 0) { - baseband_attenuation += 4; - radio_attenuation--; - } - while (baseband_attenuation > 11 && radio_attenuation < 9) { - baseband_attenuation -= 4; - radio_attenuation++; - } - } - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - - txpower = radio->txctl1; - if ((radio->version == 0x2050) && (radio->revision == 2)) { - if (radio_attenuation <= 1) { - if (txpower == 0) { - txpower = 3; - radio_attenuation += 2; - baseband_attenuation += 2; - } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { - baseband_attenuation += 4 * (radio_attenuation - 2); - radio_attenuation = 2; - } - } else if (radio_attenuation > 4 && txpower != 0) { - txpower = 0; - if (baseband_attenuation < 3) { - radio_attenuation -= 3; - baseband_attenuation += 2; - } else { - radio_attenuation -= 2; - baseband_attenuation -= 2; - } - } - } - radio->txctl1 = txpower; - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - radio_attenuation = limit_value(radio_attenuation, 0, 9); - - bcm43xx_phy_lock(bcm, phylock_flags); - bcm43xx_radio_lock(bcm); - bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation, - radio_attenuation, txpower); - bcm43xx_phy_lo_mark_current_used(bcm); - bcm43xx_radio_unlock(bcm); - bcm43xx_phy_unlock(bcm, phylock_flags); - break; - } - default: - assert(0); - } -} - -static inline -s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den) -{ - if (num < 0) - return num/den; - else - return (num+den/2)/den; -} - -static inline -s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) -{ - s32 m1, m2, f = 256, q, delta; - s8 i = 0; - - m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32); - m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1); - do { - if (i > 15) - return -EINVAL; - q = bcm43xx_tssi2dbm_ad(f * 4096 - - bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048); - delta = abs(q - f); - f = q; - i++; - } while (delta >= 2); - entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128); - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ -int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - s16 pab0, pab1, pab2; - u8 idx; - s8 *dyn_tssi2dbm; - - if (phy->type == BCM43xx_PHYTYPE_A) { - pab0 = (s16)(bcm->sprom.pa1b0); - pab1 = (s16)(bcm->sprom.pa1b1); - pab2 = (s16)(bcm->sprom.pa1b2); - } else { - pab0 = (s16)(bcm->sprom.pa0b0); - pab1 = (s16)(bcm->sprom.pa0b1); - pab2 = (s16)(bcm->sprom.pa0b2); - } - - if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) { - phy->idle_tssi = 0x34; - phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; - return 0; - } - - if (pab0 != 0 && pab1 != 0 && pab2 != 0 && - pab0 != -1 && pab1 != -1 && pab2 != -1) { - /* The pabX values are set in SPROM. Use them. */ - if (phy->type == BCM43xx_PHYTYPE_A) { - if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 && - (s8)bcm->sprom.idle_tssi_tgt_aphy != -1) - phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy); - else - phy->idle_tssi = 62; - } else { - if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 && - (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1) - phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy); - else - phy->idle_tssi = 62; - } - dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); - if (dyn_tssi2dbm == NULL) { - printk(KERN_ERR PFX "Could not allocate memory " - "for tssi2dbm table\n"); - return -ENOMEM; - } - for (idx = 0; idx < 64; idx++) - if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) { - phy->tssi2dbm = NULL; - printk(KERN_ERR PFX "Could not generate " - "tssi2dBm table\n"); - kfree(dyn_tssi2dbm); - return -ENODEV; - } - phy->tssi2dbm = dyn_tssi2dbm; - phy->dyn_tssi_tbl = 1; - } else { - /* pabX values not set in SPROM. */ - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - /* APHY needs a generated table. */ - phy->tssi2dbm = NULL; - printk(KERN_ERR PFX "Could not generate tssi2dBm " - "table (wrong SPROM info)!\n"); - return -ENODEV; - case BCM43xx_PHYTYPE_B: - phy->idle_tssi = 0x34; - phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; - break; - case BCM43xx_PHYTYPE_G: - phy->idle_tssi = 0x34; - phy->tssi2dbm = bcm43xx_tssi2dbm_g_table; - break; - } - } - - return 0; -} - -int bcm43xx_phy_init(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - int err = -ENODEV; - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - if (phy->rev == 2 || phy->rev == 3) { - bcm43xx_phy_inita(bcm); - err = 0; - } - break; - case BCM43xx_PHYTYPE_B: - switch (phy->rev) { - case 2: - bcm43xx_phy_initb2(bcm); - err = 0; - break; - case 4: - bcm43xx_phy_initb4(bcm); - err = 0; - break; - case 5: - bcm43xx_phy_initb5(bcm); - err = 0; - break; - case 6: - bcm43xx_phy_initb6(bcm); - err = 0; - break; - } - break; - case BCM43xx_PHYTYPE_G: - bcm43xx_phy_initg(bcm); - err = 0; - break; - } - if (err) - printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); - - return err; -} - -void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 antennadiv; - u16 offset; - u16 value; - u32 ucodeflags; - - antennadiv = phy->antenna_diversity; - - if (antennadiv == 0xFFFF) - antennadiv = 3; - assert(antennadiv <= 3); - - ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET); - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV); - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - case BCM43xx_PHYTYPE_G: - if (phy->type == BCM43xx_PHYTYPE_A) - offset = 0x0000; - else - offset = 0x0400; - - if (antennadiv == 2) - value = (3/*automatic*/ << 7); - else - value = (antennadiv << 7); - bcm43xx_phy_write(bcm, offset + 1, - (bcm43xx_phy_read(bcm, offset + 1) - & 0x7E7F) | value); - - if (antennadiv >= 2) { - if (antennadiv == 2) - value = (antennadiv << 7); - else - value = (0/*force0*/ << 7); - bcm43xx_phy_write(bcm, offset + 0x2B, - (bcm43xx_phy_read(bcm, offset + 0x2B) - & 0xFEFF) | value); - } - - if (phy->type == BCM43xx_PHYTYPE_G) { - if (antennadiv >= 2) - bcm43xx_phy_write(bcm, 0x048C, - bcm43xx_phy_read(bcm, 0x048C) - | 0x2000); - else - bcm43xx_phy_write(bcm, 0x048C, - bcm43xx_phy_read(bcm, 0x048C) - & ~0x2000); - if (phy->rev >= 2) { - bcm43xx_phy_write(bcm, 0x0461, - bcm43xx_phy_read(bcm, 0x0461) - | 0x0010); - bcm43xx_phy_write(bcm, 0x04AD, - (bcm43xx_phy_read(bcm, 0x04AD) - & 0x00FF) | 0x0015); - if (phy->rev == 2) - bcm43xx_phy_write(bcm, 0x0427, 0x0008); - else - bcm43xx_phy_write(bcm, 0x0427, - (bcm43xx_phy_read(bcm, 0x0427) - & 0x00FF) | 0x0008); - } - else if (phy->rev >= 6) - bcm43xx_phy_write(bcm, 0x049B, 0x00DC); - } else { - if (phy->rev < 3) - bcm43xx_phy_write(bcm, 0x002B, - (bcm43xx_phy_read(bcm, 0x002B) - & 0x00FF) | 0x0024); - else { - bcm43xx_phy_write(bcm, 0x0061, - bcm43xx_phy_read(bcm, 0x0061) - | 0x0010); - if (phy->rev == 3) { - bcm43xx_phy_write(bcm, 0x0093, 0x001D); - bcm43xx_phy_write(bcm, 0x0027, 0x0008); - } else { - bcm43xx_phy_write(bcm, 0x0093, 0x003A); - bcm43xx_phy_write(bcm, 0x0027, - (bcm43xx_phy_read(bcm, 0x0027) - & 0x00FF) | 0x0008); - } - } - } - break; - case BCM43xx_PHYTYPE_B: - if (bcm->current_core->rev == 2) - value = (3/*automatic*/ << 7); - else - value = (antennadiv << 7); - bcm43xx_phy_write(bcm, 0x03E2, - (bcm43xx_phy_read(bcm, 0x03E2) - & 0xFE7F) | value); - break; - default: - assert(0); - } - - if (antennadiv >= 2) { - ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET); - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - ucodeflags | BCM43xx_UCODEFLAG_AUTODIV); - } - - phy->antenna_diversity = antennadiv; -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h deleted file mode 100644 index 73118364b55..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifndef BCM43xx_PHY_H_ -#define BCM43xx_PHY_H_ - -#include <linux/types.h> - -struct bcm43xx_private; - -void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm); -#define bcm43xx_phy_lock(bcm, flags) \ - do { \ - local_irq_save(flags); \ - bcm43xx_raw_phy_lock(bcm); \ - } while (0) -void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); -#define bcm43xx_phy_unlock(bcm, flags) \ - do { \ - bcm43xx_raw_phy_unlock(bcm); \ - local_irq_restore(flags); \ - } while (0) - -/* Card uses the loopback gain stuff */ -#define has_loopback_gain(phy) \ - (((phy)->rev > 1) || ((phy)->connected)) - -u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); -void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); - -int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm); -int bcm43xx_phy_init(struct bcm43xx_private *bcm); - -void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm); -void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm); -int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect); - -void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm); -void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm); -void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm); - -/* Adjust the LocalOscillator to the saved values. - * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. - */ -void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed); -void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm); - -void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, - u16 baseband_attenuation); - -#endif /* BCM43xx_PHY_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c deleted file mode 100644 index 76ab109cd2d..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - PIO Transmission - - Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx.h" -#include "bcm43xx_pio.h" -#include "bcm43xx_main.h" -#include "bcm43xx_xmit.h" -#include "bcm43xx_power.h" - -#include <linux/delay.h> - - -static void tx_start(struct bcm43xx_pioqueue *queue) -{ - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_INIT); -} - -static void tx_octet(struct bcm43xx_pioqueue *queue, - u8 octet) -{ - if (queue->need_workarounds) { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, - octet); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITELO); - } else { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITELO); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, - octet); - } -} - -static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, - const u8 *packet, - unsigned int *pos) -{ - const u8 *source; - unsigned int i = *pos; - u16 ret; - - if (i < sizeof(*txhdr)) { - source = (const u8 *)txhdr; - } else { - source = packet; - i -= sizeof(*txhdr); - } - ret = le16_to_cpu( *((__le16 *)(source + i)) ); - *pos += 2; - - return ret; -} - -static void tx_data(struct bcm43xx_pioqueue *queue, - struct bcm43xx_txhdr *txhdr, - const u8 *packet, - unsigned int octets) -{ - u16 data; - unsigned int i = 0; - - if (queue->need_workarounds) { - data = tx_get_next_word(txhdr, packet, &i); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); - } - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITELO | - BCM43xx_PIO_TXCTL_WRITEHI); - while (i < octets - 1) { - data = tx_get_next_word(txhdr, packet, &i); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); - } - if (octets % 2) - tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]); -} - -static void tx_complete(struct bcm43xx_pioqueue *queue, - struct sk_buff *skb) -{ - if (queue->need_workarounds) { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, - skb->data[skb->len - 1]); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITELO | - BCM43xx_PIO_TXCTL_COMPLETE); - } else { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_COMPLETE); - } -} - -static u16 generate_cookie(struct bcm43xx_pioqueue *queue, - struct bcm43xx_pio_txpacket *packet) -{ - u16 cookie = 0x0000; - int packetindex; - - /* We use the upper 4 bits for the PIO - * controller ID and the lower 12 bits - * for the packet index (in the cache). - */ - switch (queue->mmio_base) { - case BCM43xx_MMIO_PIO1_BASE: - break; - case BCM43xx_MMIO_PIO2_BASE: - cookie = 0x1000; - break; - case BCM43xx_MMIO_PIO3_BASE: - cookie = 0x2000; - break; - case BCM43xx_MMIO_PIO4_BASE: - cookie = 0x3000; - break; - default: - assert(0); - } - packetindex = pio_txpacket_getindex(packet); - assert(((u16)packetindex & 0xF000) == 0x0000); - cookie |= (u16)packetindex; - - return cookie; -} - -static -struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, - u16 cookie, - struct bcm43xx_pio_txpacket **packet) -{ - struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); - struct bcm43xx_pioqueue *queue = NULL; - int packetindex; - - switch (cookie & 0xF000) { - case 0x0000: - queue = pio->queue0; - break; - case 0x1000: - queue = pio->queue1; - break; - case 0x2000: - queue = pio->queue2; - break; - case 0x3000: - queue = pio->queue3; - break; - default: - assert(0); - } - packetindex = (cookie & 0x0FFF); - assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); - *packet = &(queue->tx_packets_cache[packetindex]); - - return queue; -} - -static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, - struct sk_buff *skb, - struct bcm43xx_pio_txpacket *packet) -{ - struct bcm43xx_txhdr txhdr; - unsigned int octets; - - assert(skb_shinfo(skb)->nr_frags == 0); - bcm43xx_generate_txhdr(queue->bcm, - &txhdr, skb->data, skb->len, - (packet->xmitted_frags == 0), - generate_cookie(queue, packet)); - - tx_start(queue); - octets = skb->len + sizeof(txhdr); - if (queue->need_workarounds) - octets--; - tx_data(queue, &txhdr, (u8 *)skb->data, octets); - tx_complete(queue, skb); -} - -static void free_txpacket(struct bcm43xx_pio_txpacket *packet, - int irq_context) -{ - struct bcm43xx_pioqueue *queue = packet->queue; - - ieee80211_txb_free(packet->txb); - list_move(&packet->list, &queue->txfree); - queue->nr_txfree++; - - assert(queue->tx_devq_used >= packet->xmitted_octets); - assert(queue->tx_devq_packets >= packet->xmitted_frags); - queue->tx_devq_used -= packet->xmitted_octets; - queue->tx_devq_packets -= packet->xmitted_frags; -} - -static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) -{ - struct bcm43xx_pioqueue *queue = packet->queue; - struct ieee80211_txb *txb = packet->txb; - struct sk_buff *skb; - u16 octets; - int i; - - for (i = packet->xmitted_frags; i < txb->nr_frags; i++) { - skb = txb->fragments[i]; - - octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); - assert(queue->tx_devq_size >= octets); - assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); - assert(queue->tx_devq_used <= queue->tx_devq_size); - /* Check if there is sufficient free space on the device - * TX queue. If not, return and let the TX tasklet - * retry later. - */ - if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) - return -EBUSY; - if (queue->tx_devq_used + octets > queue->tx_devq_size) - return -EBUSY; - /* Now poke the device. */ - pio_tx_write_fragment(queue, skb, packet); - - /* Account for the packet size. - * (We must not overflow the device TX queue) - */ - queue->tx_devq_packets++; - queue->tx_devq_used += octets; - - assert(packet->xmitted_frags < packet->txb->nr_frags); - packet->xmitted_frags++; - packet->xmitted_octets += octets; - } - list_move_tail(&packet->list, &queue->txrunning); - - return 0; -} - -static void tx_tasklet(unsigned long d) -{ - struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d; - struct bcm43xx_private *bcm = queue->bcm; - unsigned long flags; - struct bcm43xx_pio_txpacket *packet, *tmp_packet; - int err; - u16 txctl; - - spin_lock_irqsave(&bcm->irq_lock, flags); - - if (queue->tx_frozen) - goto out_unlock; - txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); - if (txctl & BCM43xx_PIO_TXCTL_SUSPEND) - goto out_unlock; - - list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { - assert(packet->xmitted_frags < packet->txb->nr_frags); - if (packet->xmitted_frags == 0) { - int i; - struct sk_buff *skb; - - /* Check if the device queue is big - * enough for every fragment. If not, drop the - * whole packet. - */ - for (i = 0; i < packet->txb->nr_frags; i++) { - skb = packet->txb->fragments[i]; - if (unlikely(skb->len > queue->tx_devq_size)) { - dprintkl(KERN_ERR PFX "PIO TX device queue too small. " - "Dropping packet.\n"); - free_txpacket(packet, 1); - goto next_packet; - } - } - } - /* Try to transmit the packet. - * This may not completely succeed. - */ - err = pio_tx_packet(packet); - if (err) - break; - next_packet: - continue; - } -out_unlock: - spin_unlock_irqrestore(&bcm->irq_lock, flags); -} - -static void setup_txqueues(struct bcm43xx_pioqueue *queue) -{ - struct bcm43xx_pio_txpacket *packet; - int i; - - queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS; - for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { - packet = &(queue->tx_packets_cache[i]); - - packet->queue = queue; - INIT_LIST_HEAD(&packet->list); - - list_add(&packet->list, &queue->txfree); - } -} - -static -struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, - u16 pio_mmio_base) -{ - struct bcm43xx_pioqueue *queue; - u32 value; - u16 qsize; - - queue = kzalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) - goto out; - - queue->bcm = bcm; - queue->mmio_base = pio_mmio_base; - queue->need_workarounds = (bcm->current_core->rev < 3); - - INIT_LIST_HEAD(&queue->txfree); - INIT_LIST_HEAD(&queue->txqueue); - INIT_LIST_HEAD(&queue->txrunning); - tasklet_init(&queue->txtask, tx_tasklet, - (unsigned long)queue); - - value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value &= ~BCM43xx_SBF_XFER_REG_BYTESWAP; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); - - qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); - if (qsize == 0) { - printk(KERN_ERR PFX "ERROR: This card does not support PIO " - "operation mode. Please use DMA mode " - "(module parameter pio=0).\n"); - goto err_freequeue; - } - if (qsize <= BCM43xx_PIO_TXQADJUST) { - printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", - qsize); - goto err_freequeue; - } - qsize -= BCM43xx_PIO_TXQADJUST; - queue->tx_devq_size = qsize; - - setup_txqueues(queue); - -out: - return queue; - -err_freequeue: - kfree(queue); - queue = NULL; - goto out; -} - -static void cancel_transfers(struct bcm43xx_pioqueue *queue) -{ - struct bcm43xx_pio_txpacket *packet, *tmp_packet; - - netif_tx_disable(queue->bcm->net_dev); - tasklet_disable(&queue->txtask); - - list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) - free_txpacket(packet, 0); - list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) - free_txpacket(packet, 0); -} - -static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) -{ - if (!queue) - return; - - cancel_transfers(queue); - kfree(queue); -} - -void bcm43xx_pio_free(struct bcm43xx_private *bcm) -{ - struct bcm43xx_pio *pio; - - if (!bcm43xx_using_pio(bcm)) - return; - pio = bcm43xx_current_pio(bcm); - - bcm43xx_destroy_pioqueue(pio->queue3); - pio->queue3 = NULL; - bcm43xx_destroy_pioqueue(pio->queue2); - pio->queue2 = NULL; - bcm43xx_destroy_pioqueue(pio->queue1); - pio->queue1 = NULL; - bcm43xx_destroy_pioqueue(pio->queue0); - pio->queue0 = NULL; -} - -int bcm43xx_pio_init(struct bcm43xx_private *bcm) -{ - struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); - struct bcm43xx_pioqueue *queue; - int err = -ENOMEM; - - queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); - if (!queue) - goto out; - pio->queue0 = queue; - - queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); - if (!queue) - goto err_destroy0; - pio->queue1 = queue; - - queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); - if (!queue) - goto err_destroy1; - pio->queue2 = queue; - - queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); - if (!queue) - goto err_destroy2; - pio->queue3 = queue; - - if (bcm->current_core->rev < 3) - bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; - - dprintk(KERN_INFO PFX "PIO initialized\n"); - err = 0; -out: - return err; - -err_destroy2: - bcm43xx_destroy_pioqueue(pio->queue2); - pio->queue2 = NULL; -err_destroy1: - bcm43xx_destroy_pioqueue(pio->queue1); - pio->queue1 = NULL; -err_destroy0: - bcm43xx_destroy_pioqueue(pio->queue0); - pio->queue0 = NULL; - goto out; -} - -int bcm43xx_pio_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1; - struct bcm43xx_pio_txpacket *packet; - - assert(!queue->tx_suspended); - assert(!list_empty(&queue->txfree)); - - packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); - packet->txb = txb; - packet->xmitted_frags = 0; - packet->xmitted_octets = 0; - list_move_tail(&packet->list, &queue->txqueue); - queue->nr_txfree--; - assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); - - /* Suspend TX, if we are out of packets in the "free" queue. */ - if (list_empty(&queue->txfree)) { - netif_stop_queue(queue->bcm->net_dev); - queue->tx_suspended = 1; - } - - tasklet_schedule(&queue->txtask); - - return 0; -} - -void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) -{ - struct bcm43xx_pioqueue *queue; - struct bcm43xx_pio_txpacket *packet; - - queue = parse_cookie(bcm, status->cookie, &packet); - assert(queue); - - free_txpacket(packet, 1); - if (queue->tx_suspended) { - queue->tx_suspended = 0; - netif_wake_queue(queue->bcm->net_dev); - } - /* If there are packets on the txqueue, poke the tasklet - * to transmit them. - */ - if (!list_empty(&queue->txqueue)) - tasklet_schedule(&queue->txtask); -} - -static void pio_rx_error(struct bcm43xx_pioqueue *queue, - int clear_buffers, - const char *error) -{ - int i; - - printkl("PIO RX error: %s\n", error); - bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, - BCM43xx_PIO_RXCTL_READY); - if (clear_buffers) { - assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); - for (i = 0; i < 15; i++) { - /* Dummy read. */ - bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - } - } -} - -void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) -{ - __le16 preamble[21] = { 0 }; - struct bcm43xx_rxhdr *rxhdr; - u16 tmp, len, rxflags2; - int i, preamble_readwords; - struct sk_buff *skb; - - tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); - if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) - return; - bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, - BCM43xx_PIO_RXCTL_DATAAVAILABLE); - - for (i = 0; i < 10; i++) { - tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); - if (tmp & BCM43xx_PIO_RXCTL_READY) - goto data_ready; - udelay(10); - } - dprintkl(KERN_ERR PFX "PIO RX timed out\n"); - return; -data_ready: - - len = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - if (unlikely(len > 0x700)) { - pio_rx_error(queue, 0, "len > 0x700"); - return; - } - if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { - pio_rx_error(queue, 0, "len == 0"); - return; - } - preamble[0] = cpu_to_le16(len); - if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) - preamble_readwords = 14 / sizeof(u16); - else - preamble_readwords = 18 / sizeof(u16); - for (i = 0; i < preamble_readwords; i++) { - tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - preamble[i + 1] = cpu_to_le16(tmp); - } - rxhdr = (struct bcm43xx_rxhdr *)preamble; - rxflags2 = le16_to_cpu(rxhdr->flags2); - if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { - pio_rx_error(queue, - (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), - "invalid frame"); - return; - } - if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { - /* We received an xmit status. */ - struct bcm43xx_hwxmitstatus *hw; - struct bcm43xx_xmitstatus stat; - - hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); - stat.cookie = le16_to_cpu(hw->cookie); - stat.flags = hw->flags; - stat.cnt1 = hw->cnt1; - stat.cnt2 = hw->cnt2; - stat.seq = le16_to_cpu(hw->seq); - stat.unknown = le16_to_cpu(hw->unknown); - - bcm43xx_debugfs_log_txstat(queue->bcm, &stat); - bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); - - return; - } - - skb = dev_alloc_skb(len); - if (unlikely(!skb)) { - pio_rx_error(queue, 1, "OOM"); - return; - } - skb_put(skb, len); - for (i = 0; i < len - 1; i += 2) { - tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); - } - if (len % 2) { - tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - skb->data[len - 1] = (tmp & 0x00FF); -/* The specs say the following is required, but - * it is wrong and corrupts the PLCP. If we don't do - * this, the PLCP seems to be correct. So ifdef it out for now. - */ -#if 0 - if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) - skb->data[2] = (tmp & 0xFF00) >> 8; - else - skb->data[0] = (tmp & 0xFF00) >> 8; -#endif - } - skb_trim(skb, len - IEEE80211_FCS_LEN); - bcm43xx_rx(queue->bcm, skb, rxhdr); -} - -void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue) -{ - bcm43xx_power_saving_ctl_bits(queue->bcm, -1, 1); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) - | BCM43xx_PIO_TXCTL_SUSPEND); -} - -void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) -{ - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) - & ~BCM43xx_PIO_TXCTL_SUSPEND); - bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1); - if (!list_empty(&queue->txqueue)) - tasklet_schedule(&queue->txtask); -} - -void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm) -{ - struct bcm43xx_pio *pio; - - assert(bcm43xx_using_pio(bcm)); - pio = bcm43xx_current_pio(bcm); - pio->queue0->tx_frozen = 1; - pio->queue1->tx_frozen = 1; - pio->queue2->tx_frozen = 1; - pio->queue3->tx_frozen = 1; -} - -void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm) -{ - struct bcm43xx_pio *pio; - - assert(bcm43xx_using_pio(bcm)); - pio = bcm43xx_current_pio(bcm); - pio->queue0->tx_frozen = 0; - pio->queue1->tx_frozen = 0; - pio->queue2->tx_frozen = 0; - pio->queue3->tx_frozen = 0; - if (!list_empty(&pio->queue0->txqueue)) - tasklet_schedule(&pio->queue0->txtask); - if (!list_empty(&pio->queue1->txqueue)) - tasklet_schedule(&pio->queue1->txtask); - if (!list_empty(&pio->queue2->txqueue)) - tasklet_schedule(&pio->queue2->txtask); - if (!list_empty(&pio->queue3->txqueue)) - tasklet_schedule(&pio->queue3->txtask); -} - - diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h deleted file mode 100644 index bc78a3c2caf..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h +++ /dev/null @@ -1,163 +0,0 @@ -#ifndef BCM43xx_PIO_H_ -#define BCM43xx_PIO_H_ - -#include "bcm43xx.h" - -#include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/skbuff.h> - - -#define BCM43xx_PIO_TXCTL 0x00 -#define BCM43xx_PIO_TXDATA 0x02 -#define BCM43xx_PIO_TXQBUFSIZE 0x04 -#define BCM43xx_PIO_RXCTL 0x08 -#define BCM43xx_PIO_RXDATA 0x0A - -#define BCM43xx_PIO_TXCTL_WRITELO (1 << 0) -#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 1) -#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2) -#define BCM43xx_PIO_TXCTL_INIT (1 << 3) -#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7) - -#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0) -#define BCM43xx_PIO_RXCTL_READY (1 << 1) - -/* PIO constants */ -#define BCM43xx_PIO_MAXTXDEVQPACKETS 31 -#define BCM43xx_PIO_TXQADJUST 80 - -/* PIO tuning knobs */ -#define BCM43xx_PIO_MAXTXPACKETS 256 - - - -#ifdef CONFIG_BCM43XX_PIO - - -struct bcm43xx_pioqueue; -struct bcm43xx_xmitstatus; - -struct bcm43xx_pio_txpacket { - struct bcm43xx_pioqueue *queue; - struct ieee80211_txb *txb; - struct list_head list; - - u8 xmitted_frags; - u16 xmitted_octets; -}; - -#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) - -struct bcm43xx_pioqueue { - struct bcm43xx_private *bcm; - u16 mmio_base; - - u8 tx_suspended:1, - tx_frozen:1, - need_workarounds:1; /* Workarounds needed for core.rev < 3 */ - - /* Adjusted size of the device internal TX buffer. */ - u16 tx_devq_size; - /* Used octets of the device internal TX buffer. */ - u16 tx_devq_used; - /* Used packet slots in the device internal TX buffer. */ - u8 tx_devq_packets; - /* Packets from the txfree list can - * be taken on incoming TX requests. - */ - struct list_head txfree; - unsigned int nr_txfree; - /* Packets on the txqueue are queued, - * but not completely written to the chip, yet. - */ - struct list_head txqueue; - /* Packets on the txrunning queue are completely - * posted to the device. We are waiting for the txstatus. - */ - struct list_head txrunning; - /* Total number or packets sent. - * (This counter can obviously wrap). - */ - unsigned int nr_tx_packets; - struct tasklet_struct txtask; - struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; -}; - -static inline -u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, - u16 offset) -{ - return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); -} - -static inline -void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, - u16 offset, u16 value) -{ - bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); - mmiowb(); -} - - -int bcm43xx_pio_init(struct bcm43xx_private *bcm); -void bcm43xx_pio_free(struct bcm43xx_private *bcm); - -int bcm43xx_pio_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb); -void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status); -void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); - -/* Suspend a TX queue on hardware level. */ -void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue); -void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue); -/* Suspend (freeze) the TX tasklet (software level). */ -void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm); -void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm); - -#else /* CONFIG_BCM43XX_PIO */ - -static inline -int bcm43xx_pio_init(struct bcm43xx_private *bcm) -{ - return 0; -} -static inline -void bcm43xx_pio_free(struct bcm43xx_private *bcm) -{ -} -static inline -int bcm43xx_pio_tx(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - return 0; -} -static inline -void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) -{ -} -static inline -void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) -{ -} -static inline -void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue) -{ -} -static inline -void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) -{ -} -static inline -void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm) -{ -} -static inline -void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm) -{ -} - -#endif /* CONFIG_BCM43XX_PIO */ -#endif /* BCM43xx_PIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c deleted file mode 100644 index 7e774f41095..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include <linux/delay.h> - -#include "bcm43xx.h" -#include "bcm43xx_power.h" -#include "bcm43xx_main.h" - - -/* Get the Slow Clock Source */ -static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm) -{ - u32 tmp; - int err; - - assert(bcm->current_core == &bcm->core_chipcommon); - if (bcm->current_core->rev < 6) { - if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA || - bcm->bustype == BCM43xx_BUSTYPE_SB) - return BCM43xx_PCTL_CLKSRC_XTALOS; - if (bcm->bustype == BCM43xx_BUSTYPE_PCI) { - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); - assert(!err); - if (tmp & 0x10) - return BCM43xx_PCTL_CLKSRC_PCI; - return BCM43xx_PCTL_CLKSRC_XTALOS; - } - } - if (bcm->current_core->rev < 10) { - tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); - tmp &= 0x7; - if (tmp == 0) - return BCM43xx_PCTL_CLKSRC_LOPWROS; - if (tmp == 1) - return BCM43xx_PCTL_CLKSRC_XTALOS; - if (tmp == 2) - return BCM43xx_PCTL_CLKSRC_PCI; - } - - return BCM43xx_PCTL_CLKSRC_XTALOS; -} - -/* Get max/min slowclock frequency - * as described in http://bcm-specs.sipsolutions.net/PowerControl - */ -static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, - int get_max) -{ - int limit; - int clocksrc; - int divisor; - u32 tmp; - - assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL); - assert(bcm->current_core == &bcm->core_chipcommon); - - clocksrc = bcm43xx_pctl_get_slowclksrc(bcm); - if (bcm->current_core->rev < 6) { - switch (clocksrc) { - case BCM43xx_PCTL_CLKSRC_PCI: - divisor = 64; - break; - case BCM43xx_PCTL_CLKSRC_XTALOS: - divisor = 32; - break; - default: - assert(0); - divisor = 1; - } - } else if (bcm->current_core->rev < 10) { - switch (clocksrc) { - case BCM43xx_PCTL_CLKSRC_LOPWROS: - divisor = 1; - break; - case BCM43xx_PCTL_CLKSRC_XTALOS: - case BCM43xx_PCTL_CLKSRC_PCI: - tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); - divisor = ((tmp & 0xFFFF0000) >> 16) + 1; - divisor *= 4; - break; - default: - assert(0); - divisor = 1; - } - } else { - tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); - divisor = ((tmp & 0xFFFF0000) >> 16) + 1; - divisor *= 4; - } - - switch (clocksrc) { - case BCM43xx_PCTL_CLKSRC_LOPWROS: - if (get_max) - limit = 43000; - else - limit = 25000; - break; - case BCM43xx_PCTL_CLKSRC_XTALOS: - if (get_max) - limit = 20200000; - else - limit = 19800000; - break; - case BCM43xx_PCTL_CLKSRC_PCI: - if (get_max) - limit = 34000000; - else - limit = 25000000; - break; - default: - assert(0); - limit = 0; - } - limit /= divisor; - - return limit; -} - - -/* init power control - * as described in http://bcm-specs.sipsolutions.net/PowerControl - */ -int bcm43xx_pctl_init(struct bcm43xx_private *bcm) -{ - int err, maxfreq; - struct bcm43xx_coreinfo *old_core; - - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - if (err == -ENODEV) - return 0; - if (err) - goto out; - - if (bcm->chip_id == 0x4321) { - if (bcm->chip_rev == 0) - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x03A4); - if (bcm->chip_rev == 1) - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x00A4); - } - - if (bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) { - if (bcm->current_core->rev >= 10) { - /* Set Idle Power clock rate to 1Mhz */ - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL, - (bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL) - & 0x0000FFFF) | 0x40000); - } else { - maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1); - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, - (maxfreq * 150 + 999999) / 1000000); - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, - (maxfreq * 15 + 999999) / 1000000); - } - } - - err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - -out: - return err; -} - -u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm) -{ - u16 delay = 0; - int err; - u32 pll_on_delay; - struct bcm43xx_coreinfo *old_core; - int minfreq; - - if (bcm->bustype != BCM43xx_BUSTYPE_PCI) - goto out; - if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) - goto out; - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - if (err == -ENODEV) - goto out; - - minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0); - pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY); - delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; - - err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - -out: - return delay; -} - -/* set the powercontrol clock - * as described in http://bcm-specs.sipsolutions.net/PowerControl - */ -int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode) -{ - int err; - struct bcm43xx_coreinfo *old_core; - u32 tmp; - - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - if (err == -ENODEV) - return 0; - if (err) - goto out; - - if (bcm->core_chipcommon.rev < 6) { - if (mode == BCM43xx_PCTL_CLK_FAST) { - err = bcm43xx_pctl_set_crystal(bcm, 1); - if (err) - goto out; - } - } else { - if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) && - (bcm->core_chipcommon.rev < 10)) { - switch (mode) { - case BCM43xx_PCTL_CLK_FAST: - tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); - tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL; - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); - break; - case BCM43xx_PCTL_CLK_SLOW: - tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); - tmp |= BCM43xx_PCTL_FORCE_SLOW; - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); - break; - case BCM43xx_PCTL_CLK_DYNAMIC: - tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); - tmp &= ~BCM43xx_PCTL_FORCE_SLOW; - tmp |= BCM43xx_PCTL_FORCE_PLL; - tmp &= ~BCM43xx_PCTL_DYN_XTAL; - bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); - } - } - } - - err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - -out: - return err; -} - -int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on) -{ - int err; - u32 in, out, outenable; - - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in); - if (err) - goto err_pci; - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out); - if (err) - goto err_pci; - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable); - if (err) - goto err_pci; - - outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); - - if (on) { - if (in & 0x40) - return 0; - - out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); - - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); - if (err) - goto err_pci; - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); - if (err) - goto err_pci; - udelay(1000); - - out &= ~BCM43xx_PCTL_PLL_POWERDOWN; - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); - if (err) - goto err_pci; - udelay(5000); - } else { - if (bcm->current_core->rev < 5) - return 0; - if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW) - return 0; - -/* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time? - * err = bcm43xx_switch_core(bcm, bcm->active_80211_core); - * if (err) - * return err; - * if (((bcm->current_core->rev >= 3) && - * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) || - * ((bcm->current_core->rev < 3) && - * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4)))) - * return 0; - * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - * if (err) - * return err; - */ - - err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); - if (err) - goto out; - out &= ~BCM43xx_PCTL_XTAL_POWERUP; - out |= BCM43xx_PCTL_PLL_POWERDOWN; - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); - if (err) - goto err_pci; - err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); - if (err) - goto err_pci; - } - -out: - return err; - -err_pci: - printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n"); - err = -EBUSY; - goto out; -} - -/* Set the PowerSavingControlBits. - * Bitvalues: - * 0 => unset the bit - * 1 => set the bit - * -1 => calculate the bit - */ -void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, - int bit25, int bit26) -{ - int i; - u32 status; - -//FIXME: Force 25 to off and 26 to on for now: -bit25 = 0; -bit26 = 1; - - if (bit25 == -1) { - //TODO: If powersave is not off and FIXME is not set and we are not in adhoc - // and thus is not an AP and we are associated, set bit 25 - } - if (bit26 == -1) { - //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, - // or we are associated, or FIXME, or the latest PS-Poll packet sent was - // successful, set bit26 - } - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - if (bit25) - status |= BCM43xx_SBF_PS1; - else - status &= ~BCM43xx_SBF_PS1; - if (bit26) - status |= BCM43xx_SBF_PS2; - else - status &= ~BCM43xx_SBF_PS2; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - if (bit26 && bcm->current_core->rev >= 5) { - for (i = 0; i < 100; i++) { - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4) - break; - udelay(10); - } - } -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h deleted file mode 100644 index c966ab3a5a8..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifndef BCM43xx_POWER_H_ -#define BCM43xx_POWER_H_ - -#include <linux/types.h> - -/* Clock sources */ -enum { - /* PCI clock */ - BCM43xx_PCTL_CLKSRC_PCI, - /* Crystal slow clock oscillator */ - BCM43xx_PCTL_CLKSRC_XTALOS, - /* Low power oscillator */ - BCM43xx_PCTL_CLKSRC_LOPWROS, -}; - -struct bcm43xx_private; - -int bcm43xx_pctl_init(struct bcm43xx_private *bcm); -int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode); -int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on); -u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm); - -void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, - int bit25, int bit26); - -#endif /* BCM43xx_POWER_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c deleted file mode 100644 index c605099c9ba..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ /dev/null @@ -1,2170 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include <linux/delay.h> - -#include "bcm43xx.h" -#include "bcm43xx_main.h" -#include "bcm43xx_phy.h" -#include "bcm43xx_radio.h" -#include "bcm43xx_ilt.h" - - -/* Table for bcm43xx_radio_calibrationvalue() */ -static const u16 rcc_table[16] = { - 0x0002, 0x0003, 0x0001, 0x000F, - 0x0006, 0x0007, 0x0005, 0x000F, - 0x000A, 0x000B, 0x0009, 0x000F, - 0x000E, 0x000F, 0x000D, 0x000F, -}; - -/* Reverse the bits of a 4bit value. - * Example: 1101 is flipped 1011 - */ -static u16 flip_4bit(u16 value) -{ - u16 flipped = 0x0000; - - assert((value & ~0x000F) == 0x0000); - - flipped |= (value & 0x0001) << 3; - flipped |= (value & 0x0002) << 1; - flipped |= (value & 0x0004) >> 1; - flipped |= (value & 0x0008) >> 3; - - return flipped; -} - -/* Get the freq, as it has to be written to the device. */ -static inline -u16 channel2freq_bg(u8 channel) -{ - /* Frequencies are given as frequencies_bg[index] + 2.4GHz - * Starting with channel 1 - */ - static const u16 frequencies_bg[14] = { - 12, 17, 22, 27, - 32, 37, 42, 47, - 52, 57, 62, 67, - 72, 84, - }; - - assert(channel >= 1 && channel <= 14); - - return frequencies_bg[channel - 1]; -} - -/* Get the freq, as it has to be written to the device. */ -static inline -u16 channel2freq_a(u8 channel) -{ - assert(channel <= 200); - - return (5000 + 5 * channel); -} - -void bcm43xx_radio_lock(struct bcm43xx_private *bcm) -{ - u32 status; - - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - status |= BCM43xx_SBF_RADIOREG_LOCK; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - mmiowb(); - udelay(10); -} - -void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) -{ - u32 status; - - bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */ - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - status &= ~BCM43xx_SBF_RADIOREG_LOCK; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - mmiowb(); -} - -u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - offset |= 0x0040; - break; - case BCM43xx_PHYTYPE_B: - if (radio->version == 0x2053) { - if (offset < 0x70) - offset += 0x80; - else if (offset < 0x80) - offset += 0x70; - } else if (radio->version == 0x2050) { - offset |= 0x80; - } else - assert(0); - break; - case BCM43xx_PHYTYPE_G: - offset |= 0x80; - break; - } - - bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); - return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); -} - -void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) -{ - bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); - mmiowb(); - bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); -} - -static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, - s16 first, s16 second, s16 third) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 i; - u16 start = 0x08, end = 0x18; - u16 offset = 0x0400; - u16 tmp; - - if (phy->rev <= 1) { - offset = 0x5000; - start = 0x10; - end = 0x20; - } - - for (i = 0; i < 4; i++) - bcm43xx_ilt_write(bcm, offset + i, first); - - for (i = start; i < end; i++) - bcm43xx_ilt_write(bcm, offset + i, second); - - if (third != -1) { - tmp = ((u16)third << 14) | ((u16)third << 6); - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp); - bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp); - } - bcm43xx_dummy_transmission(bcm); -} - -static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 i, tmp; - u16 offset = 0x0400; - u16 start = 0x0008, end = 0x0018; - - if (phy->rev <= 1) { - offset = 0x5000; - start = 0x0010; - end = 0x0020; - } - - for (i = 0; i < 4; i++) { - tmp = (i & 0xFFFC); - tmp |= (i & 0x0001) << 1; - tmp |= (i & 0x0002) >> 1; - - bcm43xx_ilt_write(bcm, offset + i, tmp); - } - - for (i = start; i < end; i++) - bcm43xx_ilt_write(bcm, offset + i, i - start); - - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); - bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000); - bcm43xx_dummy_transmission(bcm); -} - -/* Synthetic PU workaround */ -static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - - if (radio->version != 0x2050 || radio->revision >= 6) { - /* We do not need the workaround. */ - return; - } - - if (channel <= 10) { - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, - channel2freq_bg(channel + 4)); - } else { - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, - channel2freq_bg(1)); - } - udelay(100); - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, - channel2freq_bg(channel)); -} - -u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u8 ret = 0; - u16 saved, rssi, temp; - int i, j = 0; - - saved = bcm43xx_phy_read(bcm, 0x0403); - bcm43xx_radio_selectchannel(bcm, channel, 0); - bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5); - if (radio->aci_hw_rssi) - rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F; - else - rssi = saved & 0x3F; - /* clamp temp to signed 5bit */ - if (rssi > 32) - rssi -= 64; - for (i = 0;i < 100; i++) { - temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F; - if (temp > 32) - temp -= 64; - if (temp < rssi) - j++; - if (j >= 20) - ret = 1; - } - bcm43xx_phy_write(bcm, 0x0403, saved); - - return ret; -} - -u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u8 ret[13]; - unsigned int channel = radio->channel; - unsigned int i, j, start, end; - unsigned long phylock_flags; - - if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0))) - return 0; - - bcm43xx_phy_lock(bcm, phylock_flags); - bcm43xx_radio_lock(bcm); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); - bcm43xx_set_all_gains(bcm, 3, 8, 1); - - start = (channel - 5 > 0) ? channel - 5 : 1; - end = (channel + 5 < 14) ? channel + 5 : 13; - - for (i = start; i <= end; i++) { - if (abs(channel - i) > 2) - ret[i-1] = bcm43xx_radio_aci_detect(bcm, i); - } - bcm43xx_radio_selectchannel(bcm, channel, 0); - bcm43xx_phy_write(bcm, 0x0802, - (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003); - bcm43xx_phy_write(bcm, 0x0403, - bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); - bcm43xx_set_original_gains(bcm); - for (i = 0; i < 13; i++) { - if (!ret[i]) - continue; - end = (i + 5 < 13) ? i + 5 : 13; - for (j = i; j < end; j++) - ret[j] = 1; - } - bcm43xx_radio_unlock(bcm); - bcm43xx_phy_unlock(bcm, phylock_flags); - - return ret[channel - 1]; -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) -{ - bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); - mmiowb(); - bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset) -{ - u16 val; - - bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); - val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA); - - return (s16)val; -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) -{ - u16 i; - s16 tmp; - - for (i = 0; i < 64; i++) { - tmp = bcm43xx_nrssi_hw_read(bcm, i); - tmp -= val; - tmp = limit_value(tmp, -32, 31); - bcm43xx_nrssi_hw_write(bcm, i, tmp); - } -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - s16 i, delta; - s32 tmp; - - delta = 0x1F - radio->nrssi[0]; - for (i = 0; i < 64; i++) { - tmp = (i - delta) * radio->nrssislope; - tmp /= 0x10000; - tmp += 0x3A; - tmp = limit_value(tmp, 0, 0x3F); - radio->nrssi_lt[i] = tmp; - } -} - -static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - u16 backup[20] = { 0 }; - s16 v47F; - u16 i; - u16 saved = 0xFFFF; - - backup[0] = bcm43xx_phy_read(bcm, 0x0001); - backup[1] = bcm43xx_phy_read(bcm, 0x0811); - backup[2] = bcm43xx_phy_read(bcm, 0x0812); - backup[3] = bcm43xx_phy_read(bcm, 0x0814); - backup[4] = bcm43xx_phy_read(bcm, 0x0815); - backup[5] = bcm43xx_phy_read(bcm, 0x005A); - backup[6] = bcm43xx_phy_read(bcm, 0x0059); - backup[7] = bcm43xx_phy_read(bcm, 0x0058); - backup[8] = bcm43xx_phy_read(bcm, 0x000A); - backup[9] = bcm43xx_phy_read(bcm, 0x0003); - backup[10] = bcm43xx_radio_read16(bcm, 0x007A); - backup[11] = bcm43xx_radio_read16(bcm, 0x0043); - - bcm43xx_phy_write(bcm, 0x0429, - bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF); - bcm43xx_phy_write(bcm, 0x0001, - (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x000C); - bcm43xx_phy_write(bcm, 0x0812, - (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2)); - if (phy->rev >= 6) { - backup[12] = bcm43xx_phy_read(bcm, 0x002E); - backup[13] = bcm43xx_phy_read(bcm, 0x002F); - backup[14] = bcm43xx_phy_read(bcm, 0x080F); - backup[15] = bcm43xx_phy_read(bcm, 0x0810); - backup[16] = bcm43xx_phy_read(bcm, 0x0801); - backup[17] = bcm43xx_phy_read(bcm, 0x0060); - backup[18] = bcm43xx_phy_read(bcm, 0x0014); - backup[19] = bcm43xx_phy_read(bcm, 0x0478); - - bcm43xx_phy_write(bcm, 0x002E, 0); - bcm43xx_phy_write(bcm, 0x002F, 0); - bcm43xx_phy_write(bcm, 0x080F, 0); - bcm43xx_phy_write(bcm, 0x0810, 0); - bcm43xx_phy_write(bcm, 0x0478, - bcm43xx_phy_read(bcm, 0x0478) | 0x0100); - bcm43xx_phy_write(bcm, 0x0801, - bcm43xx_phy_read(bcm, 0x0801) | 0x0040); - bcm43xx_phy_write(bcm, 0x0060, - bcm43xx_phy_read(bcm, 0x0060) | 0x0040); - bcm43xx_phy_write(bcm, 0x0014, - bcm43xx_phy_read(bcm, 0x0014) | 0x0200); - } - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); - udelay(30); - - v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F == 31) { - for (i = 7; i >= 4; i--) { - bcm43xx_radio_write16(bcm, 0x007B, i); - udelay(20); - v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F < 31 && saved == 0xFFFF) - saved = i; - } - if (saved == 0xFFFF) - saved = 4; - } else { - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); - bcm43xx_phy_write(bcm, 0x0814, - bcm43xx_phy_read(bcm, 0x0814) | 0x0001); - bcm43xx_phy_write(bcm, 0x0815, - bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x000C); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) | 0x000C); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) | 0x0030); - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) | 0x0030); - bcm43xx_phy_write(bcm, 0x005A, 0x0480); - bcm43xx_phy_write(bcm, 0x0059, 0x0810); - bcm43xx_phy_write(bcm, 0x0058, 0x000D); - if (phy->analog == 0) { - bcm43xx_phy_write(bcm, 0x0003, 0x0122); - } else { - bcm43xx_phy_write(bcm, 0x000A, - bcm43xx_phy_read(bcm, 0x000A) - | 0x2000); - } - bcm43xx_phy_write(bcm, 0x0814, - bcm43xx_phy_read(bcm, 0x0814) | 0x0004); - bcm43xx_phy_write(bcm, 0x0815, - bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); - bcm43xx_phy_write(bcm, 0x0003, - (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) - | 0x0040); - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); - bcm43xx_set_all_gains(bcm, 3, 0, 1); - bcm43xx_radio_write16(bcm, 0x0043, - (bcm43xx_radio_read16(bcm, 0x0043) - & 0x00F0) | 0x000F); - udelay(30); - v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F == -32) { - for (i = 0; i < 4; i++) { - bcm43xx_radio_write16(bcm, 0x007B, i); - udelay(20); - v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F > -31 && saved == 0xFFFF) - saved = i; - } - if (saved == 0xFFFF) - saved = 3; - } else - saved = 0; - } - bcm43xx_radio_write16(bcm, 0x007B, saved); - - if (phy->rev >= 6) { - bcm43xx_phy_write(bcm, 0x002E, backup[12]); - bcm43xx_phy_write(bcm, 0x002F, backup[13]); - bcm43xx_phy_write(bcm, 0x080F, backup[14]); - bcm43xx_phy_write(bcm, 0x0810, backup[15]); - } - bcm43xx_phy_write(bcm, 0x0814, backup[3]); - bcm43xx_phy_write(bcm, 0x0815, backup[4]); - bcm43xx_phy_write(bcm, 0x005A, backup[5]); - bcm43xx_phy_write(bcm, 0x0059, backup[6]); - bcm43xx_phy_write(bcm, 0x0058, backup[7]); - bcm43xx_phy_write(bcm, 0x000A, backup[8]); - bcm43xx_phy_write(bcm, 0x0003, backup[9]); - bcm43xx_radio_write16(bcm, 0x0043, backup[11]); - bcm43xx_radio_write16(bcm, 0x007A, backup[10]); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2); - bcm43xx_phy_write(bcm, 0x0429, - bcm43xx_phy_read(bcm, 0x0429) | 0x8000); - bcm43xx_set_original_gains(bcm); - if (phy->rev >= 6) { - bcm43xx_phy_write(bcm, 0x0801, backup[16]); - bcm43xx_phy_write(bcm, 0x0060, backup[17]); - bcm43xx_phy_write(bcm, 0x0014, backup[18]); - bcm43xx_phy_write(bcm, 0x0478, backup[19]); - } - bcm43xx_phy_write(bcm, 0x0001, backup[0]); - bcm43xx_phy_write(bcm, 0x0812, backup[2]); - bcm43xx_phy_write(bcm, 0x0811, backup[1]); -} - -void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 backup[18] = { 0 }; - u16 tmp; - s16 nrssi0, nrssi1; - - switch (phy->type) { - case BCM43xx_PHYTYPE_B: - backup[0] = bcm43xx_radio_read16(bcm, 0x007A); - backup[1] = bcm43xx_radio_read16(bcm, 0x0052); - backup[2] = bcm43xx_radio_read16(bcm, 0x0043); - backup[3] = bcm43xx_phy_read(bcm, 0x0030); - backup[4] = bcm43xx_phy_read(bcm, 0x0026); - backup[5] = bcm43xx_phy_read(bcm, 0x0015); - backup[6] = bcm43xx_phy_read(bcm, 0x002A); - backup[7] = bcm43xx_phy_read(bcm, 0x0020); - backup[8] = bcm43xx_phy_read(bcm, 0x005A); - backup[9] = bcm43xx_phy_read(bcm, 0x0059); - backup[10] = bcm43xx_phy_read(bcm, 0x0058); - backup[11] = bcm43xx_read16(bcm, 0x03E2); - backup[12] = bcm43xx_read16(bcm, 0x03E6); - backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); - - tmp = bcm43xx_radio_read16(bcm, 0x007A); - tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; - bcm43xx_radio_write16(bcm, 0x007A, tmp); - bcm43xx_phy_write(bcm, 0x0030, 0x00FF); - bcm43xx_write16(bcm, 0x03EC, 0x7F7F); - bcm43xx_phy_write(bcm, 0x0026, 0x0000); - bcm43xx_phy_write(bcm, 0x0015, - bcm43xx_phy_read(bcm, 0x0015) | 0x0020); - bcm43xx_phy_write(bcm, 0x002A, 0x08A3); - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); - - nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027); - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); - if (phy->analog >= 2) { - bcm43xx_write16(bcm, 0x03E6, 0x0040); - } else if (phy->analog == 0) { - bcm43xx_write16(bcm, 0x03E6, 0x0122); - } else { - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, - bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000); - } - bcm43xx_phy_write(bcm, 0x0020, 0x3F3F); - bcm43xx_phy_write(bcm, 0x0015, 0xF330); - bcm43xx_radio_write16(bcm, 0x005A, 0x0060); - bcm43xx_radio_write16(bcm, 0x0043, - bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0); - bcm43xx_phy_write(bcm, 0x005A, 0x0480); - bcm43xx_phy_write(bcm, 0x0059, 0x0810); - bcm43xx_phy_write(bcm, 0x0058, 0x000D); - udelay(20); - - nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027); - bcm43xx_phy_write(bcm, 0x0030, backup[3]); - bcm43xx_radio_write16(bcm, 0x007A, backup[0]); - bcm43xx_write16(bcm, 0x03E2, backup[11]); - bcm43xx_phy_write(bcm, 0x0026, backup[4]); - bcm43xx_phy_write(bcm, 0x0015, backup[5]); - bcm43xx_phy_write(bcm, 0x002A, backup[6]); - bcm43xx_synth_pu_workaround(bcm, radio->channel); - if (phy->analog != 0) - bcm43xx_write16(bcm, 0x03F4, backup[13]); - - bcm43xx_phy_write(bcm, 0x0020, backup[7]); - bcm43xx_phy_write(bcm, 0x005A, backup[8]); - bcm43xx_phy_write(bcm, 0x0059, backup[9]); - bcm43xx_phy_write(bcm, 0x0058, backup[10]); - bcm43xx_radio_write16(bcm, 0x0052, backup[1]); - bcm43xx_radio_write16(bcm, 0x0043, backup[2]); - - if (nrssi0 == nrssi1) - radio->nrssislope = 0x00010000; - else - radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - - if (nrssi0 <= -4) { - radio->nrssi[0] = nrssi0; - radio->nrssi[1] = nrssi1; - } - break; - case BCM43xx_PHYTYPE_G: - if (radio->revision >= 9) - return; - if (radio->revision == 8) - bcm43xx_calc_nrssi_offset(bcm); - - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); - backup[7] = bcm43xx_read16(bcm, 0x03E2); - bcm43xx_write16(bcm, 0x03E2, - bcm43xx_read16(bcm, 0x03E2) | 0x8000); - backup[0] = bcm43xx_radio_read16(bcm, 0x007A); - backup[1] = bcm43xx_radio_read16(bcm, 0x0052); - backup[2] = bcm43xx_radio_read16(bcm, 0x0043); - backup[3] = bcm43xx_phy_read(bcm, 0x0015); - backup[4] = bcm43xx_phy_read(bcm, 0x005A); - backup[5] = bcm43xx_phy_read(bcm, 0x0059); - backup[6] = bcm43xx_phy_read(bcm, 0x0058); - backup[8] = bcm43xx_read16(bcm, 0x03E6); - backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); - if (phy->rev >= 3) { - backup[10] = bcm43xx_phy_read(bcm, 0x002E); - backup[11] = bcm43xx_phy_read(bcm, 0x002F); - backup[12] = bcm43xx_phy_read(bcm, 0x080F); - backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL); - backup[14] = bcm43xx_phy_read(bcm, 0x0801); - backup[15] = bcm43xx_phy_read(bcm, 0x0060); - backup[16] = bcm43xx_phy_read(bcm, 0x0014); - backup[17] = bcm43xx_phy_read(bcm, 0x0478); - bcm43xx_phy_write(bcm, 0x002E, 0); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0); - switch (phy->rev) { - case 4: case 6: case 7: - bcm43xx_phy_write(bcm, 0x0478, - bcm43xx_phy_read(bcm, 0x0478) - | 0x0100); - bcm43xx_phy_write(bcm, 0x0801, - bcm43xx_phy_read(bcm, 0x0801) - | 0x0040); - break; - case 3: case 5: - bcm43xx_phy_write(bcm, 0x0801, - bcm43xx_phy_read(bcm, 0x0801) - & 0xFFBF); - break; - } - bcm43xx_phy_write(bcm, 0x0060, - bcm43xx_phy_read(bcm, 0x0060) - | 0x0040); - bcm43xx_phy_write(bcm, 0x0014, - bcm43xx_phy_read(bcm, 0x0014) - | 0x0200); - } - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); - bcm43xx_set_all_gains(bcm, 0, 8, 0); - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7); - if (phy->rev >= 2) { - bcm43xx_phy_write(bcm, 0x0811, - (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030); - bcm43xx_phy_write(bcm, 0x0812, - (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010); - } - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); - udelay(20); - - nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); - if (nrssi0 >= 0x0020) - nrssi0 -= 0x0040; - - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); - if (phy->analog >= 2) { - bcm43xx_phy_write(bcm, 0x0003, - (bcm43xx_phy_read(bcm, 0x0003) - & 0xFF9F) | 0x0040); - } - - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, - bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) - | 0x2000); - bcm43xx_radio_write16(bcm, 0x007A, - bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); - bcm43xx_phy_write(bcm, 0x0015, 0xF330); - if (phy->rev >= 2) { - bcm43xx_phy_write(bcm, 0x0812, - (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020); - bcm43xx_phy_write(bcm, 0x0811, - (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020); - } - - bcm43xx_set_all_gains(bcm, 3, 0, 1); - if (radio->revision == 8) { - bcm43xx_radio_write16(bcm, 0x0043, 0x001F); - } else { - tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F; - bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060); - tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0; - bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009); - } - bcm43xx_phy_write(bcm, 0x005A, 0x0480); - bcm43xx_phy_write(bcm, 0x0059, 0x0810); - bcm43xx_phy_write(bcm, 0x0058, 0x000D); - udelay(20); - nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); - if (nrssi1 >= 0x0020) - nrssi1 -= 0x0040; - if (nrssi0 == nrssi1) - radio->nrssislope = 0x00010000; - else - radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - if (nrssi0 >= -4) { - radio->nrssi[0] = nrssi1; - radio->nrssi[1] = nrssi0; - } - if (phy->rev >= 3) { - bcm43xx_phy_write(bcm, 0x002E, backup[10]); - bcm43xx_phy_write(bcm, 0x002F, backup[11]); - bcm43xx_phy_write(bcm, 0x080F, backup[12]); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]); - } - if (phy->rev >= 2) { - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF); - bcm43xx_phy_write(bcm, 0x0811, - bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF); - } - - bcm43xx_radio_write16(bcm, 0x007A, backup[0]); - bcm43xx_radio_write16(bcm, 0x0052, backup[1]); - bcm43xx_radio_write16(bcm, 0x0043, backup[2]); - bcm43xx_write16(bcm, 0x03E2, backup[7]); - bcm43xx_write16(bcm, 0x03E6, backup[8]); - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]); - bcm43xx_phy_write(bcm, 0x0015, backup[3]); - bcm43xx_phy_write(bcm, 0x005A, backup[4]); - bcm43xx_phy_write(bcm, 0x0059, backup[5]); - bcm43xx_phy_write(bcm, 0x0058, backup[6]); - bcm43xx_synth_pu_workaround(bcm, radio->channel); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); - bcm43xx_set_original_gains(bcm); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); - if (phy->rev >= 3) { - bcm43xx_phy_write(bcm, 0x0801, backup[14]); - bcm43xx_phy_write(bcm, 0x0060, backup[15]); - bcm43xx_phy_write(bcm, 0x0014, backup[16]); - bcm43xx_phy_write(bcm, 0x0478, backup[17]); - } - bcm43xx_nrssi_mem_update(bcm); - bcm43xx_calc_nrssi_threshold(bcm); - break; - default: - assert(0); - } -} - -void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - s32 threshold; - s32 a, b; - s16 tmp16; - u16 tmp_u16; - - switch (phy->type) { - case BCM43xx_PHYTYPE_B: { - if (radio->version != 0x2050) - return; - if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) - return; - - if (radio->revision >= 6) { - threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32; - threshold += 20 * (radio->nrssi[0] + 1); - threshold /= 40; - } else - threshold = radio->nrssi[1] - 5; - - threshold = limit_value(threshold, 0, 0x3E); - bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ - bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); - - if (radio->revision >= 6) { - bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); - bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); - bcm43xx_phy_write(bcm, 0x0085, 0x0A09); - bcm43xx_phy_write(bcm, 0x0084, 0x0808); - bcm43xx_phy_write(bcm, 0x0083, 0x0808); - bcm43xx_phy_write(bcm, 0x0082, 0x0604); - bcm43xx_phy_write(bcm, 0x0081, 0x0302); - bcm43xx_phy_write(bcm, 0x0080, 0x0100); - } - break; - } - case BCM43xx_PHYTYPE_G: - if (!phy->connected || - !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { - tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20); - if (tmp16 >= 0x20) - tmp16 -= 0x40; - if (tmp16 < 3) { - bcm43xx_phy_write(bcm, 0x048A, - (bcm43xx_phy_read(bcm, 0x048A) - & 0xF000) | 0x09EB); - } else { - bcm43xx_phy_write(bcm, 0x048A, - (bcm43xx_phy_read(bcm, 0x048A) - & 0xF000) | 0x0AED); - } - } else { - if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { - a = 0xE; - b = 0xA; - } else if (!radio->aci_wlan_automatic && radio->aci_enable) { - a = 0x13; - b = 0x12; - } else { - a = 0xE; - b = 0x11; - } - - a = a * (radio->nrssi[1] - radio->nrssi[0]); - a += (radio->nrssi[0] << 6); - if (a < 32) - a += 31; - else - a += 32; - a = a >> 6; - a = limit_value(a, -31, 31); - - b = b * (radio->nrssi[1] - radio->nrssi[0]); - b += (radio->nrssi[0] << 6); - if (b < 32) - b += 31; - else - b += 32; - b = b >> 6; - b = limit_value(b, -31, 31); - - tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; - tmp_u16 |= ((u32)b & 0x0000003F); - tmp_u16 |= (((u32)a & 0x0000003F) << 6); - bcm43xx_phy_write(bcm, 0x048A, tmp_u16); - } - break; - default: - assert(0); - } -} - -/* Stack implementation to save/restore values from the - * interference mitigation code. - * It is save to restore values in random order. - */ -static void _stack_save(u32 *_stackptr, size_t *stackidx, - u8 id, u16 offset, u16 value) -{ - u32 *stackptr = &(_stackptr[*stackidx]); - - assert((offset & 0xE000) == 0x0000); - assert((id & 0xF8) == 0x00); - *stackptr = offset; - *stackptr |= ((u32)id) << 13; - *stackptr |= ((u32)value) << 16; - (*stackidx)++; - assert(*stackidx < BCM43xx_INTERFSTACK_SIZE); -} - -static u16 _stack_restore(u32 *stackptr, - u8 id, u16 offset) -{ - size_t i; - - assert((offset & 0xE000) == 0x0000); - assert((id & 0xF8) == 0x00); - for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) { - if ((*stackptr & 0x00001FFF) != offset) - continue; - if (((*stackptr & 0x00007000) >> 13) != id) - continue; - return ((*stackptr & 0xFFFF0000) >> 16); - } - assert(0); - - return 0; -} - -#define phy_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x1, (offset), \ - bcm43xx_phy_read(bcm, (offset))); \ - } while (0) -#define phy_stackrestore(offset) \ - do { \ - bcm43xx_phy_write(bcm, (offset), \ - _stack_restore(stack, 0x1, \ - (offset))); \ - } while (0) -#define radio_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x2, (offset), \ - bcm43xx_radio_read16(bcm, (offset))); \ - } while (0) -#define radio_stackrestore(offset) \ - do { \ - bcm43xx_radio_write16(bcm, (offset), \ - _stack_restore(stack, 0x2, \ - (offset))); \ - } while (0) -#define ilt_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x3, (offset), \ - bcm43xx_ilt_read(bcm, (offset))); \ - } while (0) -#define ilt_stackrestore(offset) \ - do { \ - bcm43xx_ilt_write(bcm, (offset), \ - _stack_restore(stack, 0x3, \ - (offset))); \ - } while (0) - -static void -bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, - int mode) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 tmp, flipped; - u32 tmp32; - size_t stackidx = 0; - u32 *stack = radio->interfstack; - - switch (mode) { - case BCM43xx_RADIO_INTERFMODE_NONWLAN: - if (phy->rev != 1) { - bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) | 0x0800); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); - break; - } - radio_stacksave(0x0078); - tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); - flipped = flip_4bit(tmp); - if (flipped < 10 && flipped >= 8) - flipped = 7; - else if (flipped >= 10) - flipped -= 3; - flipped = flip_4bit(flipped); - flipped = (flipped << 1) | 0x0020; - bcm43xx_radio_write16(bcm, 0x0078, flipped); - - bcm43xx_calc_nrssi_threshold(bcm); - - phy_stacksave(0x0406); - bcm43xx_phy_write(bcm, 0x0406, 0x7E28); - - bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) | 0x0800); - bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); - - phy_stacksave(0x04A0); - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); - phy_stacksave(0x04A1); - bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); - phy_stacksave(0x04A2); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); - phy_stacksave(0x04A8); - bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803); - phy_stacksave(0x04AB); - bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605); - - phy_stacksave(0x04A7); - bcm43xx_phy_write(bcm, 0x04A7, 0x0002); - phy_stacksave(0x04A3); - bcm43xx_phy_write(bcm, 0x04A3, 0x287A); - phy_stacksave(0x04A9); - bcm43xx_phy_write(bcm, 0x04A9, 0x2027); - phy_stacksave(0x0493); - bcm43xx_phy_write(bcm, 0x0493, 0x32F5); - phy_stacksave(0x04AA); - bcm43xx_phy_write(bcm, 0x04AA, 0x2027); - phy_stacksave(0x04AC); - bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); - break; - case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800) - break; - - radio->aci_enable = 1; - - phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD); - phy_stacksave(BCM43xx_PHY_G_CRS); - if (phy->rev < 2) { - phy_stacksave(0x0406); - } else { - phy_stacksave(0x04C0); - phy_stacksave(0x04C1); - } - phy_stacksave(0x0033); - phy_stacksave(0x04A7); - phy_stacksave(0x04A3); - phy_stacksave(0x04A9); - phy_stacksave(0x04AA); - phy_stacksave(0x04AC); - phy_stacksave(0x0493); - phy_stacksave(0x04A1); - phy_stacksave(0x04A0); - phy_stacksave(0x04A2); - phy_stacksave(0x048A); - phy_stacksave(0x04A8); - phy_stacksave(0x04AB); - if (phy->rev == 2) { - phy_stacksave(0x04AD); - phy_stacksave(0x04AE); - } else if (phy->rev >= 3) { - phy_stacksave(0x04AD); - phy_stacksave(0x0415); - phy_stacksave(0x0416); - phy_stacksave(0x0417); - ilt_stacksave(0x1A00 + 0x2); - ilt_stacksave(0x1A00 + 0x3); - } - phy_stacksave(0x042B); - phy_stacksave(0x048C); - - bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) - & ~0x1000); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) - & 0xFFFC) | 0x0002); - - bcm43xx_phy_write(bcm, 0x0033, 0x0800); - bcm43xx_phy_write(bcm, 0x04A3, 0x2027); - bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8); - bcm43xx_phy_write(bcm, 0x0493, 0x287A); - bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8); - bcm43xx_phy_write(bcm, 0x04AC, 0x287A); - - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) - & 0xFFC0) | 0x001A); - bcm43xx_phy_write(bcm, 0x04A7, 0x000D); - - if (phy->rev < 2) { - bcm43xx_phy_write(bcm, 0x0406, 0xFF0D); - } else if (phy->rev == 2) { - bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF); - bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); - } else { - bcm43xx_phy_write(bcm, 0x04C0, 0x00C1); - bcm43xx_phy_write(bcm, 0x04C1, 0x0059); - } - - bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) - & 0xC0FF) | 0x1800); - bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) - & 0xFFC0) | 0x0015); - bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) - & 0xCFFF) | 0x1000); - bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) - & 0xF0FF) | 0x0A00); - bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) - & 0xCFFF) | 0x1000); - bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) - & 0xF0FF) | 0x0800); - bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) - & 0xFFCF) | 0x0010); - bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) - & 0xFFF0) | 0x0005); - bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) - & 0xFFCF) | 0x0010); - bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) - & 0xFFF0) | 0x0006); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) - & 0xF0FF) | 0x0800); - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) - & 0xF0FF) | 0x0500); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) - & 0xFFF0) | 0x000B); - - if (phy->rev >= 3) { - bcm43xx_phy_write(bcm, 0x048A, - bcm43xx_phy_read(bcm, 0x048A) - & ~0x8000); - bcm43xx_phy_write(bcm, 0x0415, - (bcm43xx_phy_read(bcm, 0x0415) - & 0x8000) | 0x36D8); - bcm43xx_phy_write(bcm, 0x0416, - (bcm43xx_phy_read(bcm, 0x0416) - & 0x8000) | 0x36D8); - bcm43xx_phy_write(bcm, 0x0417, - (bcm43xx_phy_read(bcm, 0x0417) - & 0xFE00) | 0x016D); - } else { - bcm43xx_phy_write(bcm, 0x048A, - bcm43xx_phy_read(bcm, 0x048A) - | 0x1000); - bcm43xx_phy_write(bcm, 0x048A, - (bcm43xx_phy_read(bcm, 0x048A) - & 0x9FFF) | 0x2000); - tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET); - if (!(tmp32 & 0x800)) { - tmp32 |= 0x800; - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - tmp32); - } - } - if (phy->rev >= 2) { - bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) - | 0x0800); - } - bcm43xx_phy_write(bcm, 0x048C, - (bcm43xx_phy_read(bcm, 0x048C) - & 0xF0FF) | 0x0200); - if (phy->rev == 2) { - bcm43xx_phy_write(bcm, 0x04AE, - (bcm43xx_phy_read(bcm, 0x04AE) - & 0xFF00) | 0x007F); - bcm43xx_phy_write(bcm, 0x04AD, - (bcm43xx_phy_read(bcm, 0x04AD) - & 0x00FF) | 0x1300); - } else if (phy->rev >= 6) { - bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F); - bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F); - bcm43xx_phy_write(bcm, 0x04AD, - bcm43xx_phy_read(bcm, 0x04AD) - & 0x00FF); - } - bcm43xx_calc_nrssi_slope(bcm); - break; - default: - assert(0); - } -} - -static void -bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, - int mode) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u32 tmp32; - u32 *stack = radio->interfstack; - - switch (mode) { - case BCM43xx_RADIO_INTERFMODE_NONWLAN: - if (phy->rev != 1) { - bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); - break; - } - phy_stackrestore(0x0078); - bcm43xx_calc_nrssi_threshold(bcm); - phy_stackrestore(0x0406); - bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); - if (!bcm->bad_frames_preempt) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) - & ~(1 << 11)); - } - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); - phy_stackrestore(0x04A0); - phy_stackrestore(0x04A1); - phy_stackrestore(0x04A2); - phy_stackrestore(0x04A8); - phy_stackrestore(0x04AB); - phy_stackrestore(0x04A7); - phy_stackrestore(0x04A3); - phy_stackrestore(0x04A9); - phy_stackrestore(0x0493); - phy_stackrestore(0x04AA); - phy_stackrestore(0x04AC); - break; - case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800)) - break; - - radio->aci_enable = 0; - - phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD); - phy_stackrestore(BCM43xx_PHY_G_CRS); - phy_stackrestore(0x0033); - phy_stackrestore(0x04A3); - phy_stackrestore(0x04A9); - phy_stackrestore(0x0493); - phy_stackrestore(0x04AA); - phy_stackrestore(0x04AC); - phy_stackrestore(0x04A0); - phy_stackrestore(0x04A7); - if (phy->rev >= 2) { - phy_stackrestore(0x04C0); - phy_stackrestore(0x04C1); - } else - phy_stackrestore(0x0406); - phy_stackrestore(0x04A1); - phy_stackrestore(0x04AB); - phy_stackrestore(0x04A8); - if (phy->rev == 2) { - phy_stackrestore(0x04AD); - phy_stackrestore(0x04AE); - } else if (phy->rev >= 3) { - phy_stackrestore(0x04AD); - phy_stackrestore(0x0415); - phy_stackrestore(0x0416); - phy_stackrestore(0x0417); - ilt_stackrestore(0x1A00 + 0x2); - ilt_stackrestore(0x1A00 + 0x3); - } - phy_stackrestore(0x04A2); - phy_stackrestore(0x04A8); - phy_stackrestore(0x042B); - phy_stackrestore(0x048C); - tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET); - if (tmp32 & 0x800) { - tmp32 &= ~0x800; - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - tmp32); - } - bcm43xx_calc_nrssi_slope(bcm); - break; - default: - assert(0); - } -} - -#undef phy_stacksave -#undef phy_stackrestore -#undef radio_stacksave -#undef radio_stackrestore -#undef ilt_stacksave -#undef ilt_stackrestore - -int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, - int mode) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int currentmode; - - if ((phy->type != BCM43xx_PHYTYPE_G) || - (phy->rev == 0) || - (!phy->connected)) - return -ENODEV; - - radio->aci_wlan_automatic = 0; - switch (mode) { - case BCM43xx_RADIO_INTERFMODE_AUTOWLAN: - radio->aci_wlan_automatic = 1; - if (radio->aci_enable) - mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; - else - mode = BCM43xx_RADIO_INTERFMODE_NONE; - break; - case BCM43xx_RADIO_INTERFMODE_NONE: - case BCM43xx_RADIO_INTERFMODE_NONWLAN: - case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - break; - default: - return -EINVAL; - } - - currentmode = radio->interfmode; - if (currentmode == mode) - return 0; - if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE) - bcm43xx_radio_interference_mitigation_disable(bcm, currentmode); - - if (mode == BCM43xx_RADIO_INTERFMODE_NONE) { - radio->aci_enable = 0; - radio->aci_hw_rssi = 0; - } else - bcm43xx_radio_interference_mitigation_enable(bcm, mode); - radio->interfmode = mode; - - return 0; -} - -u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) -{ - u16 reg, index, ret; - - reg = bcm43xx_radio_read16(bcm, 0x0060); - index = (reg & 0x001E) >> 1; - ret = rcc_table[index] << 1; - ret |= (reg & 0x0001); - ret |= 0x0020; - - return ret; -} - -#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) -static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 loop_or = 0; - u16 adj_loopback_gain = phy->loopback_gain[0]; - u8 loop; - u16 extern_lna_control; - - if (!phy->connected) - return 0; - if (!has_loopback_gain(phy)) { - if (phy->rev < 7 || !(bcm->sprom.boardflags - & BCM43xx_BFL_EXTLNA)) { - switch (lpd) { - case LPD(0, 1, 1): - return 0x0FB2; - case LPD(0, 0, 1): - return 0x00B2; - case LPD(1, 0, 1): - return 0x30B2; - case LPD(1, 0, 0): - return 0x30B3; - default: - assert(0); - } - } else { - switch (lpd) { - case LPD(0, 1, 1): - return 0x8FB2; - case LPD(0, 0, 1): - return 0x80B2; - case LPD(1, 0, 1): - return 0x20B2; - case LPD(1, 0, 0): - return 0x20B3; - default: - assert(0); - } - } - } else { - if (radio->revision == 8) - adj_loopback_gain += 0x003E; - else - adj_loopback_gain += 0x0026; - if (adj_loopback_gain >= 0x46) { - adj_loopback_gain -= 0x46; - extern_lna_control = 0x3000; - } else if (adj_loopback_gain >= 0x3A) { - adj_loopback_gain -= 0x3A; - extern_lna_control = 0x2000; - } else if (adj_loopback_gain >= 0x2E) { - adj_loopback_gain -= 0x2E; - extern_lna_control = 0x1000; - } else { - adj_loopback_gain -= 0x10; - extern_lna_control = 0x0000; - } - for (loop = 0; loop < 16; loop++) { - u16 tmp = adj_loopback_gain - 6 * loop; - if (tmp < 6) - break; - } - - loop_or = (loop << 8) | extern_lna_control; - if (phy->rev >= 7 && bcm->sprom.boardflags - & BCM43xx_BFL_EXTLNA) { - if (extern_lna_control) - loop_or |= 0x8000; - switch (lpd) { - case LPD(0, 1, 1): - return 0x8F92; - case LPD(0, 0, 1): - return (0x8092 | loop_or); - case LPD(1, 0, 1): - return (0x2092 | loop_or); - case LPD(1, 0, 0): - return (0x2093 | loop_or); - default: - assert(0); - } - } else { - switch (lpd) { - case LPD(0, 1, 1): - return 0x0F92; - case LPD(0, 0, 1): - case LPD(1, 0, 1): - return (0x0092 | loop_or); - case LPD(1, 0, 0): - return (0x0093 | loop_or); - default: - assert(0); - } - } - } - return 0; -} - -u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 backup[21] = { 0 }; - u16 ret; - u16 i, j; - u32 tmp1 = 0, tmp2 = 0; - - backup[0] = bcm43xx_radio_read16(bcm, 0x0043); - backup[14] = bcm43xx_radio_read16(bcm, 0x0051); - backup[15] = bcm43xx_radio_read16(bcm, 0x0052); - backup[1] = bcm43xx_phy_read(bcm, 0x0015); - backup[16] = bcm43xx_phy_read(bcm, 0x005A); - backup[17] = bcm43xx_phy_read(bcm, 0x0059); - backup[18] = bcm43xx_phy_read(bcm, 0x0058); - if (phy->type == BCM43xx_PHYTYPE_B) { - backup[2] = bcm43xx_phy_read(bcm, 0x0030); - backup[3] = bcm43xx_read16(bcm, 0x03EC); - bcm43xx_phy_write(bcm, 0x0030, 0x00FF); - bcm43xx_write16(bcm, 0x03EC, 0x3F3F); - } else { - if (phy->connected) { - backup[4] = bcm43xx_phy_read(bcm, 0x0811); - backup[5] = bcm43xx_phy_read(bcm, 0x0812); - backup[6] = bcm43xx_phy_read(bcm, 0x0814); - backup[7] = bcm43xx_phy_read(bcm, 0x0815); - backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); - backup[9] = bcm43xx_phy_read(bcm, 0x0802); - bcm43xx_phy_write(bcm, 0x0814, - (bcm43xx_phy_read(bcm, 0x0814) - | 0x0003)); - bcm43xx_phy_write(bcm, 0x0815, - (bcm43xx_phy_read(bcm, 0x0815) - & 0xFFFC)); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) - & 0x7FFF)); - bcm43xx_phy_write(bcm, 0x0802, - (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); - if (phy->rev > 1) { /* loopback gain enabled */ - backup[19] = bcm43xx_phy_read(bcm, 0x080F); - backup[20] = bcm43xx_phy_read(bcm, 0x0810); - if (phy->rev >= 3) - bcm43xx_phy_write(bcm, 0x080F, 0xC020); - else - bcm43xx_phy_write(bcm, 0x080F, 0x8020); - bcm43xx_phy_write(bcm, 0x0810, 0x0000); - } - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(0, 1, 1))); - if (phy->rev < 7 || !(bcm->sprom.boardflags - & BCM43xx_BFL_EXTLNA)) - bcm43xx_phy_write(bcm, 0x0811, 0x01B3); - else - bcm43xx_phy_write(bcm, 0x0811, 0x09B3); - } - } - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, - (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); - backup[10] = bcm43xx_phy_read(bcm, 0x0035); - bcm43xx_phy_write(bcm, 0x0035, - (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); - backup[11] = bcm43xx_read16(bcm, 0x03E6); - backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); - - // Initialization - if (phy->analog == 0) { - bcm43xx_write16(bcm, 0x03E6, 0x0122); - } else { - if (phy->analog >= 2) - bcm43xx_phy_write(bcm, 0x0003, - (bcm43xx_phy_read(bcm, 0x0003) - & 0xFFBF) | 0x0040); - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, - (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) - | 0x2000)); - } - - ret = bcm43xx_radio_calibrationvalue(bcm); - - if (phy->type == BCM43xx_PHYTYPE_B) - bcm43xx_radio_write16(bcm, 0x0078, 0x0026); - - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(0, 1, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); - bcm43xx_phy_write(bcm, 0x002B, 0x1403); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(0, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); - bcm43xx_radio_write16(bcm, 0x0051, - (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); - if (radio->revision == 8) - bcm43xx_radio_write16(bcm, 0x0043, 0x001F); - else { - bcm43xx_radio_write16(bcm, 0x0052, 0x0000); - bcm43xx_radio_write16(bcm, 0x0043, - (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) - | 0x0009); - } - bcm43xx_phy_write(bcm, 0x0058, 0x0000); - - for (i = 0; i < 16; i++) { - bcm43xx_phy_write(bcm, 0x005A, 0x0480); - bcm43xx_phy_write(bcm, 0x0059, 0xC810); - bcm43xx_phy_write(bcm, 0x0058, 0x000D); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); - udelay(10); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); - udelay(10); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 0))); - bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); - udelay(20); - tmp1 += bcm43xx_phy_read(bcm, 0x002D); - bcm43xx_phy_write(bcm, 0x0058, 0x0000); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); - } - - tmp1++; - tmp1 >>= 9; - udelay(10); - bcm43xx_phy_write(bcm, 0x0058, 0x0000); - - for (i = 0; i < 16; i++) { - bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020); - backup[13] = bcm43xx_radio_read16(bcm, 0x0078); - udelay(10); - for (j = 0; j < 16; j++) { - bcm43xx_phy_write(bcm, 0x005A, 0x0D80); - bcm43xx_phy_write(bcm, 0x0059, 0xC810); - bcm43xx_phy_write(bcm, 0x0058, 0x000D); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); - udelay(10); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); - udelay(10); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 0))); - bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); - udelay(10); - tmp2 += bcm43xx_phy_read(bcm, 0x002D); - bcm43xx_phy_write(bcm, 0x0058, 0x0000); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 1))); - bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); - } - tmp2++; - tmp2 >>= 8; - if (tmp1 < tmp2) - break; - } - - /* Restore the registers */ - bcm43xx_phy_write(bcm, 0x0015, backup[1]); - bcm43xx_radio_write16(bcm, 0x0051, backup[14]); - bcm43xx_radio_write16(bcm, 0x0052, backup[15]); - bcm43xx_radio_write16(bcm, 0x0043, backup[0]); - bcm43xx_phy_write(bcm, 0x005A, backup[16]); - bcm43xx_phy_write(bcm, 0x0059, backup[17]); - bcm43xx_phy_write(bcm, 0x0058, backup[18]); - bcm43xx_write16(bcm, 0x03E6, backup[11]); - if (phy->analog != 0) - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]); - bcm43xx_phy_write(bcm, 0x0035, backup[10]); - bcm43xx_radio_selectchannel(bcm, radio->channel, 1); - if (phy->type == BCM43xx_PHYTYPE_B) { - bcm43xx_phy_write(bcm, 0x0030, backup[2]); - bcm43xx_write16(bcm, 0x03EC, backup[3]); - } else { - if (phy->connected) { - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, - (bcm43xx_read16(bcm, - BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); - bcm43xx_phy_write(bcm, 0x0811, backup[4]); - bcm43xx_phy_write(bcm, 0x0812, backup[5]); - bcm43xx_phy_write(bcm, 0x0814, backup[6]); - bcm43xx_phy_write(bcm, 0x0815, backup[7]); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); - bcm43xx_phy_write(bcm, 0x0802, backup[9]); - if (phy->rev > 1) { - bcm43xx_phy_write(bcm, 0x080F, backup[19]); - bcm43xx_phy_write(bcm, 0x0810, backup[20]); - } - } - } - if (i >= 15) - ret = backup[13]; - - return ret; -} - -void bcm43xx_radio_init2060(struct bcm43xx_private *bcm) -{ - int err; - - bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); - bcm43xx_radio_write16(bcm, 0x0005, 0x0008); - bcm43xx_radio_write16(bcm, 0x0009, 0x0040); - bcm43xx_radio_write16(bcm, 0x0005, 0x00AA); - bcm43xx_radio_write16(bcm, 0x0032, 0x008F); - bcm43xx_radio_write16(bcm, 0x0006, 0x008F); - bcm43xx_radio_write16(bcm, 0x0034, 0x008F); - bcm43xx_radio_write16(bcm, 0x002C, 0x0007); - bcm43xx_radio_write16(bcm, 0x0082, 0x0080); - bcm43xx_radio_write16(bcm, 0x0080, 0x0000); - bcm43xx_radio_write16(bcm, 0x003F, 0x00DA); - bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); - bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010); - bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); - bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); - udelay(400); - - bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010); - udelay(400); - - bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008); - bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010); - bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); - bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040); - bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040); - bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008); - bcm43xx_phy_write(bcm, 0x0063, 0xDDC6); - bcm43xx_phy_write(bcm, 0x0069, 0x07BE); - bcm43xx_phy_write(bcm, 0x006A, 0x0000); - - err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0); - assert(err == 0); - udelay(1000); -} - -static inline -u16 freq_r3A_value(u16 frequency) -{ - u16 value; - - if (frequency < 5091) - value = 0x0040; - else if (frequency < 5321) - value = 0x0000; - else if (frequency < 5806) - value = 0x0080; - else - value = 0x0040; - - return value; -} - -void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm) -{ - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = bcm43xx_radio_read16(bcm, 0x001E); - int i, j; - - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] | data_low[j])) { - bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0); - return; - } - } - } -} - -int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, - u8 channel, - int synthetic_pu_workaround) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 r8, tmp; - u16 freq; - - if (!ieee80211_is_valid_channel(bcm->ieee, channel)) - return -EINVAL; - if ((radio->manufact == 0x17F) && - (radio->version == 0x2060) && - (radio->revision == 1)) { - freq = channel2freq_a(channel); - - r8 = bcm43xx_radio_read16(bcm, 0x0008); - bcm43xx_write16(bcm, 0x03F0, freq); - bcm43xx_radio_write16(bcm, 0x0008, r8); - - TODO();//TODO: write max channel TX power? to Radio 0x2D - tmp = bcm43xx_radio_read16(bcm, 0x002E); - tmp &= 0x0080; - TODO();//TODO: OR tmp with the Power out estimation for this channel? - bcm43xx_radio_write16(bcm, 0x002E, tmp); - - if (freq >= 4920 && freq <= 5500) { - /* - * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; - * = (freq * 0.025862069 - */ - r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ - } - bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8); - bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8); - bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8); - bcm43xx_radio_write16(bcm, 0x0022, - (bcm43xx_radio_read16(bcm, 0x0022) - & 0x000F) | (r8 << 4)); - bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4)); - bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4)); - bcm43xx_radio_write16(bcm, 0x0008, - (bcm43xx_radio_read16(bcm, 0x0008) - & 0x00F0) | (r8 << 4)); - bcm43xx_radio_write16(bcm, 0x0029, - (bcm43xx_radio_read16(bcm, 0x0029) - & 0xFF0F) | 0x00B0); - bcm43xx_radio_write16(bcm, 0x0035, 0x00AA); - bcm43xx_radio_write16(bcm, 0x0036, 0x0085); - bcm43xx_radio_write16(bcm, 0x003A, - (bcm43xx_radio_read16(bcm, 0x003A) - & 0xFF20) | freq_r3A_value(freq)); - bcm43xx_radio_write16(bcm, 0x003D, - bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF); - bcm43xx_radio_write16(bcm, 0x0081, - (bcm43xx_radio_read16(bcm, 0x0081) - & 0xFF7F) | 0x0080); - bcm43xx_radio_write16(bcm, 0x0035, - bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF); - bcm43xx_radio_write16(bcm, 0x0035, - (bcm43xx_radio_read16(bcm, 0x0035) - & 0xFFEF) | 0x0010); - bcm43xx_radio_set_tx_iq(bcm); - TODO(); //TODO: TSSI2dbm workaround - bcm43xx_phy_xmitpower(bcm);//FIXME correct? - } else { - if (synthetic_pu_workaround) - bcm43xx_synth_pu_workaround(bcm, channel); - - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, - channel2freq_bg(channel)); - - if (channel == 14) { - if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) { - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET) - & ~(1 << 7)); - } else { - bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET, - bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODEFLAGS_OFFSET) - | (1 << 7)); - } - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, - bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) - | (1 << 11)); - } else { - bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, - bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) - & 0xF7BF); - } - } - - radio->channel = channel; - //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states - // that 2000 usecs might suffice. - udelay(8000); - - return 0; -} - -void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val) -{ - u16 tmp; - - val <<= 8; - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF; - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val); - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF; - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val); - tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF; - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val); -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ -static u16 bcm43xx_get_txgain_base_band(u16 txpower) -{ - u16 ret; - - assert(txpower <= 63); - - if (txpower >= 54) - ret = 2; - else if (txpower >= 49) - ret = 4; - else if (txpower >= 44) - ret = 5; - else - ret = 6; - - return ret; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ -static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower) -{ - u16 ret; - - assert(txpower <= 63); - - if (txpower >= 32) - ret = 0; - else if (txpower >= 25) - ret = 1; - else if (txpower >= 20) - ret = 2; - else if (txpower >= 12) - ret = 3; - else - ret = 4; - - return ret; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ -static u16 bcm43xx_get_txgain_dac(u16 txpower) -{ - u16 ret; - - assert(txpower <= 63); - - if (txpower >= 54) - ret = txpower - 53; - else if (txpower >= 49) - ret = txpower - 42; - else if (txpower >= 44) - ret = txpower - 37; - else if (txpower >= 32) - ret = txpower - 32; - else if (txpower >= 25) - ret = txpower - 20; - else if (txpower >= 20) - ret = txpower - 13; - else if (txpower >= 12) - ret = txpower - 8; - else - ret = txpower; - - return ret; -} - -void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 pamp, base, dac, ilt; - - txpower = limit_value(txpower, 0, 63); - - pamp = bcm43xx_get_txgain_freq_power_amp(txpower); - pamp <<= 5; - pamp &= 0x00E0; - bcm43xx_phy_write(bcm, 0x0019, pamp); - - base = bcm43xx_get_txgain_base_band(txpower); - base &= 0x000F; - bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); - - ilt = bcm43xx_ilt_read(bcm, 0x3001); - ilt &= 0x0007; - - dac = bcm43xx_get_txgain_dac(txpower); - dac <<= 3; - dac |= ilt; - - bcm43xx_ilt_write(bcm, 0x3001, dac); - - radio->txpwr_offset = txpower; - - TODO(); - //TODO: FuncPlaceholder (Adjust BB loft cancel) -} - -void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, - u16 baseband_attenuation, u16 radio_attenuation, - u16 txpower) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - if (baseband_attenuation == 0xFFFF) - baseband_attenuation = radio->baseband_atten; - if (radio_attenuation == 0xFFFF) - radio_attenuation = radio->radio_atten; - if (txpower == 0xFFFF) - txpower = radio->txctl1; - radio->baseband_atten = baseband_attenuation; - radio->radio_atten = radio_attenuation; - radio->txctl1 = txpower; - - assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); - if (radio->revision < 6) - assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9); - else - assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31); - assert(/*txpower >= 0 &&*/ txpower <= 7); - - bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation); - bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); - if (radio->version == 0x2050) { - bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) - | ((txpower << 4) & 0x0070)); - } - //FIXME: The spec is very weird and unclear here. - if (phy->type == BCM43xx_PHYTYPE_G) - bcm43xx_phy_lo_adjust(bcm, 0); -} - -u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - - if (radio->version == 0x2050 && radio->revision < 6) - return 0; - return 2; -} - -u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 att = 0xFFFF; - - if (phy->type == BCM43xx_PHYTYPE_A) - return 0x60; - - switch (radio->version) { - case 0x2053: - switch (radio->revision) { - case 1: - att = 6; - break; - } - break; - case 0x2050: - switch (radio->revision) { - case 0: - att = 5; - break; - case 1: - if (phy->type == BCM43xx_PHYTYPE_G) { - if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && - bcm->board_type == 0x421 && - bcm->board_revision >= 30) - att = 3; - else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && - bcm->board_type == 0x416) - att = 3; - else - att = 1; - } else { - if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && - bcm->board_type == 0x421 && - bcm->board_revision >= 30) - att = 7; - else - att = 6; - } - break; - case 2: - if (phy->type == BCM43xx_PHYTYPE_G) { - if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && - bcm->board_type == 0x421 && - bcm->board_revision >= 30) - att = 3; - else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && - bcm->board_type == 0x416) - att = 5; - else if (bcm->chip_id == 0x4320) - att = 4; - else - att = 3; - } else - att = 6; - break; - case 3: - att = 5; - break; - case 4: - case 5: - att = 1; - break; - case 6: - case 7: - att = 5; - break; - case 8: - att = 0x1A; - break; - case 9: - default: - att = 5; - } - } - if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && - bcm->board_type == 0x421) { - if (bcm->board_revision < 0x43) - att = 2; - else if (bcm->board_revision < 0x51) - att = 3; - } - if (att == 0xFFFF) - att = 5; - - return att; -} - -u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - - if (radio->version != 0x2050) - return 0; - if (radio->revision == 1) - return 3; - if (radio->revision < 6) - return 2; - if (radio->revision == 8) - return 1; - return 0; -} - -void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int err; - - if (radio->enabled) - return; - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); - bcm43xx_radio_write16(bcm, 0x0005, 0x0008); - bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7); - bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7); - bcm43xx_radio_init2060(bcm); - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - bcm43xx_phy_write(bcm, 0x0015, 0x8000); - bcm43xx_phy_write(bcm, 0x0015, 0xCC00); - bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000)); - err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1); - assert(err == 0); - break; - default: - assert(0); - } - radio->enabled = 1; - dprintk(KERN_INFO PFX "Radio turned on\n"); - bcm43xx_leds_update(bcm, 0); -} - -void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - - if (phy->type == BCM43xx_PHYTYPE_A) { - bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); - bcm43xx_radio_write16(bcm, 0x0005, 0x00FB); - bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008); - bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008); - } - if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) { - bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C); - bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73); - } else - bcm43xx_phy_write(bcm, 0x0015, 0xAA00); - radio->enabled = 0; - dprintk(KERN_INFO PFX "Radio initialized\n"); - bcm43xx_leds_update(bcm, 0); -} - -void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); - break; - case BCM43xx_PHYTYPE_B: - case BCM43xx_PHYTYPE_G: - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F); - bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F); - break; - } -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h deleted file mode 100644 index 77a98a53a2e..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifndef BCM43xx_RADIO_H_ -#define BCM43xx_RADIO_H_ - -#include "bcm43xx.h" - - -#define BCM43xx_RADIO_DEFAULT_CHANNEL_A 36 -#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG 6 - -/* Force antenna 0. */ -#define BCM43xx_RADIO_TXANTENNA_0 0 -/* Force antenna 1. */ -#define BCM43xx_RADIO_TXANTENNA_1 1 -/* Use the RX antenna, that was selected for the most recently - * received good PLCP header. - */ -#define BCM43xx_RADIO_TXANTENNA_LASTPLCP 3 -#define BCM43xx_RADIO_TXANTENNA_DEFAULT BCM43xx_RADIO_TXANTENNA_LASTPLCP - -#define BCM43xx_RADIO_INTERFMODE_NONE 0 -#define BCM43xx_RADIO_INTERFMODE_NONWLAN 1 -#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN 2 -#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN 3 - - -void bcm43xx_radio_lock(struct bcm43xx_private *bcm); -void bcm43xx_radio_unlock(struct bcm43xx_private *bcm); - -u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset); -void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); - -u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm); -void bcm43xx_radio_init2060(struct bcm43xx_private *bcm); - -void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); -void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); - -static inline -int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm) -{ - /* function to return state of hardware enable of radio - * returns 0 if radio disabled, 1 if radio enabled - */ - if (bcm->current_core->rev >= 3) - return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) - & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK) - == 0) ? 1 : 0; - else - return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) - & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK) - == 0) ? 0 : 1; -} - -int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, - int synthetic_pu_workaround); - -void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); -void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, - u16 baseband_attenuation, u16 attenuation, - u16 txpower); - -u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm); -u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm); -u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm); - -void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); - -void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); - -u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel); -u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm); - -int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode); - -void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm); -void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm); -s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset); -void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val); -void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); -void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); - -void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); -u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm); - -#endif /* BCM43xx_RADIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c deleted file mode 100644 index 8ab5f93d192..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - SYSFS support routines - - Copyright (c) 2006 Michael Buesch <mbuesch@freenet.de> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx_sysfs.h" -#include "bcm43xx.h" -#include "bcm43xx_main.h" -#include "bcm43xx_radio.h" - -#include <linux/capability.h> - - -#define GENERIC_FILESIZE 64 - - -static int get_integer(const char *buf, size_t count) -{ - char tmp[10 + 1] = { 0 }; - int ret = -EINVAL; - - if (count == 0) - goto out; - count = min(count, (size_t)10); - memcpy(tmp, buf, count); - ret = simple_strtol(tmp, NULL, 10); -out: - return ret; -} - -static int get_boolean(const char *buf, size_t count) -{ - if (count != 0) { - if (buf[0] == '1') - return 1; - if (buf[0] == '0') - return 0; - if (count >= 4 && memcmp(buf, "true", 4) == 0) - return 1; - if (count >= 5 && memcmp(buf, "false", 5) == 0) - return 0; - if (count >= 3 && memcmp(buf, "yes", 3) == 0) - return 1; - if (count >= 2 && memcmp(buf, "no", 2) == 0) - return 0; - if (count >= 2 && memcmp(buf, "on", 2) == 0) - return 1; - if (count >= 3 && memcmp(buf, "off", 3) == 0) - return 0; - } - return -EINVAL; -} - -static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) -{ - int i, pos = 0; - - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - pos += snprintf(buf + pos, buf_len - pos - 1, - "%04X", swab16(sprom[i]) & 0xFFFF); - } - pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); - - return pos + 1; -} - -static int hex2sprom(u16 *sprom, const char *dump, size_t len) -{ - char tmp[5] = { 0 }; - int cnt = 0; - unsigned long parsed; - - if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) - return -EINVAL; - - while (cnt < BCM43xx_SPROM_SIZE) { - memcpy(tmp, dump, 4); - dump += 4; - parsed = simple_strtoul(tmp, NULL, 16); - sprom[cnt++] = swab16((u16)parsed); - } - - return 0; -} - -static ssize_t bcm43xx_attr_sprom_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - u16 *sprom; - unsigned long flags; - int err; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE); - sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), - GFP_KERNEL); - if (!sprom) - return -ENOMEM; - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - err = bcm43xx_sprom_read(bcm, sprom); - if (!err) - err = sprom2hex(sprom, buf, PAGE_SIZE); - mmiowb(); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - kfree(sprom); - - return err; -} - -static ssize_t bcm43xx_attr_sprom_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - u16 *sprom; - unsigned long flags; - int err; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), - GFP_KERNEL); - if (!sprom) - return -ENOMEM; - err = hex2sprom(sprom, buf, count); - if (err) - goto out_kfree; - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - spin_lock(&bcm->leds_lock); - err = bcm43xx_sprom_write(bcm, sprom); - mmiowb(); - spin_unlock(&bcm->leds_lock); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); -out_kfree: - kfree(sprom); - - return err ? err : count; - -} - -static DEVICE_ATTR(sprom, 0600, - bcm43xx_attr_sprom_show, - bcm43xx_attr_sprom_store); - -static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - ssize_t count = 0; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&bcm->mutex); - - switch (bcm43xx_current_radio(bcm)->interfmode) { - case BCM43xx_RADIO_INTERFMODE_NONE: - count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); - break; - case BCM43xx_RADIO_INTERFMODE_NONWLAN: - count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n"); - break; - case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n"); - break; - default: - assert(0); - } - - mutex_unlock(&bcm->mutex); - - return count; - -} - -static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - unsigned long flags; - int err; - int mode; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mode = get_integer(buf, count); - switch (mode) { - case 0: - mode = BCM43xx_RADIO_INTERFMODE_NONE; - break; - case 1: - mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; - break; - case 2: - mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; - break; - case 3: - mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; - break; - default: - return -EINVAL; - } - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - - err = bcm43xx_radio_set_interference_mitigation(bcm, mode); - if (err) { - printk(KERN_ERR PFX "Interference Mitigation not " - "supported by device\n"); - } - mmiowb(); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return err ? err : count; -} - -static DEVICE_ATTR(interference, 0644, - bcm43xx_attr_interfmode_show, - bcm43xx_attr_interfmode_store); - -static ssize_t bcm43xx_attr_preamble_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - ssize_t count; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&bcm->mutex); - - if (bcm->short_preamble) - count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); - else - count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); - - mutex_unlock(&bcm->mutex); - - return count; -} - -static ssize_t bcm43xx_attr_preamble_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - unsigned long flags; - int value; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - value = get_boolean(buf, count); - if (value < 0) - return value; - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - - bcm->short_preamble = !!value; - - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return count; -} - -static DEVICE_ATTR(shortpreamble, 0644, - bcm43xx_attr_preamble_show, - bcm43xx_attr_preamble_store); - -static ssize_t bcm43xx_attr_phymode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - int phytype; - int err = -EINVAL; - - if (count < 1) - goto out; - switch (buf[0]) { - case 'a': case 'A': - phytype = BCM43xx_PHYTYPE_A; - break; - case 'b': case 'B': - phytype = BCM43xx_PHYTYPE_B; - break; - case 'g': case 'G': - phytype = BCM43xx_PHYTYPE_G; - break; - default: - goto out; - } - - bcm43xx_cancel_work(bcm); - mutex_lock(&(bcm)->mutex); - err = bcm43xx_select_wireless_core(bcm, phytype); - if (!err) - bcm43xx_periodic_tasks_setup(bcm); - mutex_unlock(&(bcm)->mutex); - if (err == -ESRCH) - err = -ENODEV; - -out: - return err ? err : count; -} - -static ssize_t bcm43xx_attr_phymode_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct bcm43xx_private *bcm = dev_to_bcm(dev); - ssize_t count = 0; - - mutex_lock(&(bcm)->mutex); - switch (bcm43xx_current_phy(bcm)->type) { - case BCM43xx_PHYTYPE_A: - snprintf(buf, PAGE_SIZE, "A"); - break; - case BCM43xx_PHYTYPE_B: - snprintf(buf, PAGE_SIZE, "B"); - break; - case BCM43xx_PHYTYPE_G: - snprintf(buf, PAGE_SIZE, "G"); - break; - default: - assert(0); - } - mutex_unlock(&(bcm)->mutex); - - return count; -} - -static DEVICE_ATTR(phymode, 0644, - bcm43xx_attr_phymode_show, - bcm43xx_attr_phymode_store); - -static ssize_t bcm43xx_attr_microcode_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - unsigned long flags; - struct bcm43xx_private *bcm = dev_to_bcm(dev); - ssize_t count = 0; - u16 status; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&(bcm)->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, - BCM43xx_UCODE_STATUS); - - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&(bcm)->mutex); - switch (status) { - case 0x0000: - count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n", - status); - break; - case 0x0001: - count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n", - status); - break; - case 0x0002: - count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n", - status); - break; - case 0x0003: - count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n", - status); - break; - case 0x0004: - count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n", - status); - break; - default: - count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n", - status); - break; - } - - return count; -} - -static DEVICE_ATTR(microcodestatus, 0444, - bcm43xx_attr_microcode_show, - NULL); - -int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) -{ - struct device *dev = &bcm->pci_dev->dev; - int err; - - assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - - err = device_create_file(dev, &dev_attr_sprom); - if (err) - goto out; - err = device_create_file(dev, &dev_attr_interference); - if (err) - goto err_remove_sprom; - err = device_create_file(dev, &dev_attr_shortpreamble); - if (err) - goto err_remove_interfmode; - err = device_create_file(dev, &dev_attr_phymode); - if (err) - goto err_remove_shortpreamble; - err = device_create_file(dev, &dev_attr_microcodestatus); - if (err) - goto err_remove_phymode; - -out: - return err; -err_remove_phymode: - device_remove_file(dev, &dev_attr_phymode); -err_remove_shortpreamble: - device_remove_file(dev, &dev_attr_shortpreamble); -err_remove_interfmode: - device_remove_file(dev, &dev_attr_interference); -err_remove_sprom: - device_remove_file(dev, &dev_attr_sprom); - goto out; -} - -void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) -{ - struct device *dev = &bcm->pci_dev->dev; - - device_remove_file(dev, &dev_attr_microcodestatus); - device_remove_file(dev, &dev_attr_phymode); - device_remove_file(dev, &dev_attr_shortpreamble); - device_remove_file(dev, &dev_attr_interference); - device_remove_file(dev, &dev_attr_sprom); -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h deleted file mode 100644 index cc701df71e2..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef BCM43xx_SYSFS_H_ -#define BCM43xx_SYSFS_H_ - -struct bcm43xx_private; - -int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); -void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm); - -#endif /* BCM43xx_SYSFS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c deleted file mode 100644 index 6acfdc49dcc..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ /dev/null @@ -1,1035 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include <linux/wireless.h> -#include <net/iw_handler.h> -#include <net/ieee80211softmac.h> -#include <net/ieee80211softmac_wx.h> -#include <linux/capability.h> -#include <linux/delay.h> - -#include "bcm43xx.h" -#include "bcm43xx_wx.h" -#include "bcm43xx_main.h" -#include "bcm43xx_radio.h" -#include "bcm43xx_phy.h" - - -/* The WIRELESS_EXT version, which is implemented by this driver. */ -#define BCM43xx_WX_VERSION 18 - -#define MAX_WX_STRING 80 - -static int bcm43xx_wx_get_name(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int i; - struct bcm43xx_phyinfo *phy; - char suffix[7] = { 0 }; - int have_a = 0, have_b = 0, have_g = 0; - - mutex_lock(&bcm->mutex); - for (i = 0; i < bcm->nr_80211_available; i++) { - phy = &(bcm->core_80211_ext[i].phy); - switch (phy->type) { - case BCM43xx_PHYTYPE_A: - have_a = 1; - break; - case BCM43xx_PHYTYPE_G: - have_g = 1; - case BCM43xx_PHYTYPE_B: - have_b = 1; - break; - default: - assert(0); - } - } - mutex_unlock(&bcm->mutex); - - i = 0; - if (have_a) { - suffix[i++] = 'a'; - suffix[i++] = '/'; - } - if (have_b) { - suffix[i++] = 'b'; - suffix[i++] = '/'; - } - if (have_g) { - suffix[i++] = 'g'; - suffix[i++] = '/'; - } - if (i != 0) - suffix[i - 1] = '\0'; - - snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix); - - return 0; -} - -static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - u8 channel; - s8 expon; - int freq; - int err = -EINVAL; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - - if ((data->freq.e == 0) && - (data->freq.m >= 0) && (data->freq.m <= 1000)) { - channel = data->freq.m; - freq = bcm43xx_channel_to_freq(bcm, channel); - } else { - freq = data->freq.m; - expon = 6 - data->freq.e; - while (--expon >= 0) /* scale down the frequency to MHz */ - freq /= 10; - assert(freq > 1000); - channel = bcm43xx_freq_to_channel(bcm, freq); - } - if (!ieee80211_is_valid_channel(bcm->ieee, channel)) - goto out_unlock; - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - //ieee80211softmac_disassoc(softmac, $REASON); - bcm43xx_mac_suspend(bcm); - err = bcm43xx_radio_selectchannel(bcm, channel, 0); - bcm43xx_mac_enable(bcm); - } else { - bcm43xx_current_radio(bcm)->initial_channel = channel; - err = 0; - } -out_unlock: - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct bcm43xx_radioinfo *radio; - int err = -ENODEV; - u16 channel; - - mutex_lock(&bcm->mutex); - radio = bcm43xx_current_radio(bcm); - channel = radio->channel; - if (channel == 0xFF) { - channel = radio->initial_channel; - if (channel == 0xFF) - goto out_unlock; - } - assert(channel > 0 && channel <= 1000); - data->freq.e = 1; - data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000; - data->freq.flags = 1; - - err = 0; -out_unlock: - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_set_mode(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int mode; - - mode = data->mode; - if (mode == IW_MODE_AUTO) - mode = BCM43xx_INITIAL_IWMODE; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - if (bcm->ieee->iw_mode != mode) - bcm43xx_set_iwmode(bcm, mode); - } else - bcm->ieee->iw_mode = mode; - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_get_mode(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - - mutex_lock(&bcm->mutex); - data->mode = bcm->ieee->iw_mode; - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo; - int i, j; - struct bcm43xx_phyinfo *phy; - - data->data.length = sizeof(*range); - memset(range, 0, sizeof(*range)); - - //TODO: What about 802.11b? - /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */ - range->throughput = 27 * 1000 * 1000; - - range->max_qual.qual = 100; - range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */ - range->max_qual.noise = 146; - range->max_qual.updated = IW_QUAL_ALL_UPDATED; - - range->avg_qual.qual = 50; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; - range->avg_qual.updated = IW_QUAL_ALL_UPDATED; - - range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; - range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = WEP_KEYS; - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = BCM43xx_WX_VERSION; - - range->enc_capa = IW_ENC_CAPA_WPA | - IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | - IW_ENC_CAPA_CIPHER_CCMP; - - mutex_lock(&bcm->mutex); - phy = bcm43xx_current_phy(bcm); - - range->num_bitrates = 0; - i = 0; - if (phy->type == BCM43xx_PHYTYPE_A || - phy->type == BCM43xx_PHYTYPE_G) { - range->num_bitrates = 8; - range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000; - range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000; - } - if (phy->type == BCM43xx_PHYTYPE_B || - phy->type == BCM43xx_PHYTYPE_G) { - range->num_bitrates += 4; - range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000; - range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000; - range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000; - range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000; - } - - geo = ieee80211_get_geo(bcm->ieee); - range->num_channels = geo->a_channels + geo->bg_channels; - j = 0; - for (i = 0; i < geo->a_channels; i++) { - if (j == IW_MAX_FREQUENCIES) - break; - range->freq[j].i = j + 1; - range->freq[j].m = geo->a[i].freq * 100000; - range->freq[j].e = 1; - j++; - } - for (i = 0; i < geo->bg_channels; i++) { - if (j == IW_MAX_FREQUENCIES) - break; - range->freq[j].i = j + 1; - range->freq[j].m = geo->bg[i].freq * 100000; - range->freq[j].e = 1; - j++; - } - range->num_frequency = j; - - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_set_nick(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - size_t len; - - mutex_lock(&bcm->mutex); - len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); - memcpy(bcm->nick, extra, len); - bcm->nick[len] = '\0'; - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_get_nick(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - size_t len; - - mutex_lock(&bcm->mutex); - len = strlen(bcm->nick); - memcpy(extra, bcm->nick, len); - data->data.length = (__u16)len; - data->data.flags = 1; - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_set_rts(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int err = -EINVAL; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (data->rts.disabled) { - bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; - err = 0; - } else { - if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD && - data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) { - bcm->rts_threshold = data->rts.value; - err = 0; - } - } - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_get_rts(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - - mutex_lock(&bcm->mutex); - data->rts.value = bcm->rts_threshold; - data->rts.fixed = 0; - data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_set_frag(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int err = -EINVAL; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (data->frag.disabled) { - bcm->ieee->fts = MAX_FRAG_THRESHOLD; - err = 0; - } else { - if (data->frag.value >= MIN_FRAG_THRESHOLD && - data->frag.value <= MAX_FRAG_THRESHOLD) { - bcm->ieee->fts = data->frag.value & ~0x1; - err = 0; - } - } - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_get_frag(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - - mutex_lock(&bcm->mutex); - data->frag.value = bcm->ieee->fts; - data->frag.fixed = 0; - data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct bcm43xx_radioinfo *radio; - struct bcm43xx_phyinfo *phy; - unsigned long flags; - int err = -ENODEV; - u16 maxpower; - - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { - printk(KERN_ERR PFX "TX power not in dBm.\n"); - return -EOPNOTSUPP; - } - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) - goto out_unlock; - radio = bcm43xx_current_radio(bcm); - phy = bcm43xx_current_phy(bcm); - if (data->txpower.disabled != (!(radio->enabled))) { - if (data->txpower.disabled) - bcm43xx_radio_turn_off(bcm); - else - bcm43xx_radio_turn_on(bcm); - } - if (data->txpower.value > 0) { - /* desired and maxpower dBm values are in Q5.2 */ - if (phy->type == BCM43xx_PHYTYPE_A) - maxpower = bcm->sprom.maxpower_aphy; - else - maxpower = bcm->sprom.maxpower_bgphy; - radio->txpower_desired = limit_value(data->txpower.value << 2, - 0, maxpower); - bcm43xx_phy_xmitpower(bcm); - } - err = 0; - -out_unlock: - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct bcm43xx_radioinfo *radio; - int err = -ENODEV; - - mutex_lock(&bcm->mutex); - if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) - goto out_unlock; - radio = bcm43xx_current_radio(bcm); - /* desired dBm value is in Q5.2 */ - data->txpower.value = radio->txpower_desired >> 2; - data->txpower.fixed = 1; - data->txpower.flags = IW_TXPOW_DBM; - data->txpower.disabled = !(radio->enabled); - - err = 0; -out_unlock: - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_set_encoding(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err; - - err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); - - return err; -} - -static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err; - - err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); - - return err; -} - -static int bcm43xx_wx_get_encoding(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err; - - err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); - - return err; -} - -static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err; - - err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); - - return err; -} - -static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int mode, err = 0; - - mode = *((int *)extra); - switch (mode) { - case 0: - mode = BCM43xx_RADIO_INTERFMODE_NONE; - break; - case 1: - mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; - break; - case 2: - mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; - break; - case 3: - mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; - break; - default: - printk(KERN_ERR PFX "set_interfmode allowed parameters are: " - "0 => None, 1 => Non-WLAN, 2 => WLAN, " - "3 => Auto-WLAN\n"); - return -EINVAL; - } - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - err = bcm43xx_radio_set_interference_mitigation(bcm, mode); - if (err) { - printk(KERN_ERR PFX "Interference Mitigation not " - "supported by device\n"); - } - } else { - if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) { - printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN " - "not supported while the interface is down.\n"); - err = -ENODEV; - } else - bcm43xx_current_radio(bcm)->interfmode = mode; - } - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return err; -} - -static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int mode; - - mutex_lock(&bcm->mutex); - mode = bcm43xx_current_radio(bcm)->interfmode; - mutex_unlock(&bcm->mutex); - - switch (mode) { - case BCM43xx_RADIO_INTERFMODE_NONE: - strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING); - break; - case BCM43xx_RADIO_INTERFMODE_NONWLAN: - strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING); - break; - case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING); - break; - default: - assert(0); - } - data->data.length = strlen(extra) + 1; - - return 0; -} - -static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int on; - - on = *((int *)extra); - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - bcm->short_preamble = !!on; - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int on; - - mutex_lock(&bcm->mutex); - on = bcm->short_preamble; - mutex_unlock(&bcm->mutex); - - if (on) - strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); - else - strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING); - data->data.length = strlen(extra) + 1; - - return 0; -} - -static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int on; - - on = *((int *)extra); - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - bcm->ieee->host_encrypt = !!on; - bcm->ieee->host_decrypt = !!on; - bcm->ieee->host_build_iv = !on; - bcm->ieee->host_strip_iv_icv = !on; - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - - return 0; -} - -static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int on; - - mutex_lock(&bcm->mutex); - on = bcm->ieee->host_encrypt; - mutex_unlock(&bcm->mutex); - - if (on) - strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); - else - strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); - data->data.length = strlen(extra + 1); - - return 0; -} - -/* Enough buffer to hold a hexdump of the sprom data. */ -#define SPROM_BUFFERSIZE 512 - -static int sprom2hex(const u16 *sprom, char *dump) -{ - int i, pos = 0; - - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1, - "%04X", swab16(sprom[i]) & 0xFFFF); - } - - return pos + 1; -} - -static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) -{ - char tmp[5] = { 0 }; - int cnt = 0; - unsigned long parsed; - - if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) - return -EINVAL; - while (cnt < BCM43xx_SPROM_SIZE) { - memcpy(tmp, dump, 4); - dump += 4; - parsed = simple_strtoul(tmp, NULL, 16); - sprom[cnt++] = swab16((u16)parsed); - } - - return 0; -} - -static int bcm43xx_wx_sprom_read(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err = -EPERM; - u16 *sprom; - unsigned long flags; - - if (!capable(CAP_SYS_RAWIO)) - goto out; - - err = -ENOMEM; - sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), - GFP_KERNEL); - if (!sprom) - goto out; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - err = -ENODEV; - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) - err = bcm43xx_sprom_read(bcm, sprom); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); - if (!err) - data->data.length = sprom2hex(sprom, extra); - kfree(sprom); -out: - return err; -} - -static int bcm43xx_wx_sprom_write(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err = -EPERM; - u16 *sprom; - unsigned long flags; - char *input; - unsigned int len; - - if (!capable(CAP_SYS_RAWIO)) - goto out; - - err = -ENOMEM; - sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), - GFP_KERNEL); - if (!sprom) - goto out; - - len = data->data.length; - extra[len - 1] = '\0'; - input = strchr(extra, ':'); - if (input) { - input++; - len -= input - extra; - } else - input = extra; - err = hex2sprom(sprom, input, len); - if (err) - goto out_kfree; - - mutex_lock(&bcm->mutex); - spin_lock_irqsave(&bcm->irq_lock, flags); - spin_lock(&bcm->leds_lock); - err = -ENODEV; - if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) - err = bcm43xx_sprom_write(bcm, sprom); - spin_unlock(&bcm->leds_lock); - spin_unlock_irqrestore(&bcm->irq_lock, flags); - mutex_unlock(&bcm->mutex); -out_kfree: - kfree(sprom); -out: - return err; -} - -/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ - -static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev) -{ - struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); - struct iw_statistics *wstats; - struct ieee80211_network *network = NULL; - static int tmp_level = 0; - static int tmp_qual = 0; - unsigned long flags; - - wstats = &bcm->stats.wstats; - if (!mac->associnfo.associated) { - wstats->miss.beacon = 0; -// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here? - wstats->discard.retries = 0; -// bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question - wstats->discard.nwid = 0; -// bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto - wstats->discard.code = 0; -// bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here - wstats->discard.fragment = 0; - wstats->discard.misc = 0; - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = 7; - wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - return wstats; - } - /* fill in the real statistics when iface associated */ - spin_lock_irqsave(&mac->ieee->lock, flags); - list_for_each_entry(network, &mac->ieee->network_list, list) { - if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) { - if (!tmp_level) { /* get initial values */ - tmp_level = network->stats.signal; - tmp_qual = network->stats.rssi; - } else { /* smooth results */ - tmp_level = (15 * tmp_level + network->stats.signal)/16; - tmp_qual = (15 * tmp_qual + network->stats.rssi)/16; - } - break; - } - } - spin_unlock_irqrestore(&mac->ieee->lock, flags); - wstats->qual.level = tmp_level; - wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX; - wstats->qual.noise = bcm->stats.noise; - wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; - wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; - wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; - wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments; - wstats->discard.misc = 0; // FIXME - wstats->miss.beacon = 0; // FIXME - return wstats; -} - - -#ifdef WX -# undef WX -#endif -#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] -static const iw_handler bcm43xx_wx_handlers[] = { - /* Wireless Identification */ - WX(SIOCGIWNAME) = bcm43xx_wx_get_name, - /* Basic operations */ - WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq, - WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq, - WX(SIOCSIWMODE) = bcm43xx_wx_set_mode, - WX(SIOCGIWMODE) = bcm43xx_wx_get_mode, - /* Informative stuff */ - WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams, - /* Access Point manipulation */ - WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, - WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, - WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, - WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, - /* 802.11 specific support */ - WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, - WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, - WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick, - WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick, - /* Other parameters */ - WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, - WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, - WX(SIOCSIWRTS) = bcm43xx_wx_set_rts, - WX(SIOCGIWRTS) = bcm43xx_wx_get_rts, - WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag, - WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag, - WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower, - WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower, -//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry, -//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry, - /* Encoding */ - WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding, - WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding, - WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext, - WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext, - /* Power saving */ -//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power, -//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power, - WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, - WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, - WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, - WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, -}; -#undef WX - -static const iw_handler bcm43xx_priv_wx_handlers[] = { - /* Set Interference Mitigation Mode. */ - bcm43xx_wx_set_interfmode, - /* Get Interference Mitigation Mode. */ - bcm43xx_wx_get_interfmode, - /* Enable/Disable Short Preamble mode. */ - bcm43xx_wx_set_shortpreamble, - /* Get Short Preamble mode. */ - bcm43xx_wx_get_shortpreamble, - /* Enable/Disable Software Encryption mode */ - bcm43xx_wx_set_swencryption, - /* Get Software Encryption mode */ - bcm43xx_wx_get_swencryption, - /* Write SRPROM data. */ - bcm43xx_wx_sprom_write, - /* Read SPROM data. */ - bcm43xx_wx_sprom_read, -}; - -#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0) -#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1) -#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2) -#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3) -#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4) -#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5) -#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6) -#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7) - -#define PRIV_WX_DUMMY(ioctl) \ - { \ - .cmd = (ioctl), \ - .name = "__unused" \ - } - -static const struct iw_priv_args bcm43xx_priv_wx_args[] = { - { - .cmd = PRIV_WX_SET_INTERFMODE, - .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_interfmode", - }, - { - .cmd = PRIV_WX_GET_INTERFMODE, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_interfmode", - }, - { - .cmd = PRIV_WX_SET_SHORTPREAMBLE, - .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_shortpreamb", - }, - { - .cmd = PRIV_WX_GET_SHORTPREAMBLE, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_shortpreamb", - }, - { - .cmd = PRIV_WX_SET_SWENCRYPTION, - .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_swencrypt", - }, - { - .cmd = PRIV_WX_GET_SWENCRYPTION, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_swencrypt", - }, - { - .cmd = PRIV_WX_SPROM_WRITE, - .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE, - .name = "write_sprom", - }, - { - .cmd = PRIV_WX_SPROM_READ, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE, - .name = "read_sprom", - }, -}; - -const struct iw_handler_def bcm43xx_wx_handlers_def = { - .standard = bcm43xx_wx_handlers, - .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers), - .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers), - .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), - .private = bcm43xx_priv_wx_handlers, - .private_args = bcm43xx_priv_wx_args, - .get_wireless_stats = bcm43xx_get_wireless_stats, -}; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h deleted file mode 100644 index 1f29ff3aa4c..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - Some parts of the code in this file are derived from the ipw2200 - driver Copyright(c) 2003 - 2004 Intel Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#ifndef BCM43xx_WX_H_ -#define BCM43xx_WX_H_ - -extern const struct iw_handler_def bcm43xx_wx_handlers_def; - -#endif /* BCM43xx_WX_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c deleted file mode 100644 index f79fe11f9e8..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - - Broadcom BCM43xx wireless driver - - Transmission (TX/RX) related functions. - - Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mbuesch@freenet.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "bcm43xx_xmit.h" - -#include <linux/etherdevice.h> - - -/* Extract the bitrate out of a CCK PLCP header. */ -static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp) -{ - switch (plcp->raw[0]) { - case 0x0A: - return IEEE80211_CCK_RATE_1MB; - case 0x14: - return IEEE80211_CCK_RATE_2MB; - case 0x37: - return IEEE80211_CCK_RATE_5MB; - case 0x6E: - return IEEE80211_CCK_RATE_11MB; - } - assert(0); - return 0; -} - -/* Extract the bitrate out of an OFDM PLCP header. */ -static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp) -{ - switch (plcp->raw[0] & 0xF) { - case 0xB: - return IEEE80211_OFDM_RATE_6MB; - case 0xF: - return IEEE80211_OFDM_RATE_9MB; - case 0xA: - return IEEE80211_OFDM_RATE_12MB; - case 0xE: - return IEEE80211_OFDM_RATE_18MB; - case 0x9: - return IEEE80211_OFDM_RATE_24MB; - case 0xD: - return IEEE80211_OFDM_RATE_36MB; - case 0x8: - return IEEE80211_OFDM_RATE_48MB; - case 0xC: - return IEEE80211_OFDM_RATE_54MB; - } - assert(0); - return 0; -} - -u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_CCK_RATE_1MB: - return 0x0A; - case IEEE80211_CCK_RATE_2MB: - return 0x14; - case IEEE80211_CCK_RATE_5MB: - return 0x37; - case IEEE80211_CCK_RATE_11MB: - return 0x6E; - } - assert(0); - return 0; -} - -u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_OFDM_RATE_6MB: - return 0xB; - case IEEE80211_OFDM_RATE_9MB: - return 0xF; - case IEEE80211_OFDM_RATE_12MB: - return 0xA; - case IEEE80211_OFDM_RATE_18MB: - return 0xE; - case IEEE80211_OFDM_RATE_24MB: - return 0x9; - case IEEE80211_OFDM_RATE_36MB: - return 0xD; - case IEEE80211_OFDM_RATE_48MB: - return 0x8; - case IEEE80211_OFDM_RATE_54MB: - return 0xC; - } - assert(0); - return 0; -} - -static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, - const u16 octets, const u8 bitrate, - const int ofdm_modulation) -{ - __le32 *data = &(plcp->data); - __u8 *raw = plcp->raw; - - if (ofdm_modulation) { - u32 val = bcm43xx_plcp_get_ratecode_ofdm(bitrate); - assert(!(octets & 0xF000)); - val |= (octets << 5); - *data = cpu_to_le32(val); - } else { - u32 plen; - - plen = octets * 16 / bitrate; - if ((octets * 16 % bitrate) > 0) { - plen++; - if ((bitrate == IEEE80211_CCK_RATE_11MB) - && ((octets * 8 % 11) < 4)) { - raw[1] = 0x84; - } else - raw[1] = 0x04; - } else - raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); - raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); - } -} - -static u8 bcm43xx_calc_fallback_rate(u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_CCK_RATE_1MB: - return IEEE80211_CCK_RATE_1MB; - case IEEE80211_CCK_RATE_2MB: - return IEEE80211_CCK_RATE_1MB; - case IEEE80211_CCK_RATE_5MB: - return IEEE80211_CCK_RATE_2MB; - case IEEE80211_CCK_RATE_11MB: - return IEEE80211_CCK_RATE_5MB; - case IEEE80211_OFDM_RATE_6MB: - return IEEE80211_CCK_RATE_5MB; - case IEEE80211_OFDM_RATE_9MB: - return IEEE80211_OFDM_RATE_6MB; - case IEEE80211_OFDM_RATE_12MB: - return IEEE80211_OFDM_RATE_9MB; - case IEEE80211_OFDM_RATE_18MB: - return IEEE80211_OFDM_RATE_12MB; - case IEEE80211_OFDM_RATE_24MB: - return IEEE80211_OFDM_RATE_18MB; - case IEEE80211_OFDM_RATE_36MB: - return IEEE80211_OFDM_RATE_24MB; - case IEEE80211_OFDM_RATE_48MB: - return IEEE80211_OFDM_RATE_36MB; - case IEEE80211_OFDM_RATE_54MB: - return IEEE80211_OFDM_RATE_48MB; - } - assert(0); - return 0; -} - -static -__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header, - u8 bitrate) -{ - const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl); - __le16 duration_id = wireless_header->duration_id; - - switch (WLAN_FC_GET_TYPE(frame_ctl)) { - case IEEE80211_FTYPE_DATA: - case IEEE80211_FTYPE_MGMT: - //TODO: Steal the code from ieee80211, once it is completed there. - break; - case IEEE80211_FTYPE_CTL: - /* Use the original duration/id. */ - break; - default: - assert(0); - } - - return duration_id; -} - -static inline -u16 ceiling_div(u16 dividend, u16 divisor) -{ - return ((dividend + divisor - 1) / divisor); -} - -static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, - struct bcm43xx_txhdr *txhdr, - u16 *flags, - u8 bitrate, - const struct ieee80211_hdr_4addr *wlhdr) -{ - u16 fctl; - u16 dur; - u8 fallback_bitrate; - int ofdm_modulation; - int fallback_ofdm_modulation; -// u8 *sa, *da; - u16 flen; - -//FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); -//FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr); - fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); - ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); - fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); - - flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN, - bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp), - flen, bitrate, - !ieee80211_is_cck_rate(bitrate)); - bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp), - flen, fallback_bitrate, - !ieee80211_is_cck_rate(fallback_bitrate)); - fctl = IEEE80211_FTYPE_CTL; - fctl |= IEEE80211_STYPE_RTS; - dur = le16_to_cpu(wlhdr->duration_id); -/*FIXME: should we test for dur==0 here and let it unmodified in this case? - * The following assert checks for this case... - */ -assert(dur); -/*FIXME: The duration calculation is not really correct. - * I am not 100% sure which bitrate to use. We use the RTS rate here, - * but this is likely to be wrong. - */ - if (phy->type == BCM43xx_PHYTYPE_A) { - /* Three times SIFS */ - dur += 16 * 3; - /* Add ACK duration. */ - dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, - bitrate * 4); - /* Add CTS duration. */ - dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, - bitrate * 4); - } else { - /* Three times SIFS */ - dur += 10 * 3; - /* Add ACK duration. */ - dur += ceiling_div(8 * (14 /*bytes*/) * 10, - bitrate); - /* Add CTS duration. */ - dur += ceiling_div(8 * (14 /*bytes*/) * 10, - bitrate); - } - - txhdr->rts_cts_frame_control = cpu_to_le16(fctl); - txhdr->rts_cts_dur = cpu_to_le16(dur); -//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); -//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); - memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! -// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); - - *flags |= BCM43xx_TXHDRFLAG_RTSCTS; - *flags |= BCM43xx_TXHDRFLAG_RTS; - if (ofdm_modulation) - *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM; - if (fallback_ofdm_modulation) - *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM; -} - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - const unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie) -{ - const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; - const struct ieee80211_security *secinfo = &bcm->ieee->sec; - u8 bitrate; - u8 fallback_bitrate; - int ofdm_modulation; - int fallback_ofdm_modulation; - u16 plcp_fragment_len = fragment_len; - u16 flags = 0; - u16 control = 0; - u16 wsec_rate = 0; - u16 encrypt_frame; - const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl)); - const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT); - - /* Now construct the TX header. */ - memset(txhdr, 0, sizeof(*txhdr)); - - bitrate = ieee80211softmac_suggest_txrate(bcm->softmac, - is_multicast_ether_addr(wireless_header->addr1), is_mgt); - ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); - fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); - fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); - - /* Set Frame Control from 80211 header. */ - txhdr->frame_control = wireless_header->frame_ctl; - /* Copy address1 from 80211 header. */ - memcpy(txhdr->mac1, wireless_header->addr1, 6); - /* Set the fallback duration ID. */ - txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header, - fallback_bitrate); - /* Set the cookie (used as driver internal ID for the frame) */ - txhdr->cookie = cpu_to_le16(cookie); - - /* Hardware appends FCS. */ - plcp_fragment_len += IEEE80211_FCS_LEN; - - /* Hardware encryption. */ - encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; - if (encrypt_frame && !bcm->ieee->host_encrypt) { - const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; - memcpy(txhdr->wep_iv, hdr->payload, 4); - /* Hardware appends ICV. */ - plcp_fragment_len += 4; - - wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) - & BCM43xx_TXHDR_WSEC_ALGO_MASK; - wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) - & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; - } - - /* Generate the PLCP header and the fallback PLCP header. */ - bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), - plcp_fragment_len, - bitrate, ofdm_modulation); - bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len, - fallback_bitrate, fallback_ofdm_modulation); - - /* Set the CONTROL field */ - if (ofdm_modulation) - control |= BCM43xx_TXHDRCTL_OFDM; - if (bcm->short_preamble) //FIXME: could be the other way around, please test - control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; - control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) - & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; - - /* Set the FLAGS field */ - if (!is_multicast_ether_addr(wireless_header->addr1) && - !is_broadcast_ether_addr(wireless_header->addr1)) - flags |= BCM43xx_TXHDRFLAG_EXPECTACK; - if (1 /* FIXME: PS poll?? */) - flags |= 0x10; // FIXME: unknown meaning. - if (fallback_ofdm_modulation) - flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; - if (is_first_fragment) - flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; - - /* Set WSEC/RATE field */ - wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT) - & BCM43xx_TXHDR_RATE_MASK; - - /* Generate the RTS/CTS packet, if required. */ - /* FIXME: We should first try with CTS-to-self, - * if we are on 80211g. If we get too many - * failures (hidden nodes), we should switch back to RTS/CTS. - */ - if (0/*FIXME txctl->use_rts_cts*/) { - bcm43xx_generate_rts(phy, txhdr, &flags, - 0/*FIXME txctl->rts_cts_rate*/, - wireless_header); - } - - txhdr->flags = cpu_to_le16(flags); - txhdr->control = cpu_to_le16(control); - txhdr->wsec_rate = cpu_to_le16(wsec_rate); -} - -static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi, int ofdm, - int adjust_2053, int adjust_2050) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - s32 tmp; - - switch (radio->version) { - case 0x2050: - if (ofdm) { - tmp = in_rssi; - if (tmp > 127) - tmp -= 256; - tmp *= 73; - tmp /= 64; - if (adjust_2050) - tmp += 25; - else - tmp -= 3; - } else { - if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { - if (in_rssi > 63) - in_rssi = 63; - tmp = radio->nrssi_lt[in_rssi]; - tmp = 31 - tmp; - tmp *= -131; - tmp /= 128; - tmp -= 57; - } else { - tmp = in_rssi; - tmp = 31 - tmp; - tmp *= -149; - tmp /= 128; - tmp -= 68; - } - if (phy->type == BCM43xx_PHYTYPE_G && - adjust_2050) - tmp += 25; - } - break; - case 0x2060: - if (in_rssi > 127) - tmp = in_rssi - 256; - else - tmp = in_rssi; - break; - default: - tmp = in_rssi; - tmp -= 11; - tmp *= 103; - tmp /= 64; - if (adjust_2053) - tmp -= 109; - else - tmp -= 83; - } - - return (s8)tmp; -} - -//TODO -#if 0 -static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - s8 ret; - - if (phy->type == BCM43xx_PHYTYPE_A) { - //TODO: Incomplete specs. - ret = 0; - } else - ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); - - return ret; -} -#endif - -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr) -{ - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_plcp_hdr4 *plcp; - struct ieee80211_rx_stats stats; - struct ieee80211_hdr_4addr *wlhdr; - u16 frame_ctl; - int is_packet_for_us = 0; - int err = -EINVAL; - const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); - const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); - const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); - const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); - - if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { - plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); - /* Skip two unknown bytes and the PLCP header. */ - skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); - } else { - plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); - /* Skip the PLCP header. */ - skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); - } - /* The SKB contains the PAYLOAD (wireless header + data) - * at this point. The FCS at the end is stripped. - */ - - memset(&stats, 0, sizeof(stats)); - stats.mac_time = le16_to_cpu(rxhdr->mactime); - stats.rssi = rxhdr->rssi; - stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, - !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), - !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); - stats.noise = bcm->stats.noise; - if (is_ofdm) - stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); - else - stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); - stats.received_channel = radio->channel; - stats.mask = IEEE80211_STATMASK_SIGNAL | - IEEE80211_STATMASK_NOISE | - IEEE80211_STATMASK_RATE | - IEEE80211_STATMASK_RSSI; - if (phy->type == BCM43xx_PHYTYPE_A) - stats.freq = IEEE80211_52GHZ_BAND; - else - stats.freq = IEEE80211_24GHZ_BAND; - stats.len = skb->len; - - bcm->stats.last_rx = jiffies; - if (bcm->ieee->iw_mode == IW_MODE_MONITOR) { - err = ieee80211_rx(bcm->ieee, skb, &stats); - return (err == 0) ? -EINVAL : 0; - } - - wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); - - switch (bcm->ieee->iw_mode) { - case IW_MODE_ADHOC: - if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || - memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || - is_broadcast_ether_addr(wlhdr->addr1) || - is_multicast_ether_addr(wlhdr->addr1) || - bcm->net_dev->flags & IFF_PROMISC) - is_packet_for_us = 1; - break; - case IW_MODE_INFRA: - default: - /* When receiving multicast or broadcast packets, filter out - the packets we send ourself; we shouldn't see those */ - if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || - memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || - (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && - (is_broadcast_ether_addr(wlhdr->addr1) || - is_multicast_ether_addr(wlhdr->addr1) || - bcm->net_dev->flags & IFF_PROMISC))) - is_packet_for_us = 1; - break; - } - - frame_ctl = le16_to_cpu(wlhdr->frame_ctl); - switch (WLAN_FC_GET_TYPE(frame_ctl)) { - case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); - break; - case IEEE80211_FTYPE_DATA: - if (is_packet_for_us) { - err = ieee80211_rx(bcm->ieee, skb, &stats); - err = (err == 0) ? -EINVAL : 0; - } - break; - case IEEE80211_FTYPE_CTL: - break; - default: - assert(0); - return -EINVAL; - } - - return err; -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h deleted file mode 100644 index 47c135a7f4d..00000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef BCM43xx_XMIT_H_ -#define BCM43xx_XMIT_H_ - -#include "bcm43xx_main.h" - - -#define _bcm43xx_declare_plcp_hdr(size) \ - struct bcm43xx_plcp_hdr##size { \ - union { \ - __le32 data; \ - __u8 raw[size]; \ - } __attribute__((__packed__)); \ - } __attribute__((__packed__)) - -/* struct bcm43xx_plcp_hdr4 */ -_bcm43xx_declare_plcp_hdr(4); -/* struct bcm43xx_plcp_hdr6 */ -_bcm43xx_declare_plcp_hdr(6); - -#undef _bcm43xx_declare_plcp_hdr - -/* Device specific TX header. To be prepended to TX frames. */ -struct bcm43xx_txhdr { - union { - struct { - __le16 flags; - __le16 wsec_rate; - __le16 frame_control; - u16 unknown_zeroed_0; - __le16 control; - u8 wep_iv[10]; - u8 unknown_wsec_tkip_data[3]; //FIXME - PAD_BYTES(3); - u8 mac1[6]; - u16 unknown_zeroed_1; - struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; - __le16 rts_cts_dur_fallback; - struct bcm43xx_plcp_hdr4 fallback_plcp; - __le16 fallback_dur_id; - PAD_BYTES(2); - __le16 cookie; - __le16 unknown_scb_stuff; //FIXME - struct bcm43xx_plcp_hdr6 rts_cts_plcp; - __le16 rts_cts_frame_control; - __le16 rts_cts_dur; - u8 rts_cts_mac1[6]; - u8 rts_cts_mac2[6]; - PAD_BYTES(2); - struct bcm43xx_plcp_hdr6 plcp; - } __attribute__((__packed__)); - u8 raw[82]; - } __attribute__((__packed__)); -} __attribute__((__packed__)); - -/* Values/Masks for the device TX header */ -#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 -#define BCM43xx_TXHDRFLAG_RTSCTS 0x0002 -#define BCM43xx_TXHDRFLAG_RTS 0x0004 -#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 -#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 -#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080 -#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 -#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200 -#define BCM43xx_TXHDRFLAG_CTS 0x0400 -#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 - -#define BCM43xx_TXHDRCTL_OFDM 0x0001 -#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 -#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 -#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 - -#define BCM43xx_TXHDR_RATE_MASK 0x0F00 -#define BCM43xx_TXHDR_RATE_SHIFT 8 -#define BCM43xx_TXHDR_RTSRATE_MASK 0xF000 -#define BCM43xx_TXHDR_RTSRATE_SHIFT 12 -#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 -#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 -#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 -#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - const unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie); - -/* RX header as received from the hardware. */ -struct bcm43xx_rxhdr { - /* Frame Length. Must be generated explicitly in PIO mode. */ - __le16 frame_length; - PAD_BYTES(2); - /* Flags field 1 */ - __le16 flags1; - u8 rssi; - u8 signal_quality; - PAD_BYTES(2); - /* Flags field 3 */ - __le16 flags3; - /* Flags field 2 */ - __le16 flags2; - /* Lower 16bits of the TSF at the time the frame started. */ - __le16 mactime; - PAD_BYTES(14); -} __attribute__((__packed__)); - -#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) -/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ -#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) -#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) - -#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) -#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) -/*FIXME: WEP related flags */ - -#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) - -/* Transmit Status as received from the hardware. */ -struct bcm43xx_hwxmitstatus { - PAD_BYTES(4); - __le16 cookie; - u8 flags; - u8 cnt1:4, - cnt2:4; - PAD_BYTES(2); - __le16 seq; - __le16 unknown; //FIXME -} __attribute__((__packed__)); - -/* Transmit Status in CPU byteorder. */ -struct bcm43xx_xmitstatus { - u16 cookie; - u8 flags; - u8 cnt1:4, - cnt2:4; - u16 seq; - u16 unknown; //FIXME -}; - -#define BCM43xx_TXSTAT_FLAG_AMPDU 0x10 -#define BCM43xx_TXSTAT_FLAG_INTER 0x20 - -u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate); -u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate); - -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr); - -#endif /* BCM43xx_XMIT_H_ */ diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 98d6ff69d37..fa87c5c2ae0 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4495,9 +4495,9 @@ static void ipw_rx_notification(struct ipw_priv *priv, priv-> essid_len), print_mac(mac, priv->bssid), - ntohs(auth->status), + le16_to_cpu(auth->status), ipw_get_status_code - (ntohs + (le16_to_cpu (auth->status))); priv->status &= @@ -4532,9 +4532,9 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DL_STATE | IPW_DL_ASSOC, "association failed (0x%04X): %s\n", - ntohs(resp->status), + le16_to_cpu(resp->status), ipw_get_status_code - (ntohs + (le16_to_cpu (resp->status))); } @@ -4591,8 +4591,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "authentication failed (0x%04X): %s\n", - ntohs(auth->status), - ipw_get_status_code(ntohs + le16_to_cpu(auth->status), + ipw_get_status_code(le16_to_cpu (auth-> status))); } @@ -10350,9 +10350,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, remaining_bytes, PCI_DMA_TODEVICE)); - tfd->u.data.num_chunks = - cpu_to_le32(le32_to_cpu(tfd->u.data.num_chunks) + - 1); + le32_add_cpu(&tfd->u.data.num_chunks, 1); } } diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index fdc187e0769..cd3295b66dd 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -385,73 +385,73 @@ struct clx2_queue { dma_addr_t dma_addr; /**< physical addr for BD's */ int low_mark; /**< low watermark, resume queue if free space more than this */ int high_mark; /**< high watermark, stop queue if free space less than this */ -} __attribute__ ((packed)); +} __attribute__ ((packed)); /* XXX */ struct machdr32 { __le16 frame_ctl; - u16 duration; // watch out for endians! + __le16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; u8 addr3[MACADRR_BYTE_LEN]; - u16 seq_ctrl; // more endians! + __le16 seq_ctrl; // more endians! u8 addr4[MACADRR_BYTE_LEN]; __le16 qos_ctrl; } __attribute__ ((packed)); struct machdr30 { __le16 frame_ctl; - u16 duration; // watch out for endians! + __le16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; u8 addr3[MACADRR_BYTE_LEN]; - u16 seq_ctrl; // more endians! + __le16 seq_ctrl; // more endians! u8 addr4[MACADRR_BYTE_LEN]; } __attribute__ ((packed)); struct machdr26 { __le16 frame_ctl; - u16 duration; // watch out for endians! + __le16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; u8 addr3[MACADRR_BYTE_LEN]; - u16 seq_ctrl; // more endians! + __le16 seq_ctrl; // more endians! __le16 qos_ctrl; } __attribute__ ((packed)); struct machdr24 { __le16 frame_ctl; - u16 duration; // watch out for endians! + __le16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; u8 addr3[MACADRR_BYTE_LEN]; - u16 seq_ctrl; // more endians! + __le16 seq_ctrl; // more endians! } __attribute__ ((packed)); // TX TFD with 32 byte MAC Header struct tx_tfd_32 { struct machdr32 mchdr; // 32 - u32 uivplaceholder[2]; // 8 + __le32 uivplaceholder[2]; // 8 } __attribute__ ((packed)); // TX TFD with 30 byte MAC Header struct tx_tfd_30 { struct machdr30 mchdr; // 30 u8 reserved[2]; // 2 - u32 uivplaceholder[2]; // 8 + __le32 uivplaceholder[2]; // 8 } __attribute__ ((packed)); // tx tfd with 26 byte mac header struct tx_tfd_26 { struct machdr26 mchdr; // 26 u8 reserved1[2]; // 2 - u32 uivplaceholder[2]; // 8 + __le32 uivplaceholder[2]; // 8 u8 reserved2[4]; // 4 } __attribute__ ((packed)); // tx tfd with 24 byte mac header struct tx_tfd_24 { struct machdr24 mchdr; // 24 - u32 uivplaceholder[2]; // 8 + __le32 uivplaceholder[2]; // 8 u8 reserved[8]; // 8 } __attribute__ ((packed)); @@ -460,7 +460,7 @@ struct tx_tfd_24 { struct tfd_command { u8 index; u8 length; - u16 reserved; + __le16 reserved; u8 payload[0]; } __attribute__ ((packed)); @@ -562,27 +562,27 @@ struct rate_histogram { struct ipw_cmd_stats { u8 cmd_id; u8 seq_num; - u16 good_sfd; - u16 bad_plcp; - u16 wrong_bssid; - u16 valid_mpdu; - u16 bad_mac_header; - u16 reserved_frame_types; - u16 rx_ina; - u16 bad_crc32; - u16 invalid_cts; - u16 invalid_acks; - u16 long_distance_ina_fina; - u16 dsp_silence_unreachable; - u16 accumulated_rssi; - u16 rx_ovfl_frame_tossed; - u16 rssi_silence_threshold; - u16 rx_ovfl_frame_supplied; - u16 last_rx_frame_signal; - u16 last_rx_frame_noise; - u16 rx_autodetec_no_ofdm; - u16 rx_autodetec_no_barker; - u16 reserved; + __le16 good_sfd; + __le16 bad_plcp; + __le16 wrong_bssid; + __le16 valid_mpdu; + __le16 bad_mac_header; + __le16 reserved_frame_types; + __le16 rx_ina; + __le16 bad_crc32; + __le16 invalid_cts; + __le16 invalid_acks; + __le16 long_distance_ina_fina; + __le16 dsp_silence_unreachable; + __le16 accumulated_rssi; + __le16 rx_ovfl_frame_tossed; + __le16 rssi_silence_threshold; + __le16 rx_ovfl_frame_supplied; + __le16 last_rx_frame_signal; + __le16 last_rx_frame_noise; + __le16 rx_autodetec_no_ofdm; + __le16 rx_autodetec_no_barker; + __le16 reserved; } __attribute__ ((packed)); struct notif_channel_result { @@ -637,7 +637,7 @@ struct notif_association { struct notif_authenticate { u8 state; struct machdr24 addr; - u16 status; + __le16 status; } __attribute__ ((packed)); struct notif_calibration { @@ -732,14 +732,14 @@ struct ipw_rx_queue { struct alive_command_responce { u8 alive_command; u8 sequence_number; - u16 software_revision; + __le16 software_revision; u8 device_identifier; u8 reserved1[5]; - u16 reserved2; - u16 reserved3; - u16 clock_settle_time; - u16 powerup_settle_time; - u16 reserved4; + __le16 reserved2; + __le16 reserved3; + __le16 clock_settle_time; + __le16 powerup_settle_time; + __le16 reserved4; u8 time_stamp[5]; /* month, day, year, hours, minutes */ u8 ucode_valid; } __attribute__ ((packed)); @@ -878,7 +878,11 @@ static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan, struct ipw_associate { u8 channel; +#ifdef __LITTLE_ENDIAN_BITFIELD u8 auth_type:4, auth_key:4; +#else + u8 auth_key:4, auth_type:4; +#endif u8 assoc_type; u8 reserved; __le16 policy_support; @@ -918,12 +922,12 @@ struct ipw_frag_threshold { struct ipw_retry_limit { u8 short_retry_limit; u8 long_retry_limit; - u16 reserved; + __le16 reserved; } __attribute__ ((packed)); struct ipw_dino_config { - u32 dino_config_addr; - u16 dino_config_size; + __le32 dino_config_addr; + __le16 dino_config_size; u8 dino_response; u8 reserved; } __attribute__ ((packed)); @@ -998,7 +1002,7 @@ struct ipw_sensitivity_calib { * - \a status contains status; * - \a param filled with status parameters. */ -struct ipw_cmd { +struct ipw_cmd { /* XXX */ u32 cmd; /**< Host command */ u32 status;/**< Status */ u32 status_len; @@ -1092,7 +1096,7 @@ struct ipw_ibss_seq { struct list_head list; }; -struct ipw_error_elem { +struct ipw_error_elem { /* XXX */ u32 desc; u32 time; u32 blink1; @@ -1102,13 +1106,13 @@ struct ipw_error_elem { u32 data; }; -struct ipw_event { +struct ipw_event { /* XXX */ u32 event; u32 time; u32 data; } __attribute__ ((packed)); -struct ipw_fw_error { +struct ipw_fw_error { /* XXX */ unsigned long jiffies; u32 status; u32 config; @@ -1153,7 +1157,7 @@ struct ipw_prom_priv { */ struct ipw_rt_hdr { struct ieee80211_radiotap_header rt_hdr; - u64 rt_tsf; /* TSF */ + u64 rt_tsf; /* TSF */ /* XXX */ u8 rt_flags; /* radiotap packet flags */ u8 rt_rate; /* rate in 500kb/s */ __le16 rt_channel; /* channel in mhz */ @@ -1940,8 +1944,8 @@ enum { #define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C) struct ipw_fixed_rate { - u16 tx_rates; - u16 reserved; + __le16 tx_rates; + __le16 reserved; } __attribute__ ((packed)); #define IPW_INDIRECT_ADDR_MASK (~0x3ul) @@ -1951,12 +1955,12 @@ struct host_cmd { u8 len; u16 reserved; u32 *param; -} __attribute__ ((packed)); +} __attribute__ ((packed)); /* XXX */ struct cmdlog_host_cmd { u8 cmd; u8 len; - u16 reserved; + __le16 reserved; char param[124]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b54ff712e70..bcaa61b7c56 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,7 +1,22 @@ +config IWLCORE + tristate "Intel Wireless Wifi Core" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + +config IWLWIFI_LEDS + bool + default n + +config IWLCORE_RFKILL + boolean "IWLWIFI RF kill support" + depends on IWLCORE + select RFKILL + select RFKILL_INPUT + config IWL4965 tristate "Intel Wireless WiFi 4965AGN" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select IWLCORE ---help--- Select to build the driver supporting the: @@ -24,21 +39,22 @@ config IWL4965 say M here and read <file:Documentation/kbuild/modules.txt>. The module will be called iwl4965.ko. -config IWL4965_QOS - bool "Enable Wireless QoS in iwl4965 driver" - depends on IWL4965 - ---help--- - This option will enable wireless quality of service (QoS) for the - iwl4965 driver. - config IWL4965_HT bool "Enable 802.11n HT features in iwl4965 driver" depends on EXPERIMENTAL - depends on IWL4965 && IWL4965_QOS + depends on IWL4965 ---help--- This option enables IEEE 802.11n High Throughput features for the iwl4965 driver. +config IWL4965_LEDS + bool "Enable LEDS features in iwl4965 driver" + depends on IWL4965 && MAC80211_LEDS && LEDS_CLASS + select IWLWIFI_LEDS + ---help--- + This option enables LEDS for the iwlwifi drivers + + config IWL4965_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwl4965 driver" depends on IWL4965 @@ -52,7 +68,7 @@ config IWL4965_SENSITIVITY This option will enable sensitivity calibration for the iwl4965 driver. -config IWL4965_DEBUG +config IWLWIFI_DEBUG bool "Enable full debugging output in iwl4965 driver" depends on IWL4965 ---help--- @@ -78,6 +94,12 @@ config IWL4965_DEBUG as the debug information can assist others in helping you resolve any problems you may encounter. +config IWLWIFI_DEBUGFS + bool "Iwlwifi debugfs support" + depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS + ---help--- + Enable creation of debugfs files for the iwlwifi drivers. + config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL @@ -104,19 +126,18 @@ config IWL3945 say M here and read <file:Documentation/kbuild/modules.txt>. The module will be called iwl3945.ko. -config IWL3945_QOS - bool "Enable Wireless QoS in iwl3945 driver" - depends on IWL3945 - ---help--- - This option will enable wireless quality of service (QoS) for the - iwl3945 driver. - config IWL3945_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwl3945 drivers" depends on IWL3945 ---help--- This option will enable spectrum measurement for the iwl3945 driver. +config IWL3945_LEDS + bool "Enable LEDS features in iwl3945 driver" + depends on IWL3945 && MAC80211_LEDS && LEDS_CLASS + ---help--- + This option enables LEDS for the iwl3945 driver. + config IWL3945_DEBUG bool "Enable full debugging output in iwl3945 driver" depends on IWL3945 diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 3bbd38358d5..2751e8aa97d 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,5 +1,26 @@ +obj-$(CONFIG_IWLCORE) += iwlcore.o +iwlcore-objs = iwl-core.o iwl-eeprom.o iwl-hcmd.o + +ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y) + iwlcore-objs += iwl-debugfs.o +endif + +ifeq ($(CONFIG_IWLWIFI_LEDS),y) + iwlcore-objs += iwl-led.o +endif + +ifeq ($(CONFIG_IWLCORE_RFKILL),y) + iwlcore-objs += iwl-rfkill.o +endif + obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o +ifeq ($(CONFIG_IWL3945_LEDS),y) + iwl3945-objs += iwl-3945-led.o +endif + + obj-$(CONFIG_IWL4965) += iwl4965.o iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 46bb2c7d11d..817ece77364 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -515,14 +515,20 @@ struct iwl3945_qosparam_cmd { #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3) +#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 #define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +/* wep key is either from global key (0) or from station info array (1) */ +#define STA_KEY_FLG_WEP_KEY_MAP_MSK __constant_cpu_to_le16(0x0008) + +/* wep key in STA: 5-bytes (0) or 13-bytes (1) */ +#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) /* Flags indicate whether to modify vs. don't change various station params */ #define STA_MODIFY_KEY_MASK 0x01 @@ -546,7 +552,8 @@ struct iwl3945_keyinfo { u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ u8 reserved1; __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - __le16 reserved2; + u8 key_offset; + u8 reserved2; u8 key[16]; /* 16-byte unicast decryption key */ } __attribute__ ((packed)); @@ -659,26 +666,26 @@ struct iwl3945_rx_frame_hdr { u8 payload[0]; } __attribute__ ((packed)); -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) +#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) -#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) -#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) -#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) -#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) -#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) +#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) +#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) +#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) +#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) +#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) -#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) -#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) -#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) -#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) -#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) +#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) +#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) +#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) +#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) +#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) struct iwl3945_rx_frame_end { __le32 status; @@ -700,45 +707,6 @@ struct iwl3945_rx_frame { struct iwl3945_rx_frame_end end; } __attribute__ ((packed)); -/* Fixed (non-configurable) rx data from phy */ -#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL_AGC_DB_POS (7) -struct iwl4965_rx_non_cfg_phy { - __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ - __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ - u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; -} __attribute__ ((packed)); - -/* - * REPLY_4965_RX = 0xc3 (response only, not a command) - * Used only for legacy (non 11n) frames. - */ -#define RX_RES_PHY_CNT 14 -struct iwl4965_rx_phy_res { - u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ - u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ - u8 stat_id; /* configurable DSP phy data set ID */ - u8 reserved1; - __le64 timestamp; /* TSF at on air rise */ - __le32 beacon_time_stamp; /* beacon at on-air rise */ - __le16 phy_flags; /* general phy flags: band, modulation, ... */ - __le16 channel; /* channel number */ - __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ - __le32 reserved2; - __le32 rate_n_flags; - __le16 byte_count; /* frame's byte-count */ - __le16 reserved3; -} __attribute__ ((packed)); - -struct iwl4965_rx_mpdu_res_start { - __le16 byte_count; - __le16 reserved; -} __attribute__ ((packed)); - - /****************************************************************************** * (5) * Tx Commands & Responses: diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h new file mode 100644 index 00000000000..bc12f97ba0b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_3945_dev_h__ +#define __iwl_3945_dev_h__ + +#define IWL_PCI_DEVICE(dev, subdev, cfg) \ + .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = (subdev), \ + .driver_data = (kernel_ulong_t)&(cfg) + +#define IWL_SKU_G 0x1 +#define IWL_SKU_A 0x2 + +struct iwl_3945_cfg { + const char *name; + const char *fw_name; + unsigned int sku; +}; + +#endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index f853c6b9f76..f1d002f7b79 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -40,6 +40,15 @@ do { if (iwl3945_debug_level & (level)) \ do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + +static inline void iwl3945_print_hex_dump(int level, void *p, u32 len) +{ + if (!(iwl3945_debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +} #else static inline void IWL_DEBUG(int level, const char *fmt, ...) { @@ -47,7 +56,12 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...) static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) { } -#endif /* CONFIG_IWL3945_DEBUG */ +static inline void iwl3945_print_hex_dump(int level, void *p, u32 len) +{ +} +#endif /* CONFIG_IWL3945_DEBUG */ + + /* * To use the debug system; @@ -143,6 +157,7 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) +#define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 571815d7e8b..368da9852aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -198,43 +198,27 @@ struct iwl3945_eeprom_temperature_corr { */ struct iwl3945_eeprom { u8 reserved0[16]; -#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ u16 device_id; /* abs.ofs: 16 */ u8 reserved1[2]; -#define EEPROM_PMC (2*0x0A) /* 2 bytes */ u16 pmc; /* abs.ofs: 20 */ u8 reserved2[20]; -#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ u8 mac_address[6]; /* abs.ofs: 42 */ u8 reserved3[58]; -#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ u16 board_revision; /* abs.ofs: 106 */ u8 reserved4[11]; -#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ u8 board_pba_number[9]; /* abs.ofs: 119 */ u8 reserved5[8]; -#define EEPROM_VERSION (2*0x44) /* 2 bytes */ u16 version; /* abs.ofs: 136 */ -#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ u8 sku_cap; /* abs.ofs: 138 */ -#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ u8 leds_mode; /* abs.ofs: 139 */ -#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ u16 oem_mode; -#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ u16 wowlan_mode; /* abs.ofs: 142 */ -#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ u16 leds_time_interval; /* abs.ofs: 144 */ -#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ u8 leds_off_time; /* abs.ofs: 146 */ -#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ u8 leds_on_time; /* abs.ofs: 147 */ -#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ u8 almgor_m_version; /* abs.ofs: 148 */ -#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ u8 antenna_switch_type; /* abs.ofs: 149 */ u8 reserved6[42]; -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ u8 sku_id[4]; /* abs.ofs: 192 */ /* @@ -249,9 +233,7 @@ struct iwl3945_eeprom { * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ u16 band_1_count; /* abs.ofs: 196 */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ struct iwl3945_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ /* @@ -259,36 +241,28 @@ struct iwl3945_eeprom { * 5.0 GHz channels 7, 8, 11, 12, 16 * (4915-5080MHz) (none of these is ever supported) */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ u16 band_2_count; /* abs.ofs: 226 */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ struct iwl3945_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ /* * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 * (5170-5320MHz) */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ u16 band_3_count; /* abs.ofs: 254 */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ struct iwl3945_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ /* * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 * (5500-5700MHz) */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ u16 band_4_count; /* abs.ofs: 280 */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ struct iwl3945_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ /* * 5.7 GHz channels 145, 149, 153, 157, 161, 165 * (5725-5825MHz) */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ u16 band_5_count; /* abs.ofs: 304 */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ struct iwl3945_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ u8 reserved9[194]; @@ -296,15 +270,9 @@ struct iwl3945_eeprom { /* * 3945 Txpower calibration data. */ -#define EEPROM_TXPOWER_CALIB_GROUP0 0x200 -#define EEPROM_TXPOWER_CALIB_GROUP1 0x240 -#define EEPROM_TXPOWER_CALIB_GROUP2 0x280 -#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0 -#define EEPROM_TXPOWER_CALIB_GROUP4 0x300 #define IWL_NUM_TX_CALIB_GROUPS 5 struct iwl3945_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS]; /* abs.ofs: 512 */ -#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340 struct iwl3945_eeprom_temperature_corr corrections; /* abs.ofs: 832 */ u8 reserved16[172]; /* fill out to full 1024 byte block */ } __attribute__ ((packed)); @@ -321,181 +289,6 @@ struct iwl3945_eeprom { #define PCI_REG_WUM8 0x0E8 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -/*=== CSR (control and status registers) ===*/ -#define CSR_BASE (0x000) - -#define CSR_SW_VER (CSR_BASE+0x000) -#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ -#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ -#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ -#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ -#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ -#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ -#define CSR_GP_CNTRL (CSR_BASE+0x024) - -/* - * Hardware revision info - * Bit fields: - * 31-8: Reserved - * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 - * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D - * 1-0: "Dash" value, as in A-1, etc. - */ -#define CSR_HW_REV (CSR_BASE+0x028) - -/* EEPROM reads */ -#define CSR_EEPROM_REG (CSR_BASE+0x02c) -#define CSR_EEPROM_GP (CSR_BASE+0x030) -#define CSR_GP_UCODE (CSR_BASE+0x044) -#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) -#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) -#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) -#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) -#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) - -/* Analog phase-lock-loop configuration (3945 only) - * Set bit 24. */ -#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) - -/* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100) -#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200) -#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) -#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) -#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) -#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) -#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) - -/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), - * acknowledged (reset) by host writing "1" to flagged bits. */ -#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ -#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ -#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ -#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ -#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ -#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ -#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ -#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ -#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ -#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ - -#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ - CSR_INT_BIT_HW_ERR | \ - CSR_INT_BIT_FH_TX | \ - CSR_INT_BIT_SW_ERR | \ - CSR_INT_BIT_RF_KILL | \ - CSR_INT_BIT_SW_RX | \ - CSR_INT_BIT_WAKEUP | \ - CSR_INT_BIT_ALIVE) - -/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ -#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ -#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ -#define CSR_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ -#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ -#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ -#define CSR_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ -#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ -#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ - -#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL2 | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - -#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \ - CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) - - -/* RESET */ -#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) -#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) -#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) -#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) -#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) - -/* GP (general purpose) CONTROL */ -#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) -#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) -#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) -#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) - -#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) - -#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) -#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) -#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) - - -/* EEPROM REG */ -#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) -#define CSR_EEPROM_REG_BIT_CMD (0x00000002) - -/* EEPROM GP */ -#define CSR_EEPROM_GP_VALID_MSK (0x00000006) -#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) -#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) - -/* UCODE DRV GP */ -#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) -#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) -#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) -#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) - -/* GPIO */ -#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) -#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) -#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER - -/* GI Chicken Bits */ -#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) -#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) - -/* CSR_ANA_PLL_CFG */ -#define CSR_ANA_PLL_CFG_SH (0x00880300) - -/*=== HBUS (Host-side Bus) ===*/ -#define HBUS_BASE (0x400) - -/* - * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM - * structures, error log, event log, verifying uCode load). - * First write to address register, then read from or write to data register - * to complete the job. Once the address register is set up, accesses to - * data registers auto-increment the address by one dword. - * Bit usage for address registers (read or write): - * 0-31: memory address within device - */ -#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) -#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) -#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) -#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) - -/* - * Registers for accessing device's internal peripheral registers - * (e.g. SCD, BSM, etc.). First write to address register, - * then read from or write to data register to complete the job. - * Bit usage for address registers (read or write): - * 0-15: register address (offset) within device - * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) - */ -#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) -#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) -#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) -#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) - -/* - * Per-Tx-queue write pointer (index, really!) (3945 and 4965). - * Indicates index to next TFD that driver will fill (1 past latest filled). - * Bit usage: - * 0-7: queue write index - * 11-8: queue selector - */ -#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) - /* SCD (3945 Tx Frame Scheduler) */ #define SCD_BASE (CSR_BASE + 0x2E00) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 75e20d0a20d..0b947511461 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -59,28 +59,28 @@ * */ -#define _iwl3945_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) +#define _iwl3945_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs)) #ifdef CONFIG_IWL3945_DEBUG -static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *iwl, +static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *priv, u32 ofs, u32 val) { IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); - _iwl3945_write32(iwl, ofs, val); + _iwl3945_write32(priv, ofs, val); } -#define iwl3945_write32(iwl, ofs, val) \ - __iwl3945_write32(__FILE__, __LINE__, iwl, ofs, val) +#define iwl3945_write32(priv, ofs, val) \ + __iwl3945_write32(__FILE__, __LINE__, priv, ofs, val) #else -#define iwl3945_write32(iwl, ofs, val) _iwl3945_write32(iwl, ofs, val) +#define iwl3945_write32(priv, ofs, val) _iwl3945_write32(priv, ofs, val) #endif -#define _iwl3945_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) +#define _iwl3945_read32(priv, ofs) readl((priv)->hw_base + (ofs)) #ifdef CONFIG_IWL3945_DEBUG -static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *iwl, u32 ofs) +static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *priv, u32 ofs) { IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl3945_read32(iwl, ofs); + return _iwl3945_read32(priv, ofs); } -#define iwl3945_read32(iwl, ofs) __iwl3945_read32(__FILE__, __LINE__, iwl, ofs) +#define iwl3945_read32(priv, ofs) __iwl3945_read32(__FILE__, __LINE__, priv, ofs) #else #define iwl3945_read32(p, o) _iwl3945_read32(p, o) #endif @@ -105,18 +105,13 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l, u32 bits, u32 mask, int timeout) { int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout); - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO - ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", - addr, bits, mask, f, l); - else - IWL_DEBUG_IO - ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", - addr, bits, mask, ret, f, l); + IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", + addr, bits, mask, + unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); return ret; } -#define iwl3945_poll_bit(iwl, addr, bits, mask, timeout) \ - __iwl3945_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) +#define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \ + __iwl3945_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) #else #define iwl3945_poll_bit(p, a, b, m, t) _iwl3945_poll_bit(p, a, b, m, t) #endif @@ -321,8 +316,8 @@ static inline int __iwl3945_poll_direct_bit(const char *f, u32 l, "- %s %d\n", addr, mask, ret, f, l); return ret; } -#define iwl3945_poll_direct_bit(iwl, addr, mask, timeout) \ - __iwl3945_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) +#define iwl3945_poll_direct_bit(priv, addr, mask, timeout) \ + __iwl3945_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) #else #define iwl3945_poll_direct_bit _iwl3945_poll_direct_bit #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c new file mode 100644 index 00000000000..d200d08fb08 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -0,0 +1,433 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <net/mac80211.h> +#include <linux/etherdevice.h> +#include <asm/unaligned.h> + +#include "iwl-3945.h" +#include "iwl-helpers.h" + +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (10) + +static const struct { + u16 brightness; + u8 on_time; + u8 of_time; +} blink_tbl[] = +{ + {300, 25, 25}, + {200, 40, 40}, + {100, 55, 55}, + {70, 65, 65}, + {50, 75, 75}, + {20, 85, 85}, + {15, 95, 95 }, + {10, 110, 110}, + {5, 130, 130}, + {0, 167, 167} +}; + +static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, + struct sk_buff *skb) +{ + return 1; +} + + +/* Send led command */ +static int iwl_send_led_cmd(struct iwl3945_priv *priv, + struct iwl3945_led_cmd *led_cmd) +{ + struct iwl3945_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl3945_led_cmd), + .data = led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl3945_led_cmd_callback + }; + + return iwl3945_send_cmd(priv, &cmd); +} + + +/* Set led on command */ +static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = IWL_LED_SOLID, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led on command */ +static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id, + enum led_brightness brightness) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + if (brightness == LED_FULL) { + led_cmd.on = IWL_LED_SOLID; + led_cmd.off = 0; + } + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led register off */ +static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id) +{ + IWL_DEBUG_LED("led on %d\n", led_id); + return iwl3945_led_on(priv, led_id); +} + +/* Set led off command */ +static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = 0, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + IWL_DEBUG_LED("led off %d\n", led_id); + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led register off */ +static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id) +{ + iwl3945_led_off(priv, led_id); + return 0; +} + +/* Set led blink command */ +static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id, + u8 brightness) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + + return iwl_send_led_cmd(priv, &led_cmd); +} + + +/* + * brightness call back function for Tx/Rx LED + */ +static int iwl3945_led_associated(struct iwl3945_priv *priv, int led_id) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return 0; + + + /* start counting Tx/Rx bytes */ + if (!priv->last_blink_time && priv->allow_blinking) + priv->last_blink_time = jiffies; + return 0; +} + +/* + * brightness call back for association and radio + */ +static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct iwl3945_led *led = container_of(led_cdev, + struct iwl3945_led, led_dev); + struct iwl3945_priv *priv = led->priv; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + switch (brightness) { + case LED_FULL: + if (led->type == IWL_LED_TRG_ASSOC) { + priv->allow_blinking = 1; + IWL_DEBUG_LED("MAC is associated\n"); + } + if (led->led_on) + led->led_on(priv, IWL_LED_LINK); + break; + case LED_OFF: + if (led->type == IWL_LED_TRG_ASSOC) { + priv->allow_blinking = 0; + IWL_DEBUG_LED("MAC is disassociated\n"); + } + if (led->led_off) + led->led_off(priv, IWL_LED_LINK); + break; + default: + if (led->led_pattern) + led->led_pattern(priv, IWL_LED_LINK, brightness); + break; + } +} + + + +/* + * Register led class with the system + */ +static int iwl3945_led_register_led(struct iwl3945_priv *priv, + struct iwl3945_led *led, + enum led_type type, u8 set_led, + const char *name, char *trigger) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret; + + led->led_dev.name = name; + led->led_dev.brightness_set = iwl3945_led_brightness_set; + led->led_dev.default_trigger = trigger; + + ret = led_classdev_register(device, &led->led_dev); + if (ret) { + IWL_ERROR("Error: failed to register led handler.\n"); + return ret; + } + + led->priv = priv; + led->type = type; + led->registered = 1; + + if (set_led && led->led_on) + led->led_on(priv, IWL_LED_LINK); + return 0; +} + + +/* + * calculate blink rate according to last 2 sec Tx/Rx activities + */ +static inline u8 get_blink_rate(struct iwl3945_priv *priv) +{ + int index; + u8 blink_rate; + + if (priv->rxtxpackets < IWL_LED_THRESHOLD) + index = 10; + else { + for (index = 0; index < IWL_MAX_BLINK_TBL; index++) { + if (priv->rxtxpackets > (blink_tbl[index].brightness * + IWL_1MB_RATE)) + break; + } + } + /* if 0 frame is transfered */ + if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) + blink_rate = IWL_LED_SOLID; + else + blink_rate = blink_tbl[index].on_time; + + return blink_rate; +} + +static inline int is_rf_kill(struct iwl3945_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +/* + * this function called from handler. Since setting Led command can + * happen very frequent we postpone led command to be called from + * REPLY handler so we know ucode is up + */ +void iwl3945_led_background(struct iwl3945_priv *priv) +{ + u8 blink_rate; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + priv->last_blink_time = 0; + return; + } + if (is_rf_kill(priv)) { + priv->last_blink_time = 0; + return; + } + + if (!priv->allow_blinking) { + priv->last_blink_time = 0; + if (priv->last_blink_rate != IWL_LED_SOLID) { + priv->last_blink_rate = IWL_LED_SOLID; + iwl3945_led_on(priv, IWL_LED_LINK); + } + return; + } + if (!priv->last_blink_time || + !time_after(jiffies, priv->last_blink_time + + msecs_to_jiffies(1000))) + return; + + blink_rate = get_blink_rate(priv); + + /* call only if blink rate change */ + if (blink_rate != priv->last_blink_rate) { + if (blink_rate != IWL_LED_SOLID) { + priv->last_blink_time = jiffies + + msecs_to_jiffies(1000); + iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate); + } else { + priv->last_blink_time = 0; + iwl3945_led_on(priv, IWL_LED_LINK); + } + } + + priv->last_blink_rate = blink_rate; + priv->rxtxpackets = 0; +} + + +/* Register all led handler */ +int iwl3945_led_register(struct iwl3945_priv *priv) +{ + char *trigger; + char name[32]; + int ret; + + priv->last_blink_rate = 0; + priv->rxtxpackets = 0; + priv->last_blink_time = 0; + priv->allow_blinking = 0; + + trigger = ieee80211_get_radio_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:radio", + wiphy_name(priv->hw->wiphy)); + + priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; + + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_RADIO], + IWL_LED_TRG_RADIO, 1, + name, trigger); + if (ret) + goto exit_fail; + + trigger = ieee80211_get_assoc_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:assoc", + wiphy_name(priv->hw->wiphy)); + + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_ASSOC], + IWL_LED_TRG_ASSOC, 0, + name, trigger); + /* for assoc always turn led on */ + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_rx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:RX", + wiphy_name(priv->hw->wiphy)); + + + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_RX], + IWL_LED_TRG_RX, 0, + name, trigger); + + priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated; + priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated; + priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_tx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:TX", + wiphy_name(priv->hw->wiphy)); + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_TX], + IWL_LED_TRG_TX, 0, + name, trigger); + priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated; + priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated; + priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern; + + if (ret) + goto exit_fail; + + return 0; + +exit_fail: + iwl3945_led_unregister(priv); + return ret; +} + + +/* unregister led class */ +static void iwl3945_led_unregister_led(struct iwl3945_led *led, u8 set_led) +{ + if (!led->registered) + return; + + led_classdev_unregister(&led->led_dev); + + if (set_led) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->registered = 0; +} + +/* Unregister all led handlers */ +void iwl3945_led_unregister(struct iwl3945_priv *priv) +{ + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h new file mode 100644 index 00000000000..b1d2f6b8b25 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef IWL3945_LEDS_H +#define IWL3945_LEDS_H + +struct iwl3945_priv; + +#ifdef CONFIG_IWL3945_LEDS +#define IWL_LED_SOLID 11 +#define IWL_LED_NAME_LEN 31 +#define IWL_DEF_LED_INTRVL __constant_cpu_to_le32(1000) + +#define IWL_LED_ACTIVITY (0<<1) +#define IWL_LED_LINK (1<<1) + +enum led_type { + IWL_LED_TRG_TX, + IWL_LED_TRG_RX, + IWL_LED_TRG_ASSOC, + IWL_LED_TRG_RADIO, + IWL_LED_TRG_MAX, +}; + +#include <linux/leds.h> + +struct iwl3945_led { + struct iwl3945_priv *priv; + struct led_classdev led_dev; + + int (*led_on) (struct iwl3945_priv *priv, int led_id); + int (*led_off) (struct iwl3945_priv *priv, int led_id); + int (*led_pattern) (struct iwl3945_priv *priv, int led_id, + enum led_brightness brightness); + + enum led_type type; + unsigned int registered; +}; + +extern int iwl3945_led_register(struct iwl3945_priv *priv); +extern void iwl3945_led_unregister(struct iwl3945_priv *priv); +extern void iwl3945_led_background(struct iwl3945_priv *priv); + +#else +static inline int iwl3945_led_register(struct iwl3945_priv *priv) { return 0; } +static inline void iwl3945_led_unregister(struct iwl3945_priv *priv) {} +static inline void iwl3945_led_background(struct iwl3945_priv *priv) {} +#endif /* CONFIG_IWL3945_LEDS */ + +#endif /* IWL3945_LEDS_H */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 80d31ae51e7..85c22641542 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -37,7 +37,7 @@ #include <linux/workqueue.h> -#include "../net/mac80211/ieee80211_rate.h" +#include "../net/mac80211/rate.h" #include "iwl-3945.h" @@ -100,14 +100,6 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_a[] = { {-89, IWL_RATE_6M_INDEX} }; -static struct iwl3945_tpt_entry iwl3945_tpt_table_b[] = { - {-86, IWL_RATE_11M_INDEX}, - {-88, IWL_RATE_5M_INDEX}, - {-90, IWL_RATE_2M_INDEX}, - {-92, IWL_RATE_1M_INDEX} - -}; - static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { {-60, IWL_RATE_54M_INDEX}, {-64, IWL_RATE_48M_INDEX}, @@ -129,7 +121,7 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { #define IWL_RATE_MIN_SUCCESS_TH 8 #define IWL_RATE_DECREASE_TH 1920 -static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode) +static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, enum ieee80211_band band) { u32 index = 0; u32 table_size = 0; @@ -138,21 +130,19 @@ static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode) if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) rssi = IWL_MIN_RSSI_VAL; - switch (mode) { - case MODE_IEEE80211G: + switch (band) { + case IEEE80211_BAND_2GHZ: tpt_table = iwl3945_tpt_table_g; table_size = ARRAY_SIZE(iwl3945_tpt_table_g); break; - case MODE_IEEE80211A: + case IEEE80211_BAND_5GHZ: tpt_table = iwl3945_tpt_table_a; table_size = ARRAY_SIZE(iwl3945_tpt_table_a); break; default: - case MODE_IEEE80211B: - tpt_table = iwl3945_tpt_table_b; - table_size = ARRAY_SIZE(iwl3945_tpt_table_b); + BUG(); break; } @@ -168,9 +158,9 @@ static void iwl3945_clear_window(struct iwl3945_rate_scale_data *window) { window->data = 0; window->success_counter = 0; - window->success_ratio = IWL_INVALID_VALUE; + window->success_ratio = -1; window->counter = 0; - window->average_tpt = IWL_INVALID_VALUE; + window->average_tpt = IWL_INV_TPT; window->stamp = 0; } @@ -340,17 +330,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * after assoc.. */ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { - if (sta->supp_rates & (1 << i)) { - sta->txrate = i; + if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) { + sta->txrate_idx = i; break; } } - sta->last_txrate = sta->txrate; + sta->last_txrate_idx = sta->txrate_idx; - /* For MODE_IEEE80211A mode it start at IWL_FIRST_OFDM_RATE */ - if (local->hw.conf.phymode == MODE_IEEE80211A) - sta->last_txrate += IWL_FIRST_OFDM_RATE; + /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; IWL_DEBUG_RATE("leave\n"); } @@ -429,17 +419,19 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) { int next_rate = iwl3945_get_prev_ieee_rate(rate); - switch (priv->phymode) { - case MODE_IEEE80211A: + switch (priv->band) { + case IEEE80211_BAND_5GHZ: if (rate == IWL_RATE_12M_INDEX) next_rate = IWL_RATE_9M_INDEX; else if (rate == IWL_RATE_6M_INDEX) next_rate = IWL_RATE_6M_INDEX; break; +/* XXX cannot be invoked in current mac80211 so not a regression case MODE_IEEE80211B: if (rate == IWL_RATE_11M_INDEX_TABLE) next_rate = IWL_RATE_5M_INDEX_TABLE; break; + */ default: break; } @@ -465,22 +457,25 @@ static void rs_tx_status(void *priv_rate, struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl3945_rs_sta *rs_sta; + struct ieee80211_supported_band *sband; IWL_DEBUG_RATE("enter\n"); - retries = tx_resp->retry_count; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - first_index = tx_resp->control.tx_rate; + + retries = tx_resp->retry_count; + first_index = tx_resp->control.tx_rate->hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { - IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n", - tx_resp->control.tx_rate, first_index); + IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; } + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); if (!sta || !sta->rate_ctrl_priv) { - if (sta) - sta_info_put(sta); + rcu_read_unlock(); IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); return; } @@ -553,7 +548,7 @@ static void rs_tx_status(void *priv_rate, spin_unlock_irqrestore(&rs_sta->lock, flags); - sta_info_put(sta); + rcu_read_unlock(); IWL_DEBUG_RATE("leave\n"); @@ -561,14 +556,14 @@ static void rs_tx_status(void *priv_rate, } static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, - u8 index, u16 rate_mask, int phymode) + u8 index, u16 rate_mask, enum ieee80211_band band) { u8 high = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID; /* 802.11A walks to the next literal adjacent rate in * the rate table */ - if (unlikely(phymode == MODE_IEEE80211A)) { + if (unlikely(band == IEEE80211_BAND_5GHZ)) { int i; u32 mask; @@ -639,7 +634,8 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * */ static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel) { u8 low = IWL_RATE_INVALID; @@ -648,9 +644,9 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, int index; struct iwl3945_rs_sta *rs_sta; struct iwl3945_rate_scale_data *window = NULL; - int current_tpt = IWL_INVALID_VALUE; - int low_tpt = IWL_INVALID_VALUE; - int high_tpt = IWL_INVALID_VALUE; + int current_tpt = IWL_INV_TPT; + int low_tpt = IWL_INV_TPT; + int high_tpt = IWL_INV_TPT; u32 fail_count; s8 scale_action = 0; unsigned long flags; @@ -663,6 +659,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE("enter\n"); + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest @@ -672,16 +670,15 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate = rate_lowest(local, local->oper_hw_mode, sta); - if (sta) - sta_info_put(sta); + sel->rate = rate_lowest(local, sband, sta); + rcu_read_unlock(); return; } - rate_mask = sta->supp_rates; - index = min(sta->last_txrate & 0xffff, IWL_RATE_COUNT - 1); + rate_mask = sta->supp_rates[sband->band]; + index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); - if (priv->phymode == (u8) MODE_IEEE80211A) + if (sband->band == IEEE80211_BAND_5GHZ) rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; rs_sta = (void *)sta->rate_ctrl_priv; @@ -713,7 +710,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { - window->average_tpt = IWL_INVALID_VALUE; + window->average_tpt = IWL_INV_TPT; spin_unlock_irqrestore(&rs_sta->lock, flags); IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " @@ -732,7 +729,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, current_tpt = window->average_tpt; high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, - local->hw.conf.phymode); + sband->band); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -749,19 +746,16 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); scale_action = -1; - } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) + } else if ((low_tpt == IWL_INV_TPT) && (high_tpt == IWL_INV_TPT)) scale_action = 1; - else if ((low_tpt != IWL_INVALID_VALUE) && - (high_tpt != IWL_INVALID_VALUE) - && (low_tpt < current_tpt) - && (high_tpt < current_tpt)) { + else if ((low_tpt != IWL_INV_TPT) && (high_tpt != IWL_INV_TPT) && + (low_tpt < current_tpt) && (high_tpt < current_tpt)) { IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < " "current_tpt [%d]\n", low_tpt, high_tpt, current_tpt); scale_action = 0; } else { - if (high_tpt != IWL_INVALID_VALUE) { + if (high_tpt != IWL_INV_TPT) { if (high_tpt > current_tpt) scale_action = 1; else { @@ -769,7 +763,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, ("decrease rate because of high tpt\n"); scale_action = -1; } - } else if (low_tpt != IWL_INVALID_VALUE) { + } else if (low_tpt != IWL_INV_TPT) { if (low_tpt > current_tpt) { IWL_DEBUG_RATE ("decrease rate because of low tpt\n"); @@ -810,17 +804,17 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, out: - sta->last_txrate = index; - if (priv->phymode == (u8) MODE_IEEE80211A) - sta->txrate = sta->last_txrate - IWL_FIRST_OFDM_RATE; + sta->last_txrate_idx = index; + if (sband->band == IEEE80211_BAND_5GHZ) + sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; else - sta->txrate = sta->last_txrate; + sta->txrate_idx = sta->last_txrate_idx; - sta_info_put(sta); + rcu_read_unlock(); IWL_DEBUG_RATE("leave: %d\n", index); - sel->rate = &priv->ieee_rates[index]; + sel->rate = &sband->bitrates[sta->txrate_idx]; } static struct rate_control_ops rs_ops = { @@ -848,13 +842,15 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) unsigned long now = jiffies; u32 max_time = 0; + rcu_read_lock(); + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); if (!sta || !sta->rate_ctrl_priv) { - if (sta) { - sta_info_put(sta); + if (sta) IWL_DEBUG_RATE("leave - no private rate data!\n"); - } else + else IWL_DEBUG_RATE("leave - no station!\n"); + rcu_read_unlock(); return sprintf(buf, "station %d not found\n", sta_id); } @@ -895,7 +891,7 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) i = j; } spin_unlock_irqrestore(&rs_sta->lock, flags); - sta_info_put(sta); + rcu_read_unlock(); /* Display the average rate of all samples taken. * @@ -932,11 +928,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) return; } + rcu_read_lock(); + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); if (!sta || !sta->rate_ctrl_priv) { - if (sta) - sta_info_put(sta); IWL_DEBUG_RATE("leave - no private rate data!\n"); + rcu_read_unlock(); return; } @@ -945,8 +942,9 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) spin_lock_irqsave(&rs_sta->lock, flags); rs_sta->tgg = 0; - switch (priv->phymode) { - case MODE_IEEE80211G: + switch (priv->band) { + case IEEE80211_BAND_2GHZ: + /* TODO: this always does G, not a regression */ if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) { rs_sta->tgg = 1; rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot; @@ -954,18 +952,15 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rs_sta->expected_tpt = iwl3945_expected_tpt_g; break; - case MODE_IEEE80211A: + case IEEE80211_BAND_5GHZ: rs_sta->expected_tpt = iwl3945_expected_tpt_a; break; - - default: - IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n"); - case MODE_IEEE80211B: - rs_sta->expected_tpt = iwl3945_expected_tpt_b; + case IEEE80211_NUM_BANDS: + BUG(); break; } - sta_info_put(sta); + rcu_read_unlock(); spin_unlock_irqrestore(&rs_sta->lock, flags); rssi = priv->last_rx_rssi; @@ -974,20 +969,19 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi); - rs_sta->start_rate = - iwl3945_get_rate_index_by_rssi(rssi, priv->phymode); + rs_sta->start_rate = iwl3945_get_rate_index_by_rssi(rssi, priv->band); IWL_DEBUG_RATE("leave: rssi %d assign rate index: " "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, iwl3945_rates[rs_sta->start_rate].plcp); } -void iwl3945_rate_control_register(struct ieee80211_hw *hw) +int iwl3945_rate_control_register(void) { - ieee80211_rate_control_register(&rs_ops); + return ieee80211_rate_control_register(&rs_ops); } -void iwl3945_rate_control_unregister(struct ieee80211_hw *hw) +void iwl3945_rate_control_unregister(void) { ieee80211_rate_control_unregister(&rs_ops); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index d5e9220f871..f085d330bdc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -36,8 +36,8 @@ struct iwl3945_rate_info { u8 next_rs; /* next rate used in rs algo */ u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ u8 next_rs_tgg; /* next rate used in TGG rs algo */ - u8 table_rs_index; /* index in rate scale table cmd */ - u8 prev_table_rs; /* prev in rate table cmd */ + u8 table_rs_index; /* index in rate scale table cmd */ + u8 prev_table_rs; /* prev in rate table cmd */ }; /* @@ -159,7 +159,7 @@ enum { #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) -#define IWL_INVALID_VALUE -1 +#define IWL_INV_TPT -1 #define IWL_MIN_RSSI_VAL -100 #define IWL_MAX_RSSI_VAL 0 @@ -202,7 +202,7 @@ extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); * ieee80211_register_hw * */ -extern void iwl3945_rate_control_register(struct ieee80211_hw *hw); +extern int iwl3945_rate_control_register(void); /** * iwl3945_rate_control_unregister - Unregister the rate control callbacks @@ -210,6 +210,6 @@ extern void iwl3945_rate_control_register(struct ieee80211_hw *hw); * This should be called after calling ieee80211_unregister_hw, but before * the driver is unloaded. */ -extern void iwl3945_rate_control_unregister(struct ieee80211_hw *hw); +extern void iwl3945_rate_control_unregister(void); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8d4d91d35fd..598e4eef4f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -39,6 +39,7 @@ #include <asm/unaligned.h> #include <net/mac80211.h> +#include "iwl-3945-core.h" #include "iwl-3945.h" #include "iwl-helpers.h" #include "iwl-3945-rs.h" @@ -183,6 +184,16 @@ void iwl3945_disable_events(struct iwl3945_priv *priv) } +static int iwl3945_hwrate_to_plcp_idx(u8 plcp) +{ + int idx; + + for (idx = 0; idx < IWL_RATE_COUNT; idx++) + if (iwl3945_rates[idx].plcp == plcp) + return idx; + return -1; +} + /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -216,14 +227,126 @@ __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv) return 0; /* "diversity" is default if error */ } +#ifdef CONFIG_IWL3945_DEBUG +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +static const char *iwl3945_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} +#else +static inline const char *iwl3945_get_tx_fail_reason(u32 status) +{ + return ""; +} +#endif + + +/** + * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd + * + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. As result, some free space forms. If there is + * enough free space (> low mark), wake the stack that feeds us. + */ +static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, + int txq_id, int index) +{ + struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; + struct iwl3945_queue *q = &txq->q; + struct iwl3945_tx_info *tx_info; + + BUG_ON(txq_id == IWL_CMD_QUEUE_NUM); + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + tx_info = &txq->txb[txq->q.read_ptr]; + ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0], + &tx_info->status); + tx_info->skb[0] = NULL; + iwl3945_hw_txq_free_tfd(priv, txq); + } + + if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && + (txq_id != IWL_CMD_QUEUE_NUM) && + priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); +} + +/** + * iwl3945_rx_reply_tx - Handle Tx response + */ +static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) +{ + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_status *tx_status; + struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->status); + int rate_idx; + + if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); + return; + } + + tx_status = &(txq->txb[txq->q.read_ptr].status); + + tx_status->retry_count = tx_resp->failure_frame; + /* tx_status->rts_retry_count = tx_resp->failure_rts; */ + tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? + IEEE80211_TX_STATUS_ACK : 0; + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", + txq_id, iwl3945_get_tx_fail_reason(status), status, + tx_resp->rate, tx_resp->failure_frame); + + rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); + tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + iwl3945_tx_queue_reclaim(priv, txq_id, index); + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + + + /***************************************************************************** * * Intel PRO/Wireless 3945ABG/BG Network Connection * * RX handler implementations * - * Used by iwl-base.c - * *****************************************************************************/ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) @@ -235,9 +358,161 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics)); + iwl3945_led_background(priv); + priv->last_statistics_time = jiffies; } +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ +#ifdef CONFIG_IWL3945_DEBUG + +/** + * iwl3945_report_frame - dump frame to syslog during debug sessions + * + * You may hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + */ +static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + u32 rate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); + if (rate == -1) + rate = 0; + else + rate = iwl3945_rates[rate].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, rate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl3945_print_hex_dump(IWL_DL_RX, data, length); +} +#else +static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ +} +#endif + + static void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb, struct iwl3945_rx_frame_hdr *rx_hdr, @@ -247,9 +522,9 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, * the information provided in the skb from the hardware */ s8 signal = stats->ssi; s8 noise = 0; - int rate = stats->rate; + int rate = stats->rate_idx; u64 tsf = stats->mactime; - __le16 phy_flags_hw = rx_hdr->phy_flags; + __le16 phy_flags_hw = rx_hdr->phy_flags, antenna; struct iwl3945_rt_rx_hdr { struct ieee80211_radiotap_header rt_hdr; @@ -315,15 +590,14 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, IEEE80211_CHAN_2GHZ), &iwl3945_rt->rt_chbitmask); - rate = iwl3945_rate_index_from_plcp(rate); if (rate == -1) iwl3945_rt->rt_rate = 0; else iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee; /* antenna number */ - iwl3945_rt->rt_antenna = - le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; + iwl3945_rt->rt_antenna = le16_to_cpu(antenna) >> 4; /* set the preamble flag if we have it */ if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) @@ -368,6 +642,10 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, if (priv->add_radiotap) iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); +#ifdef CONFIG_IWL3945_LEDS + if (is_data) + priv->rxtxpackets += len; +#endif ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); rxb->skb = NULL; } @@ -377,25 +655,28 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) { + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); - struct ieee80211_hdr *header; + int snr; u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); - struct ieee80211_rx_status stats = { - .mactime = le64_to_cpu(rx_end->timestamp), - .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)), - .channel = le16_to_cpu(rx_hdr->channel), - .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - MODE_IEEE80211G : MODE_IEEE80211A, - .antenna = 0, - .rate = rx_hdr->rate, - .flag = 0, - }; u8 network_packet; - int snr; + + rx_status.antenna = 0; + rx_status.flag = 0; + rx_status.mactime = le64_to_cpu(rx_end->timestamp); + rx_status.freq = + ieee80211_frequency_to_channel(le16_to_cpu(rx_hdr->channel)); + rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + + rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); + if (rx_status.band == IEEE80211_BAND_5GHZ) + rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; if ((unlikely(rx_stats->phy_count > 20))) { IWL_DEBUG_DROP @@ -411,12 +692,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_handle_data_packet(priv, 1, rxb, &stats); + iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); return; } /* Convert 3945's rssi indicator to dBm */ - stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; /* Set default noise value to -127 */ if (priv->last_rx_noise == 0) @@ -432,51 +713,47 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, * signal-to-noise ratio (SNR) is (sig_avg / noise_diff). * Convert linear SNR to dB SNR, then subtract that from rssi dBm * to obtain noise level in dBm. - * Calculate stats.signal (quality indicator in %) based on SNR. */ + * Calculate rx_status.signal (quality indicator in %) based on SNR. */ if (rx_stats_noise_diff) { snr = rx_stats_sig_avg / rx_stats_noise_diff; - stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr); - stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise); + rx_status.noise = rx_status.ssi - + iwl3945_calc_db_from_ratio(snr); + rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, + rx_status.noise); /* If noise info not available, calculate signal quality indicator (%) * using just the dBm signal level. */ } else { - stats.noise = priv->last_rx_noise; - stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0); + rx_status.noise = priv->last_rx_noise; + rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0); } IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", - stats.ssi, stats.noise, stats.signal, + rx_status.ssi, rx_status.noise, rx_status.signal, rx_stats_sig_avg, rx_stats_noise_diff); - stats.freq = ieee80211chan2mhz(stats.channel); - - /* can be covered by iwl3945_report_frame() in most cases */ -/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ - header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); network_packet = iwl3945_is_network_packet(priv, header); -#ifdef CONFIG_IWL3945_DEBUG - if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit()) - IWL_DEBUG_STATS - ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", - network_packet ? '*' : ' ', - stats.channel, stats.ssi, stats.ssi, - stats.ssi, stats.rate); + IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", + network_packet ? '*' : ' ', + le16_to_cpu(rx_hdr->channel), + rx_status.ssi, rx_status.ssi, + rx_status.ssi, rx_status.rate_idx); +#ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_RX)) /* Set "1" to report good data frames in groups of 100 */ - iwl3945_report_frame(priv, pkt, header, 1); + iwl3945_dbg_report_frame(priv, pkt, header, 1); #endif if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); priv->last_tsf = le64_to_cpu(rx_end->timestamp); - priv->last_rx_rssi = stats.ssi; - priv->last_rx_noise = stats.noise; + priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_noise = rx_status.noise; } switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { @@ -563,7 +840,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } } - iwl3945_handle_data_packet(priv, 0, rxb, &stats); + iwl3945_handle_data_packet(priv, 0, rxb, &rx_status); break; case IEEE80211_FTYPE_CTL: @@ -580,7 +857,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, print_mac(mac2, header->addr2), print_mac(mac3, header->addr3)); else - iwl3945_handle_data_packet(priv, 1, rxb, &stats); + iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); break; } } @@ -689,7 +966,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); + u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; u8 rts_retry_limit; @@ -709,7 +986,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, priv->stations[sta_id].current_rate.rate_n_flags = rate; if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - (sta_id != IWL3945_BROADCAST_ID) && + (sta_id != priv->hw_setting.bcast_sta_id) && (sta_id != IWL_MULTICAST_ID)) priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate; @@ -996,19 +1273,19 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) if (rev_id & PCI_CFG_REV_ID_BIT_RTP) IWL_DEBUG_INFO("RTP type \n"); else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { - IWL_DEBUG_INFO("ALM-MB type\n"); + IWL_DEBUG_INFO("3945 RADIO-MB type\n"); iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB); + CSR39_HW_IF_CONFIG_REG_BIT_3945_MB); } else { - IWL_DEBUG_INFO("ALM-MM type\n"); + IWL_DEBUG_INFO("3945 RADIO-MM type\n"); iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM); + CSR39_HW_IF_CONFIG_REG_BIT_3945_MM); } if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) { IWL_DEBUG_INFO("SKU OP mode is mrc\n"); iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC); + CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC); } else IWL_DEBUG_INFO("SKU OP mode is basic\n"); @@ -1016,24 +1293,24 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", priv->eeprom.board_revision); iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); + CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); } else { IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", priv->eeprom.board_revision); iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); + CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); } if (priv->eeprom.almgor_m_version <= 1) { iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); + CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); IWL_DEBUG_INFO("Card M type A version is 0x%X\n", priv->eeprom.almgor_m_version); } else { IWL_DEBUG_INFO("Card M type B version is 0x%X\n", priv->eeprom.almgor_m_version); iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); + CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); } spin_unlock_irqrestore(&priv->lock, flags); @@ -1552,14 +1829,14 @@ int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv) .channel = priv->active_rxon.channel, }; - txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1; + txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1; ch_info = iwl3945_get_channel_info(priv, - priv->phymode, + priv->band, le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) { IWL_ERROR ("Failed to get channel info for channel %d [%d]\n", - le16_to_cpu(priv->active_rxon.channel), priv->phymode); + le16_to_cpu(priv->active_rxon.channel), priv->band); return -EINVAL; } @@ -2241,8 +2518,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index; } - switch (priv->phymode) { - case MODE_IEEE80211A: + switch (priv->band) { + case IEEE80211_BAND_5GHZ: IWL_DEBUG_RATE("Select A mode rate scale\n"); /* If one of the following CCK rates is used, * have it fall back to the 6M OFDM rate */ @@ -2257,8 +2534,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; break; - case MODE_IEEE80211B: - IWL_DEBUG_RATE("Select B mode rate scale\n"); + case IEEE80211_BAND_2GHZ: + IWL_DEBUG_RATE("Select B/G mode rate scale\n"); /* If an OFDM rate is used, have it fall back to the * 1M CCK rates */ for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++) @@ -2269,7 +2546,7 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) break; default: - IWL_DEBUG_RATE("Select G mode rate scale\n"); + WARN_ON(1); break; } @@ -2303,7 +2580,6 @@ int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv) return -ENOMEM; } - priv->hw_setting.ac_queue_count = AC_NUM; priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE; priv->hw_setting.max_pkt_size = 2342; priv->hw_setting.tx_cmd_len = sizeof(struct iwl3945_tx_cmd); @@ -2311,6 +2587,8 @@ int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv) priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_setting.max_stations = IWL3945_STATION_COUNT; priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID; + + priv->hw_setting.tx_ant_num = 2; return 0; } @@ -2323,7 +2601,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u; memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID; + tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id; tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; frame_size = iwl3945_fill_beacon_frame(priv, @@ -2350,6 +2628,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv) { + priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; } @@ -2364,9 +2643,25 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv) cancel_delayed_work(&priv->thermal_periodic); } +static struct iwl_3945_cfg iwl3945_bg_cfg = { + .name = "3945BG", + .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .sku = IWL_SKU_G, +}; + +static struct iwl_3945_cfg iwl3945_abg_cfg = { + .name = "3945ABG", + .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G, +}; + struct pci_device_id iwl3945_hw_card_ids[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)}, + {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)}, + {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)}, + {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)}, + {IWL_PCI_DEVICE(0x4227, 0x1014, iwl3945_bg_cfg)}, + {IWL_PCI_DEVICE(0x4222, PCI_ANY_ID, iwl3945_abg_cfg)}, + {IWL_PCI_DEVICE(0x4227, PCI_ANY_ID, iwl3945_abg_cfg)}, {0} }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 1da14f9bbe0..3dc7f0fbf02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -40,9 +40,17 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #define DRV_NAME "iwl3945" -#include "iwl-3945-hw.h" +#include "iwl-csr.h" #include "iwl-prph.h" +#include "iwl-3945-hw.h" #include "iwl-3945-debug.h" +#include "iwl-3945-led.h" + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL3945_UCODE_API "-1" /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -109,6 +117,9 @@ struct iwl3945_queue { * space less than this */ } __attribute__ ((packed)); +int iwl3945_queue_space(const struct iwl3945_queue *q); +int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i); + #define MAX_NUM_OF_TBS (20) /* One for each TFD */ @@ -195,7 +206,7 @@ struct iwl3945_channel_info { u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ - u8 phymode; /* MODE_IEEE80211{A,B,G} */ + enum ieee80211_band band; /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -269,8 +280,8 @@ struct iwl3945_frame { #define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) #define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) -#define SEQ_TO_INDEX(x) (x & 0xff) -#define INDEX_TO_SEQ(x) (x & 0xff) +#define SEQ_TO_INDEX(x) ((u8)(x & 0xff)) +#define INDEX_TO_SEQ(x) ((u8)(x & 0xff)) #define SEQ_HUGE_FRAME (0x4000) #define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) @@ -390,23 +401,24 @@ struct iwl3945_rx_queue { #define MIN_B_CHANNELS 1 #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ -#define STATUS_INT_ENABLED 1 -#define STATUS_RF_KILL_HW 2 -#define STATUS_RF_KILL_SW 3 -#define STATUS_INIT 4 -#define STATUS_ALIVE 5 -#define STATUS_READY 6 -#define STATUS_TEMPERATURE 7 -#define STATUS_GEO_CONFIGURED 8 -#define STATUS_EXIT_PENDING 9 -#define STATUS_IN_SUSPEND 10 -#define STATUS_STATISTICS 11 -#define STATUS_SCANNING 12 -#define STATUS_SCAN_ABORTING 13 -#define STATUS_SCAN_HW 14 -#define STATUS_POWER_PMI 15 -#define STATUS_FW_ERROR 16 -#define STATUS_CONF_PENDING 17 +#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ +#define STATUS_INT_ENABLED 2 +#define STATUS_RF_KILL_HW 3 +#define STATUS_RF_KILL_SW 4 +#define STATUS_INIT 5 +#define STATUS_ALIVE 6 +#define STATUS_READY 7 +#define STATUS_TEMPERATURE 8 +#define STATUS_GEO_CONFIGURED 9 +#define STATUS_EXIT_PENDING 10 +#define STATUS_IN_SUSPEND 11 +#define STATUS_STATISTICS 12 +#define STATUS_SCANNING 13 +#define STATUS_SCAN_ABORTING 14 +#define STATUS_SCAN_HW 15 +#define STATUS_POWER_PMI 16 +#define STATUS_FW_ERROR 17 +#define STATUS_CONF_PENDING 18 #define MAX_TID_COUNT 9 @@ -431,8 +443,6 @@ union iwl3945_ht_rate_supp { }; }; -#ifdef CONFIG_IWL3945_QOS - union iwl3945_qos_capabity { struct { u8 edca_count:4; /* bit 0-3 */ @@ -460,7 +470,6 @@ struct iwl3945_qos_info { union iwl3945_qos_capabity qos_cap; struct iwl3945_qosparam_cmd def_qos_parm; }; -#endif /*CONFIG_IWL3945_QOS */ #define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_SLEEP 1 @@ -511,8 +520,8 @@ struct iwl3945_ibss_seq { /** * struct iwl3945_driver_hw_info * @max_txq_num: Max # Tx queues supported - * @ac_queue_count: # Tx queues for EDCA Access Categories (AC) * @tx_cmd_len: Size of Tx command (but not including frame itself) + * @tx_ant_num: Number of TX antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) * @rx_buf_size: * @max_pkt_size: @@ -524,8 +533,8 @@ struct iwl3945_ibss_seq { */ struct iwl3945_driver_hw_info { u16 max_txq_num; - u16 ac_queue_count; u16 tx_cmd_len; + u16 tx_ant_num; u16 max_rxq_size; u32 rx_buf_size; u32 max_pkt_size; @@ -561,16 +570,6 @@ extern int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header); extern int iwl3945_power_init_handle(struct iwl3945_priv *priv); extern int iwl3945_eeprom_init(struct iwl3945_priv *priv); -#ifdef CONFIG_IWL3945_DEBUG -extern void iwl3945_report_frame(struct iwl3945_priv *priv, - struct iwl3945_rx_packet *pkt, - struct ieee80211_hdr *header, int group100); -#else -static inline void iwl3945_report_frame(struct iwl3945_priv *priv, - struct iwl3945_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) {} -#endif extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb, void *data, short len, @@ -694,19 +693,20 @@ struct iwl3945_priv { struct ieee80211_hw *hw; struct ieee80211_channel *ieee_channels; struct ieee80211_rate *ieee_rates; + struct iwl_3945_cfg *cfg; /* device configuration */ /* temporary frame storage list */ struct list_head free_frames; int frames_count; - u8 phymode; + enum ieee80211_band band; int alloc_rxb_skb; bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb); - const struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ @@ -779,13 +779,15 @@ struct iwl3945_priv { struct iwl3945_init_alive_resp card_alive_init; struct iwl3945_alive_resp card_alive; -#ifdef LED - /* LED related variables */ - struct iwl3945_activity_blink activity; - unsigned long led_packets; - int led_state; +#ifdef CONFIG_IWL3945_LEDS + struct iwl3945_led led[IWL_LED_TRG_MAX]; + unsigned long last_blink_time; + u8 last_blink_rate; + u8 allow_blinking; + unsigned int rxtxpackets; #endif + u16 active_rate; u16 active_rate_basic; @@ -803,7 +805,6 @@ struct iwl3945_priv { struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long status; - u32 config; int last_rx_rssi; /* From Rx packet statisitics */ int last_rx_noise; /* From beacon statistics */ @@ -830,10 +831,9 @@ struct iwl3945_priv { struct iwl3945_station_entry stations[IWL_STATION_COUNT]; /* Indication if ieee80211_ops->open has been called */ - int is_open; + u8 is_open; u8 mac80211_registered; - int is_abg; u32 notif_missed_beacons; @@ -852,7 +852,7 @@ struct iwl3945_priv { /* eeprom */ struct iwl3945_eeprom eeprom; - int iw_mode; + enum ieee80211_if_types iw_mode; struct sk_buff *ibss_beacon; @@ -869,9 +869,7 @@ struct iwl3945_priv { u16 assoc_capability; u8 ps_mode; -#ifdef CONFIG_IWL3945_QOS struct iwl3945_qos_info qos_data; -#endif /*CONFIG_IWL3945_QOS */ struct workqueue_struct *workqueue; @@ -937,13 +935,12 @@ static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info) static inline u8 is_channel_a_band(const struct iwl3945_channel_info *ch_info) { - return ch_info->phymode == MODE_IEEE80211A; + return ch_info->band == IEEE80211_BAND_5GHZ; } static inline u8 is_channel_bg_band(const struct iwl3945_channel_info *ch_info) { - return ((ch_info->phymode == MODE_IEEE80211B) || - (ch_info->phymode == MODE_IEEE80211G)); + return ch_info->band == IEEE80211_BAND_2GHZ; } static inline int is_channel_passive(const struct iwl3945_channel_info *ch) @@ -956,18 +953,8 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -static inline int iwl3945_rate_index_from_plcp(int plcp) -{ - int i; - - for (i = 0; i < IWL_RATE_COUNT; i++) - if (iwl3945_rates[i].plcp == plcp) - return i; - return -1; -} - extern const struct iwl3945_channel_info *iwl3945_get_channel_info( - const struct iwl3945_priv *priv, int phymode, u16 channel); + const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); /* Requires full declaration of iwl3945_priv before including */ #include "iwl-3945-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index f3470c896d9..7e36ecb2757 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -139,7 +139,7 @@ enum { REPLY_PHY_CALIBRATION_CMD = 0xb0, REPLY_RX_PHY_CMD = 0xc0, REPLY_RX_MPDU_CMD = 0xc1, - REPLY_4965_RX = 0xc3, + REPLY_RX = 0xc3, REPLY_COMPRESSED_BA = 0xc5, REPLY_MAX = 0xff }; @@ -151,16 +151,16 @@ enum { * *****************************************************************************/ -/* iwl4965_cmd_header flags value */ +/* iwl_cmd_header flags value */ #define IWL_CMD_FAILED_MSK 0x40 /** - * struct iwl4965_cmd_header + * struct iwl_cmd_header * * This header format appears in the beginning of each command sent from the * driver, and each response/notification received from uCode. */ -struct iwl4965_cmd_header { +struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* IWL_CMD_* */ /* @@ -194,7 +194,7 @@ struct iwl4965_cmd_header { * 4965 rate_n_flags bit fields * * rate_n_flags format is used in following 4965 commands: - * REPLY_4965_RX (response only) + * REPLY_RX (response only) * REPLY_TX (both command and response) * REPLY_TX_LINK_QUALITY_CMD * @@ -727,14 +727,21 @@ struct iwl4965_qosparam_cmd { #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3) +#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 #define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +/* wep key is either from global key (0) or from station info array (1) */ +#define STA_KEY_FLG_MAP_KEY_MSK __constant_cpu_to_le16(0x0008) + +/* wep key in STA: 5-bytes (0) or 13-bytes (1) */ +#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) +#define STA_KEY_MAX_NUM 8 /* Flags indicate whether to modify vs. don't change various station params */ #define STA_MODIFY_KEY_MASK 0x01 @@ -752,7 +759,8 @@ struct iwl4965_keyinfo { u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ u8 reserved1; __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - __le16 reserved2; + u8 key_offset; + u8 reserved2; u8 key[16]; /* 16-byte unicast decryption key */ } __attribute__ ((packed)); @@ -868,26 +876,35 @@ struct iwl4965_rx_frame_hdr { u8 payload[0]; } __attribute__ ((packed)); -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) +#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) + +#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) + +#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) +#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) +#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) +#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) +#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) +#define RX_RES_STATUS_SEC_TYPE_ERR (0x7 << 8) -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) +#define RX_RES_STATUS_STATION_FOUND (1<<6) +#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7) -#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) -#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) -#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) -#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) -#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) +#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) +#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) +#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) +#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) +#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) -#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) -#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) -#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) -#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) -#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) +#define RX_MPDU_RES_STATUS_ICV_OK (0x20) +#define RX_MPDU_RES_STATUS_MIC_OK (0x40) +#define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) +#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) struct iwl4965_rx_frame_end { __le32 status; @@ -922,7 +939,7 @@ struct iwl4965_rx_non_cfg_phy { } __attribute__ ((packed)); /* - * REPLY_4965_RX = 0xc3 (response only, not a command) + * REPLY_RX = 0xc3 (response only, not a command) * Used only for legacy (non 11n) frames. */ #define RX_RES_PHY_CNT 14 @@ -1038,6 +1055,10 @@ struct iwl4965_rx_mpdu_res_start { * MAC header) to DWORD boundary. */ #define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +/* accelerate aggregation support + * 0 - no CCMP encryption; 1 - CCMP encryption */ +#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22) + /* HCCA-AP - disable duration overwriting. */ #define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) @@ -1300,6 +1321,25 @@ struct iwl4965_tx_resp { __le32 status; /* TX status (for aggregation status of 1st frame) */ } __attribute__ ((packed)); +struct agg_tx_status { + __le16 status; + __le16 sequence; +} __attribute__ ((packed)); + +struct iwl4965_tx_resp_agg { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 reserved1; + u8 failure_rts; + u8 failure_frame; + __le32 rate_n_flags; + __le16 wireless_media_time; + __le16 reserved3; + __le32 pa_power1; + __le32 pa_power2; + struct agg_tx_status status; /* TX status (for aggregation status */ + /* of 1st frame) */ +} __attribute__ ((packed)); + /* * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) * @@ -1313,9 +1353,8 @@ struct iwl4965_compressed_ba_resp { /* Index of recipient (BA-sending) station in uCode's station table */ u8 sta_id; u8 tid; - __le16 ba_seq_ctl; - __le32 ba_bitmap0; - __le32 ba_bitmap1; + __le16 seq_ctl; + __le64 bitmap; __le16 scd_flow; __le16 scd_ssn; } __attribute__ ((packed)); @@ -2625,7 +2664,7 @@ struct iwl4965_led_cmd { struct iwl4965_rx_packet { __le32 len; - struct iwl4965_cmd_header hdr; + struct iwl_cmd_header hdr; union { struct iwl4965_alive_resp alive_frame; struct iwl4965_rx_frame rx_frame; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index ffe1e9dfdec..de7bac14972 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,316 +92,6 @@ /* RSSI to dBm */ #define IWL_RSSI_OFFSET 44 -/* - * EEPROM related constants, enums, and structures. - */ - -/* - * EEPROM access time values: - * - * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, - * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit - * CSR_EEPROM_REG_BIT_CMD (0x2). - * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). - * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. - * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. - */ -#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ - -/* - * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags. - * - * IBSS and/or AP operation is allowed *only* on those channels with - * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because - * RADAR detection is not supported by the 4965 driver, but is a - * requirement for establishing a new network for legal operation on channels - * requiring RADAR detection or restricting ACTIVE scanning. - * - * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. - * It only indicates that 20 MHz channel use is supported; FAT channel - * usage is indicated by a separate set of regulatory flags for each - * FAT channel pair. - * - * NOTE: Using a channel inappropriately will result in a uCode error! - */ -enum { - EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ - EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ - /* Bit 2 Reserved */ - EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ - EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ - EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ - EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ - EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ -}; - -/* SKU Capabilities */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) - -/* *regulatory* channel data format in eeprom, one for each channel. - * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ -struct iwl4965_eeprom_channel { - u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ - s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ -} __attribute__ ((packed)); - -/* 4965 has two radio transmitters (and 3 radio receivers) */ -#define EEPROM_TX_POWER_TX_CHAINS (2) - -/* 4965 has room for up to 8 sets of txpower calibration data */ -#define EEPROM_TX_POWER_BANDS (8) - -/* 4965 factory calibration measures txpower gain settings for - * each of 3 target output levels */ -#define EEPROM_TX_POWER_MEASUREMENTS (3) - -/* 4965 driver does not work with txpower calibration version < 5. - * Look for this in calib_version member of struct iwl4965_eeprom. */ -#define EEPROM_TX_POWER_VERSION_NEW (5) - - -/* - * 4965 factory calibration data for one txpower level, on one channel, - * measured on one of the 2 tx chains (radio transmitter and associated - * antenna). EEPROM contains: - * - * 1) Temperature (degrees Celsius) of device when measurement was made. - * - * 2) Gain table index used to achieve the target measurement power. - * This refers to the "well-known" gain tables (see iwl-4965-hw.h). - * - * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). - * - * 4) RF power amplifier detector level measurement (not used). - */ -struct iwl4965_eeprom_calib_measure { - u8 temperature; /* Device temperature (Celsius) */ - u8 gain_idx; /* Index into gain table */ - u8 actual_pow; /* Measured RF output power, half-dBm */ - s8 pa_det; /* Power amp detector level (not used) */ -} __attribute__ ((packed)); - - -/* - * 4965 measurement set for one channel. EEPROM contains: - * - * 1) Channel number measured - * - * 2) Measurements for each of 3 power levels for each of 2 radio transmitters - * (a.k.a. "tx chains") (6 measurements altogether) - */ -struct iwl4965_eeprom_calib_ch_info { - u8 ch_num; - struct iwl4965_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __attribute__ ((packed)); - -/* - * 4965 txpower subband info. - * - * For each frequency subband, EEPROM contains the following: - * - * 1) First and last channels within range of the subband. "0" values - * indicate that this sample set is not being used. - * - * 2) Sample measurement sets for 2 channels close to the range endpoints. - */ -struct iwl4965_eeprom_calib_subband_info { - u8 ch_from; /* channel number of lowest channel in subband */ - u8 ch_to; /* channel number of highest channel in subband */ - struct iwl4965_eeprom_calib_ch_info ch1; - struct iwl4965_eeprom_calib_ch_info ch2; -} __attribute__ ((packed)); - - -/* - * 4965 txpower calibration info. EEPROM contains: - * - * 1) Factory-measured saturation power levels (maximum levels at which - * tx power amplifier can output a signal without too much distortion). - * There is one level for 2.4 GHz band and one for 5 GHz band. These - * values apply to all channels within each of the bands. - * - * 2) Factory-measured power supply voltage level. This is assumed to be - * constant (i.e. same value applies to all channels/bands) while the - * factory measurements are being made. - * - * 3) Up to 8 sets of factory-measured txpower calibration values. - * These are for different frequency ranges, since txpower gain - * characteristics of the analog radio circuitry vary with frequency. - * - * Not all sets need to be filled with data; - * struct iwl4965_eeprom_calib_subband_info contains range of channels - * (0 if unused) for each set of data. - */ -struct iwl4965_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ - s16 voltage; /* signed */ - struct iwl4965_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; -} __attribute__ ((packed)); - - -/* - * 4965 EEPROM map - */ -struct iwl4965_eeprom { - u8 reserved0[16]; -#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ - u16 device_id; /* abs.ofs: 16 */ - u8 reserved1[2]; -#define EEPROM_PMC (2*0x0A) /* 2 bytes */ - u16 pmc; /* abs.ofs: 20 */ - u8 reserved2[20]; -#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ - u8 mac_address[6]; /* abs.ofs: 42 */ - u8 reserved3[58]; -#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ - u16 board_revision; /* abs.ofs: 106 */ - u8 reserved4[11]; -#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ - u8 board_pba_number[9]; /* abs.ofs: 119 */ - u8 reserved5[8]; -#define EEPROM_VERSION (2*0x44) /* 2 bytes */ - u16 version; /* abs.ofs: 136 */ -#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ - u8 sku_cap; /* abs.ofs: 138 */ -#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ - u8 leds_mode; /* abs.ofs: 139 */ -#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ - u16 oem_mode; -#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ - u16 wowlan_mode; /* abs.ofs: 142 */ -#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ - u16 leds_time_interval; /* abs.ofs: 144 */ -#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ - u8 leds_off_time; /* abs.ofs: 146 */ -#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ - u8 leds_on_time; /* abs.ofs: 147 */ -#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ - u8 almgor_m_version; /* abs.ofs: 148 */ -#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ - u8 antenna_switch_type; /* abs.ofs: 149 */ - u8 reserved6[8]; -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ - u16 board_revision_4965; /* abs.ofs: 158 */ - u8 reserved7[13]; -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ - u8 reserved8[10]; -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ - u8 sku_id[4]; /* abs.ofs: 192 */ - -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by 3945 or 4965 has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ - u16 band_1_count; /* abs.ofs: 196 */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ - u16 band_2_count; /* abs.ofs: 226 */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ - u16 band_3_count; /* abs.ofs: 254 */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ - u16 band_4_count; /* abs.ofs: 280 */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ - u16 band_5_count; /* abs.ofs: 304 */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ - - u8 reserved10[2]; - - -/* - * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) - * - * The channel listed is the center of the lower 20 MHz half of the channel. - * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each FAT channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, - * and the overall FAT channel width centers on channel 3. - * - * NOTE: The RXON command uses 20 MHz channel numbers to specify the - * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a FAT channel. - * - * NOTE: 4965 does not support FAT channels on 2.4 GHz. - */ -#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ - struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ - u8 reserved11[2]; - -/* - * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), - * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) - */ -#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ - struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ - u8 reserved12[6]; - -/* - * 4965 driver requires txpower calibration format version 5 or greater. - * Driver does not work with txpower calibration version < 5. - * This value is simply a 16-bit number, no major/minor versions here. - */ -#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ - u16 calib_version; /* abs.ofs: 364 */ - u8 reserved13[2]; - u8 reserved14[96]; /* abs.ofs: 368 */ - -/* - * 4965 Txpower calibration data. - */ -#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ - struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ - - u8 reserved16[140]; /* fill out to full 1024 byte block */ - - -} __attribute__ ((packed)); - -#define IWL_EEPROM_IMAGE_SIZE 1024 - -/* End of EEPROM */ #include "iwl-4965-commands.h" @@ -410,182 +100,6 @@ struct iwl4965_eeprom { #define PCI_REG_WUM8 0x0E8 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -/*=== CSR (control and status registers) ===*/ -#define CSR_BASE (0x000) - -#define CSR_SW_VER (CSR_BASE+0x000) -#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ -#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ -#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ -#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ -#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ -#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ -#define CSR_GP_CNTRL (CSR_BASE+0x024) - -/* - * Hardware revision info - * Bit fields: - * 31-8: Reserved - * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 - * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D - * 1-0: "Dash" value, as in A-1, etc. - * - * NOTE: Revision step affects calculation of CCK txpower for 4965. - */ -#define CSR_HW_REV (CSR_BASE+0x028) - -/* EEPROM reads */ -#define CSR_EEPROM_REG (CSR_BASE+0x02c) -#define CSR_EEPROM_GP (CSR_BASE+0x030) -#define CSR_GP_UCODE (CSR_BASE+0x044) -#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) -#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) -#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) -#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) -#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) - -/* - * Indicates hardware rev, to determine CCK backoff for txpower calculation. - * Bit fields: - * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step - */ -#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) - -/* Hardware interface configuration bits */ -#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010) -#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) -#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) -#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) -#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) - -/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), - * acknowledged (reset) by host writing "1" to flagged bits. */ -#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ -#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ -#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ -#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ -#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ -#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ -#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ -#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ -#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ -#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ - -#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ - CSR_INT_BIT_HW_ERR | \ - CSR_INT_BIT_FH_TX | \ - CSR_INT_BIT_SW_ERR | \ - CSR_INT_BIT_RF_KILL | \ - CSR_INT_BIT_SW_RX | \ - CSR_INT_BIT_WAKEUP | \ - CSR_INT_BIT_ALIVE) - -/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ -#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ -#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ -#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ -#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ -#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ -#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ - -#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - -#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) - - -/* RESET */ -#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) -#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) -#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) -#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) -#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) - -/* GP (general purpose) CONTROL */ -#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) -#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) -#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) -#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) - -#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) - -#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) -#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) -#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) - - -/* EEPROM REG */ -#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) -#define CSR_EEPROM_REG_BIT_CMD (0x00000002) - -/* EEPROM GP */ -#define CSR_EEPROM_GP_VALID_MSK (0x00000006) -#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) -#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) - -/* UCODE DRV GP */ -#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) -#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) -#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) -#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) - -/* GPIO */ -#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) -#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) -#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER - -/* GI Chicken Bits */ -#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) -#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) - -/*=== HBUS (Host-side Bus) ===*/ -#define HBUS_BASE (0x400) - -/* - * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM - * structures, error log, event log, verifying uCode load). - * First write to address register, then read from or write to data register - * to complete the job. Once the address register is set up, accesses to - * data registers auto-increment the address by one dword. - * Bit usage for address registers (read or write): - * 0-31: memory address within device - */ -#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) -#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) -#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) -#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) - -/* - * Registers for accessing device's internal peripheral registers - * (e.g. SCD, BSM, etc.). First write to address register, - * then read from or write to data register to complete the job. - * Bit usage for address registers (read or write): - * 0-15: register address (offset) within device - * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) - */ -#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) -#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) -#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) -#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) - -/* - * Per-Tx-queue write pointer (index, really!) (3945 and 4965). - * Driver sets this to indicate index to next TFD that driver will fill - * (1 past latest filled). - * Bit usage: - * 0-7: queue write index (0-255) - * 11-8: queue selector (0-15) - */ -#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) - -#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) - -#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - #define TFD_QUEUE_SIZE_MAX (256) #define IWL_NUM_SCAN_RATES (2) @@ -599,9 +113,6 @@ struct iwl4965_eeprom { #define TFD_TX_CMD_SLOTS 256 #define TFD_CMD_SLOTS 32 -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \ - sizeof(struct iwl4965_cmd_meta)) - /* * RX related structures and functions */ @@ -615,16 +126,18 @@ struct iwl4965_eeprom { /* Sizes and addresses for instruction and data memory (SRAM) in * 4965's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ #define RTC_INST_LOWER_BOUND (0x000000) -#define KDR_RTC_INST_UPPER_BOUND (0x018000) +#define IWL49_RTC_INST_UPPER_BOUND (0x018000) #define RTC_DATA_LOWER_BOUND (0x800000) -#define KDR_RTC_DATA_UPPER_BOUND (0x80A000) +#define IWL49_RTC_DATA_UPPER_BOUND (0x80A000) -#define KDR_RTC_INST_SIZE (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) -#define KDR_RTC_DATA_SIZE (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) +#define IWL49_RTC_INST_SIZE \ + (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define IWL49_RTC_DATA_SIZE \ + (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) -#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE -#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE +#define IWL_MAX_INST_SIZE IWL49_RTC_INST_SIZE +#define IWL_MAX_DATA_SIZE IWL49_RTC_DATA_SIZE /* Size of uCode instruction memory in bootstrap state machine */ #define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE @@ -632,7 +145,7 @@ struct iwl4965_eeprom { static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) { return (addr >= RTC_DATA_LOWER_BOUND) && - (addr < KDR_RTC_DATA_UPPER_BOUND); + (addr < IWL49_RTC_DATA_UPPER_BOUND); } /********************* START TEMPERATURE *************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-io.h b/drivers/net/wireless/iwlwifi/iwl-4965-io.h deleted file mode 100644 index 34a0b57eea0..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965-io.h +++ /dev/null @@ -1,431 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl4965_io_h__ -#define __iwl4965_io_h__ - -#include <linux/io.h> - -#include "iwl-4965-debug.h" - -/* - * IO, register, and NIC memory access functions - * - * NOTE on naming convention and macro usage for these - * - * A single _ prefix before a an access function means that no state - * check or debug information is printed when that function is called. - * - * A double __ prefix before an access function means that state is checked - * and the current line number is printed in addition to any other debug output. - * - * The non-prefixed name is the #define that maps the caller into a - * #define that provides the caller's __LINE__ to the double prefix version. - * - * If you wish to call the function without any debug or state checking, - * you should use the single _ prefix version (as is used by dependent IO - * routines, for example _iwl4965_read_direct32 calls the non-check version of - * _iwl4965_read32.) - * - * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with - * git-bisect and the IO debug level you can quickly determine the specific - * commit which breaks the IO sequence to the hardware. - * - */ - -#define _iwl4965_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_write32(const char *f, u32 l, struct iwl4965_priv *iwl, - u32 ofs, u32 val) -{ - IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); - _iwl4965_write32(iwl, ofs, val); -} -#define iwl4965_write32(iwl, ofs, val) \ - __iwl4965_write32(__FILE__, __LINE__, iwl, ofs, val) -#else -#define iwl4965_write32(iwl, ofs, val) _iwl4965_write32(iwl, ofs, val) -#endif - -#define _iwl4965_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) -#ifdef CONFIG_IWL4965_DEBUG -static inline u32 __iwl4965_read32(char *f, u32 l, struct iwl4965_priv *iwl, u32 ofs) -{ - IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl4965_read32(iwl, ofs); -} -#define iwl4965_read32(iwl, ofs) __iwl4965_read32(__FILE__, __LINE__, iwl, ofs) -#else -#define iwl4965_read32(p, o) _iwl4965_read32(p, o) -#endif - -static inline int _iwl4965_poll_bit(struct iwl4965_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int i = 0; - - do { - if ((_iwl4965_read32(priv, addr) & mask) == (bits & mask)) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; -} -#ifdef CONFIG_IWL4965_DEBUG -static inline int __iwl4965_poll_bit(const char *f, u32 l, - struct iwl4965_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int ret = _iwl4965_poll_bit(priv, addr, bits, mask, timeout); - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO - ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", - addr, bits, mask, f, l); - else - IWL_DEBUG_IO - ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", - addr, bits, mask, ret, f, l); - return ret; -} -#define iwl4965_poll_bit(iwl, addr, bits, mask, timeout) \ - __iwl4965_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) -#else -#define iwl4965_poll_bit(p, a, b, m, t) _iwl4965_poll_bit(p, a, b, m, t) -#endif - -static inline void _iwl4965_set_bit(struct iwl4965_priv *priv, u32 reg, u32 mask) -{ - _iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) | mask); -} -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_set_bit(const char *f, u32 l, - struct iwl4965_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl4965_read32(priv, reg) | mask; - IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl4965_write32(priv, reg, val); -} -#define iwl4965_set_bit(p, r, m) __iwl4965_set_bit(__FILE__, __LINE__, p, r, m) -#else -#define iwl4965_set_bit(p, r, m) _iwl4965_set_bit(p, r, m) -#endif - -static inline void _iwl4965_clear_bit(struct iwl4965_priv *priv, u32 reg, u32 mask) -{ - _iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) & ~mask); -} -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_clear_bit(const char *f, u32 l, - struct iwl4965_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl4965_read32(priv, reg) & ~mask; - IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl4965_write32(priv, reg, val); -} -#define iwl4965_clear_bit(p, r, m) __iwl4965_clear_bit(__FILE__, __LINE__, p, r, m) -#else -#define iwl4965_clear_bit(p, r, m) _iwl4965_clear_bit(p, r, m) -#endif - -static inline int _iwl4965_grab_nic_access(struct iwl4965_priv *priv) -{ - int ret; - u32 gp_ctl; - -#ifdef CONFIG_IWL4965_DEBUG - if (atomic_read(&priv->restrict_refcnt)) - return 0; -#endif - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("WARNING: Requesting MAC access during RFKILL " - "wakes up NIC\n"); - - /* 10 msec allows time for NIC to complete its data save */ - gp_ctl = _iwl4965_read32(priv, CSR_GP_CNTRL); - if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { - IWL_DEBUG_RF_KILL("Wait for complete power-down, " - "gpctl = 0x%08x\n", gp_ctl); - mdelay(10); - } else - IWL_DEBUG_RF_KILL("power-down complete, " - "gpctl = 0x%08x\n", gp_ctl); - } - - /* this bit wakes up the NIC */ - _iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - ret = _iwl4965_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); - if (ret < 0) { - IWL_ERROR("MAC is in deep sleep!\n"); - return -EIO; - } - -#ifdef CONFIG_IWL4965_DEBUG - atomic_inc(&priv->restrict_refcnt); -#endif - return 0; -} - -#ifdef CONFIG_IWL4965_DEBUG -static inline int __iwl4965_grab_nic_access(const char *f, u32 l, - struct iwl4965_priv *priv) -{ - if (atomic_read(&priv->restrict_refcnt)) - IWL_DEBUG_INFO("Grabbing access while already held at " - "line %d.\n", l); - - IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l); - return _iwl4965_grab_nic_access(priv); -} -#define iwl4965_grab_nic_access(priv) \ - __iwl4965_grab_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl4965_grab_nic_access(priv) \ - _iwl4965_grab_nic_access(priv) -#endif - -static inline void _iwl4965_release_nic_access(struct iwl4965_priv *priv) -{ -#ifdef CONFIG_IWL4965_DEBUG - if (atomic_dec_and_test(&priv->restrict_refcnt)) -#endif - _iwl4965_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); -} -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_release_nic_access(const char *f, u32 l, - struct iwl4965_priv *priv) -{ - if (atomic_read(&priv->restrict_refcnt) <= 0) - IWL_ERROR("Release unheld nic access at line %d.\n", l); - - IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l); - _iwl4965_release_nic_access(priv); -} -#define iwl4965_release_nic_access(priv) \ - __iwl4965_release_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl4965_release_nic_access(priv) \ - _iwl4965_release_nic_access(priv) -#endif - -static inline u32 _iwl4965_read_direct32(struct iwl4965_priv *priv, u32 reg) -{ - return _iwl4965_read32(priv, reg); -} -#ifdef CONFIG_IWL4965_DEBUG -static inline u32 __iwl4965_read_direct32(const char *f, u32 l, - struct iwl4965_priv *priv, u32 reg) -{ - u32 value = _iwl4965_read_direct32(priv, reg); - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Nic access not held from %s %d\n", f, l); - IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, - f, l); - return value; -} -#define iwl4965_read_direct32(priv, reg) \ - __iwl4965_read_direct32(__FILE__, __LINE__, priv, reg) -#else -#define iwl4965_read_direct32 _iwl4965_read_direct32 -#endif - -static inline void _iwl4965_write_direct32(struct iwl4965_priv *priv, - u32 reg, u32 value) -{ - _iwl4965_write32(priv, reg, value); -} -#ifdef CONFIG_IWL4965_DEBUG -static void __iwl4965_write_direct32(u32 line, - struct iwl4965_priv *priv, u32 reg, u32 value) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Nic access not held from line %d\n", line); - _iwl4965_write_direct32(priv, reg, value); -} -#define iwl4965_write_direct32(priv, reg, value) \ - __iwl4965_write_direct32(__LINE__, priv, reg, value) -#else -#define iwl4965_write_direct32 _iwl4965_write_direct32 -#endif - -static inline void iwl4965_write_reg_buf(struct iwl4965_priv *priv, - u32 reg, u32 len, u32 *values) -{ - u32 count = sizeof(u32); - - if ((priv != NULL) && (values != NULL)) { - for (; 0 < len; len -= count, reg += count, values++) - _iwl4965_write_direct32(priv, reg, *values); - } -} - -static inline int _iwl4965_poll_direct_bit(struct iwl4965_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int i = 0; - - do { - if ((_iwl4965_read_direct32(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; -} - -#ifdef CONFIG_IWL4965_DEBUG -static inline int __iwl4965_poll_direct_bit(const char *f, u32 l, - struct iwl4965_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int ret = _iwl4965_poll_direct_bit(priv, addr, mask, timeout); - - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - " - "timedout - %s %d\n", addr, mask, f, l); - else - IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " - "- %s %d\n", addr, mask, ret, f, l); - return ret; -} -#define iwl4965_poll_direct_bit(iwl, addr, mask, timeout) \ - __iwl4965_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) -#else -#define iwl4965_poll_direct_bit _iwl4965_poll_direct_bit -#endif - -static inline u32 _iwl4965_read_prph(struct iwl4965_priv *priv, u32 reg) -{ - _iwl4965_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); - return _iwl4965_read_direct32(priv, HBUS_TARG_PRPH_RDAT); -} -#ifdef CONFIG_IWL4965_DEBUG -static inline u32 __iwl4965_read_prph(u32 line, struct iwl4965_priv *priv, u32 reg) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Nic access not held from line %d\n", line); - return _iwl4965_read_prph(priv, reg); -} - -#define iwl4965_read_prph(priv, reg) \ - __iwl4965_read_prph(__LINE__, priv, reg) -#else -#define iwl4965_read_prph _iwl4965_read_prph -#endif - -static inline void _iwl4965_write_prph(struct iwl4965_priv *priv, - u32 addr, u32 val) -{ - _iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WADDR, - ((addr & 0x0000FFFF) | (3 << 24))); - _iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); -} -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_write_prph(u32 line, struct iwl4965_priv *priv, - u32 addr, u32 val) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Nic access from line %d\n", line); - _iwl4965_write_prph(priv, addr, val); -} - -#define iwl4965_write_prph(priv, addr, val) \ - __iwl4965_write_prph(__LINE__, priv, addr, val); -#else -#define iwl4965_write_prph _iwl4965_write_prph -#endif - -#define _iwl4965_set_bits_prph(priv, reg, mask) \ - _iwl4965_write_prph(priv, reg, (_iwl4965_read_prph(priv, reg) | mask)) -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_set_bits_prph(u32 line, struct iwl4965_priv *priv, - u32 reg, u32 mask) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Nic access not held from line %d\n", line); - - _iwl4965_set_bits_prph(priv, reg, mask); -} -#define iwl4965_set_bits_prph(priv, reg, mask) \ - __iwl4965_set_bits_prph(__LINE__, priv, reg, mask) -#else -#define iwl4965_set_bits_prph _iwl4965_set_bits_prph -#endif - -#define _iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \ - _iwl4965_write_prph(priv, reg, ((_iwl4965_read_prph(priv, reg) & mask) | bits)) - -#ifdef CONFIG_IWL4965_DEBUG -static inline void __iwl4965_set_bits_mask_prph(u32 line, - struct iwl4965_priv *priv, u32 reg, u32 bits, u32 mask) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Nic access not held from line %d\n", line); - _iwl4965_set_bits_mask_prph(priv, reg, bits, mask); -} -#define iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \ - __iwl4965_set_bits_mask_prph(__LINE__, priv, reg, bits, mask) -#else -#define iwl4965_set_bits_mask_prph _iwl4965_set_bits_mask_prph -#endif - -static inline void iwl4965_clear_bits_prph(struct iwl4965_priv - *priv, u32 reg, u32 mask) -{ - u32 val = _iwl4965_read_prph(priv, reg); - _iwl4965_write_prph(priv, reg, (val & ~mask)); -} - -static inline u32 iwl4965_read_targ_mem(struct iwl4965_priv *priv, u32 addr) -{ - iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); - return iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT); -} - -static inline void iwl4965_write_targ_mem(struct iwl4965_priv *priv, u32 addr, u32 val) -{ - iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); -} - -static inline void iwl4965_write_targ_mem_buf(struct iwl4965_priv *priv, u32 addr, - u32 len, u32 *values) -{ - iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - for (; 0 < len; len -= sizeof(u32), values++) - iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index d0646226414..315b0433801 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -36,9 +36,10 @@ #include <linux/workqueue.h> -#include "../net/mac80211/ieee80211_rate.h" +#include "../net/mac80211/rate.h" #include "iwl-4965.h" +#include "iwl-core.h" #include "iwl-helpers.h" #define RS_NAME "iwl-4965-rs" @@ -83,7 +84,7 @@ struct iwl4965_rate_scale_data { /** * struct iwl4965_scale_tbl_info -- tx params and success history for all rates * - * There are two of these in struct iwl_rate_scale_priv, + * There are two of these in struct iwl4965_lq_sta, * one for "active", and one for "search". */ struct iwl4965_scale_tbl_info { @@ -98,8 +99,23 @@ struct iwl4965_scale_tbl_info { struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; +#ifdef CONFIG_IWL4965_HT + +struct iwl4965_traffic_load { + unsigned long time_stamp; /* age of the oldest statistics */ + u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time + * slice */ + u32 total; /* total num of packets during the + * last TID_MAX_TIME_DIFF */ + u8 queue_count; /* number of queues that has + * been used since the last cleanup */ + u8 head; /* start of the circular buffer */ +}; + +#endif /* CONFIG_IWL4965_HT */ + /** - * struct iwl_rate_scale_priv -- driver's rate scaling private structure + * struct iwl4965_lq_sta -- driver's rate scaling private structure * * Pointer to this gets passed back and forth between driver and mac80211. */ @@ -124,7 +140,7 @@ struct iwl4965_lq_sta { u8 valid_antenna; u8 is_green; u8 is_dup; - u8 phymode; + enum ieee80211_band band; u8 ibss_sta_added; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ @@ -136,15 +152,22 @@ struct iwl4965_lq_sta { struct iwl4965_link_quality_cmd lq; struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ +#ifdef CONFIG_IWL4965_HT + struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT]; + u8 tx_agg_tid_en; +#endif #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; +#ifdef CONFIG_IWL4965_HT + struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; +#endif struct iwl4965_rate dbg_fixed; - struct iwl4965_priv *drv; + struct iwl_priv *drv; #endif }; -static void rs_rate_scale_perform(struct iwl4965_priv *priv, +static void rs_rate_scale_perform(struct iwl_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta); @@ -207,8 +230,8 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 }; -static int iwl4965_lq_sync_callback(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb) +static int iwl4965_lq_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) { /*We didn't cache the SKB; let the caller free it */ return 1; @@ -219,13 +242,13 @@ static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags) return (u8)(rate_n_flags & 0xFF); } -static int rs_send_lq_cmd(struct iwl4965_priv *priv, +static int rs_send_lq_cmd(struct iwl_priv *priv, struct iwl4965_link_quality_cmd *lq, u8 flags) { -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG int i; #endif - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_TX_LINK_QUALITY_CMD, .len = sizeof(struct iwl4965_link_quality_cmd), .meta.flags = flags, @@ -243,7 +266,7 @@ static int rs_send_lq_cmd(struct iwl4965_priv *priv, IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk, lq->general_params.dual_stream_ant_msk); -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) IWL_DEBUG_RATE("lq index %d 0x%X\n", i, lq->rs_table[i].rate_n_flags); @@ -252,9 +275,9 @@ static int rs_send_lq_cmd(struct iwl4965_priv *priv, if (flags & CMD_ASYNC) cmd.meta.u.callback = iwl4965_lq_sync_callback; - if (iwl4965_is_associated(priv) && priv->assoc_station_added && + if (iwl_is_associated(priv) && priv->assoc_station_added && priv->lq_mngr.lq_ready) - return iwl4965_send_cmd(priv, &cmd); + return iwl_send_cmd(priv, &cmd); return 0; } @@ -269,6 +292,135 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) window->stamp = 0; } +#ifdef CONFIG_IWL4965_HT +/* + * removes the old data from the statistics. All data that is older than + * TID_MAX_TIME_DIFF, will be deleted. + */ +static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time) +{ + /* The oldest age we want to keep */ + u32 oldest_time = curr_time - TID_MAX_TIME_DIFF; + + while (tl->queue_count && + (tl->time_stamp < oldest_time)) { + tl->total -= tl->packet_count[tl->head]; + tl->packet_count[tl->head] = 0; + tl->time_stamp += TID_QUEUE_CELL_SPACING; + tl->queue_count--; + tl->head++; + if (tl->head >= TID_QUEUE_MAX_SIZE) + tl->head = 0; + } +} + +/* + * increment traffic load value for tid and also remove + * any old values if passed the certain time period + */ +static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) +{ + u32 curr_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + struct iwl4965_traffic_load *tl = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return; + + tl = &lq_data->load[tid]; + + curr_time -= curr_time % TID_ROUND_VALUE; + + /* Happens only for the first packet. Initialize the data */ + if (!(tl->queue_count)) { + tl->total = 1; + tl->time_stamp = curr_time; + tl->queue_count = 1; + tl->head = 0; + tl->packet_count[0] = 1; + return; + } + + time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + /* The history is too long: remove data that is older than */ + /* TID_MAX_TIME_DIFF */ + if (index >= TID_QUEUE_MAX_SIZE) + rs_tl_rm_old_stats(tl, curr_time); + + index = (tl->head + index) % TID_QUEUE_MAX_SIZE; + tl->packet_count[index] = tl->packet_count[index] + 1; + tl->total = tl->total + 1; + + if ((index + 1) > tl->queue_count) + tl->queue_count = index + 1; +} + +/* + get the traffic load value for tid +*/ +static u32 rs_tl_get_load(struct iwl4965_lq_sta *lq_data, u8 tid) +{ + u32 curr_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + struct iwl4965_traffic_load *tl = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return 0; + + tl = &(lq_data->load[tid]); + + curr_time -= curr_time % TID_ROUND_VALUE; + + if (!(tl->queue_count)) + return 0; + + time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + /* The history is too long: remove data that is older than */ + /* TID_MAX_TIME_DIFF */ + if (index >= TID_QUEUE_MAX_SIZE) + rs_tl_rm_old_stats(tl, curr_time); + + return tl->total; +} + +static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, + struct iwl4965_lq_sta *lq_data, u8 tid, + struct sta_info *sta) +{ + unsigned long state; + DECLARE_MAC_BUF(mac); + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + state = sta->ampdu_mlme.tid_state_tx[tid]; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (state == HT_AGG_STATE_IDLE && + rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { + IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", + print_mac(mac, sta->addr), tid); + ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); + } +} + +static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, + struct iwl4965_lq_sta *lq_data, + struct sta_info *sta) +{ + if ((tid < TID_MAX_LOAD_COUNT)) + rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); + else if (tid == IWL_AGG_ALL_TID) + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) + rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); +} + +#endif /* CONFIG_IWLWIFI_HT */ + /** * rs_collect_tx_data - Update the success/failure sliding window * @@ -277,7 +429,8 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) * packets. */ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, - int scale_index, s32 tpt, u32 status) + int scale_index, s32 tpt, int retries, + int successes) { struct iwl4965_rate_scale_data *window = NULL; u64 mask; @@ -298,26 +451,33 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, * subtract "1" from the success counter (this is the main reason * we keep these bitmaps!). */ - if (window->counter >= win_size) { - window->counter = win_size - 1; - mask = 1; - mask = (mask << (win_size - 1)); - if ((window->data & mask)) { - window->data &= ~mask; - window->success_counter = window->success_counter - 1; + while (retries > 0) { + if (window->counter >= win_size) { + window->counter = win_size - 1; + mask = 1; + mask = (mask << (win_size - 1)); + if (window->data & mask) { + window->data &= ~mask; + window->success_counter = + window->success_counter - 1; + } } - } - /* Increment frames-attempted counter */ - window->counter = window->counter + 1; + /* Increment frames-attempted counter */ + window->counter++; + + /* Shift bitmap by one frame (throw away oldest history), + * OR in "1", and increment "success" if this + * frame was successful. */ + mask = window->data; + window->data = (mask << 1); + if (successes > 0) { + window->success_counter = window->success_counter + 1; + window->data |= 0x1; + successes--; + } - /* Shift bitmap by one frame (throw away oldest history), - * OR in "1", and increment "success" if this frame was successful. */ - mask = window->data; - window->data = (mask << 1); - if (status != 0) { - window->success_counter = window->success_counter + 1; - window->data |= 0x1; + retries--; } /* Calculate current success ratio, avoid divide-by-0! */ @@ -404,13 +564,14 @@ static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, * fill "search" or "active" tx mode table. */ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, - int phymode, struct iwl4965_scale_tbl_info *tbl, + enum ieee80211_band band, + struct iwl4965_scale_tbl_info *tbl, int *rate_idx) { int index; u32 ant_msk; - index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags); + index = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags); if (index == IWL_RATE_INVALID) { *rate_idx = -1; @@ -429,7 +590,7 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, tbl->lq_type = LQ_NONE; else { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; @@ -498,7 +659,7 @@ static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate, } } -static inline u8 rs_use_green(struct iwl4965_priv *priv, +static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) { #ifdef CONFIG_IWL4965_HT @@ -607,7 +768,7 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { switch_to_legacy = 1; scale_index = rs_ht_to_legacy[scale_index]; - if (lq_sta->phymode == MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; @@ -625,7 +786,7 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, /* Mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { /* supp_rates has no CCK bits in A mode */ - if (lq_sta->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) rate_mask = (u16)(rate_mask & (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); else @@ -661,8 +822,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, struct iwl4965_link_quality_cmd *table; struct sta_info *sta; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = local_to_hw(local); struct iwl4965_rate_scale_data *window = NULL; struct iwl4965_rate_scale_data *search_win = NULL; struct iwl4965_rate tx_mcs; @@ -677,28 +839,32 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return; + /* This packet was aggregated but doesn't carry rate scale info */ + if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) && + !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU)) + return; + retries = tx_resp->retry_count; if (retries > 15) retries = 15; + rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); - if (!sta || !sta->rate_ctrl_priv) { - if (sta) - sta_info_put(sta); - return; - } + if (!sta || !sta->rate_ctrl_priv) + goto out; + lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; if (!priv->lq_mngr.lq_ready) - return; + goto out; if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) - return; + goto out; table = &lq_sta->lq; active_index = lq_sta->active_tbl; @@ -719,17 +885,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, search_win = (struct iwl4965_rate_scale_data *) &(search_tbl->win[0]); - tx_mcs.rate_n_flags = tx_resp->control.tx_rate; - - rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, - &tbl_type, &rs_index); - if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { - IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", - rs_index, tx_mcs.rate_n_flags); - sta_info_put(sta); - return; - } - /* * Ignore this Tx frame response if its initial rate doesn't match * that of latest Link Quality command. There may be stragglers @@ -738,14 +893,29 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * to check "search" mode, or a prior "search" mode after we've moved * to a new "search" mode (which might become the new "active" mode). */ - if (retries && - (tx_mcs.rate_n_flags != - le32_to_cpu(table->rs_table[0].rate_n_flags))) { - IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", - tx_mcs.rate_n_flags, - le32_to_cpu(table->rs_table[0].rate_n_flags)); - sta_info_put(sta); - return; + tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags); + rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); + if (priv->band == IEEE80211_BAND_5GHZ) + rs_index -= IWL_FIRST_OFDM_RATE; + + if ((tx_resp->control.tx_rate == NULL) || + (tbl_type.is_SGI ^ + !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || + (tbl_type.is_fat ^ + !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || + (tbl_type.is_dup ^ + !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || + (tbl_type.antenna_type ^ + tx_resp->control.antenna_sel_tx) || + (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^ + !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || + (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^ + !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || + (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != + tx_resp->control.tx_rate->bitrate)) { + IWL_DEBUG_RATE("initial rate does not match 0x%x\n", + tx_mcs.rate_n_flags); + goto out; } /* Update frame history window with "failure" for each Tx retry. */ @@ -754,7 +924,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * Each tx attempt steps one entry deeper in the rate table. */ tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); /* If type matches "search" table, @@ -766,7 +936,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; - rs_collect_tx_data(search_win, rs_index, tpt, 0); + rs_collect_tx_data(search_win, rs_index, tpt, 1, 0); /* Else if type matches "current/active" table, * add failure to "current/active" history */ @@ -777,7 +947,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; - rs_collect_tx_data(window, rs_index, tpt, 0); + rs_collect_tx_data(window, rs_index, tpt, 1, 0); } /* If not searching for a new mode, increment failed counter @@ -794,14 +964,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * if Tx was successful first try, use original rate, * else look up the rate that was, finally, successful. */ - if (!tx_resp->retry_count) - tx_mcs.rate_n_flags = tx_resp->control.tx_rate; - else - tx_mcs.rate_n_flags = - le32_to_cpu(table->rs_table[index].rate_n_flags); - - rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, - &tbl_type, &rs_index); + tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) @@ -818,9 +982,13 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; - rs_collect_tx_data(search_win, - rs_index, tpt, status); - + if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + rs_collect_tx_data(search_win, rs_index, tpt, + tx_resp->ampdu_ack_len, + tx_resp->ampdu_ack_map); + else + rs_collect_tx_data(search_win, rs_index, tpt, + 1, status); /* Else if type matches "current/active" table, * add final tx status to "current/active" history */ } else if ((tbl_type.lq_type == curr_tbl->lq_type) && @@ -830,21 +998,34 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; - rs_collect_tx_data(window, rs_index, tpt, status); + if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) + rs_collect_tx_data(window, rs_index, tpt, + tx_resp->ampdu_ack_len, + tx_resp->ampdu_ack_map); + else + rs_collect_tx_data(window, rs_index, tpt, + 1, status); } /* If not searching for new mode, increment success/failed counter * ... these help determine when to start searching again */ if (lq_sta->stay_in_tbl) { - if (status) - lq_sta->total_success++; - else - lq_sta->total_failed++; + if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) { + lq_sta->total_success += tx_resp->ampdu_ack_map; + lq_sta->total_failed += + (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map); + } else { + if (status) + lq_sta->total_success++; + else + lq_sta->total_failed++; + } } /* See if there's a better rate or modulation mode to try. */ rs_rate_scale_perform(priv, dev, hdr, sta); - sta_info_put(sta); +out: + rcu_read_unlock(); return; } @@ -948,7 +1129,7 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, * to decrease to match "active" throughput. When moving from MIMO to SISO, * bit rate will typically need to increase, but not if performance was bad. */ -static s32 rs_get_best_rate(struct iwl4965_priv *priv, +static s32 rs_get_best_rate(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct iwl4965_scale_tbl_info *tbl, /* "search" */ u16 rate_mask, s8 index, s8 rate) @@ -1046,7 +1227,7 @@ static inline u8 rs_is_both_ant_supp(u8 valid_antenna) /* * Set up search table for MIMO */ -static int rs_switch_to_mimo(struct iwl4965_priv *priv, +static int rs_switch_to_mimo(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, @@ -1105,13 +1286,13 @@ static int rs_switch_to_mimo(struct iwl4965_priv *priv, return 0; #else return -1; -#endif /*CONFIG_IWL4965_HT */ +#endif /*CONFIG_IWL4965_HT */ } /* * Set up search table for SISO */ -static int rs_switch_to_siso(struct iwl4965_priv *priv, +static int rs_switch_to_siso(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, @@ -1168,13 +1349,13 @@ static int rs_switch_to_siso(struct iwl4965_priv *priv, #else return -1; -#endif /*CONFIG_IWL4965_HT */ +#endif /*CONFIG_IWL4965_HT */ } /* * Try to switch to new modulation mode from legacy */ -static int rs_move_legacy_other(struct iwl4965_priv *priv, +static int rs_move_legacy_other(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, @@ -1272,7 +1453,7 @@ static int rs_move_legacy_other(struct iwl4965_priv *priv, /* * Try to switch to new modulation mode from SISO */ -static int rs_move_siso_to_other(struct iwl4965_priv *priv, +static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, @@ -1325,6 +1506,7 @@ static int rs_move_siso_to_other(struct iwl4965_priv *priv, break; case IWL_SISO_SWITCH_GI: IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); + memcpy(search_tbl, tbl, sz); search_tbl->action = 0; if (search_tbl->is_SGI) @@ -1367,7 +1549,7 @@ static int rs_move_siso_to_other(struct iwl4965_priv *priv, /* * Try to switch to new modulation mode from MIMO */ -static int rs_move_mimo_to_other(struct iwl4965_priv *priv, +static int rs_move_mimo_to_other(struct iwl_priv *priv, struct iwl4965_lq_sta *lq_sta, struct ieee80211_conf *conf, struct sta_info *sta, @@ -1390,6 +1572,7 @@ static int rs_move_mimo_to_other(struct iwl4965_priv *priv, case IWL_MIMO_SWITCH_ANTENNA_B: IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); + /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_SISO; @@ -1546,7 +1729,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) /* * Do rate scaling and search for new modulation mode. */ -static void rs_rate_scale_perform(struct iwl4965_priv *priv, +static void rs_rate_scale_perform(struct iwl_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta) @@ -1574,6 +1757,10 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, u8 active_tbl = 0; u8 done_search = 0; u16 high_low; +#ifdef CONFIG_IWL4965_HT + u8 tid = MAX_TID_COUNT; + __le16 *qc; +#endif IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); @@ -1594,6 +1781,13 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, } lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; +#ifdef CONFIG_IWL4965_HT + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + tid = (u8)(le16_to_cpu(*qc) & 0xf); + rs_tl_add_packet(lq_sta, tid); + } +#endif /* * Select rate-scale / modulation-mode table to work with in * the rest of this function: "search" if searching for better @@ -1608,7 +1802,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, is_green = lq_sta->is_green; /* current tx rate */ - index = sta->last_txrate; + index = sta->last_txrate_idx; IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, tbl->lq_type); @@ -1621,7 +1815,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, /* mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { - if (lq_sta->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) /* supp_rates has no CCK bits in A mode */ rate_scale_index_msk = (u16) (rate_mask & (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); @@ -1727,7 +1921,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, tbl = &(lq_sta->lq_info[active_tbl]); /* Revert to "active" rate and throughput info */ - index = iwl4965_rate_index_from_plcp( + index = iwl4965_hwrate_to_plcp_idx( tbl->current_rate.rate_n_flags); current_tpt = lq_sta->last_tpt; @@ -1883,7 +2077,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, rs_rate_scale_clear_window(&(tbl->win[i])); /* Use new "search" start rate */ - index = iwl4965_rate_index_from_plcp( + index = iwl4965_hwrate_to_plcp_idx( tbl->current_rate.rate_n_flags); IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", @@ -1914,15 +2108,14 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, * mode for a while before next round of mode comparisons. */ if (lq_sta->enable_counter && (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { -#ifdef CONFIG_IWL4965_HT_AGG - /* If appropriate, set up aggregation! */ - if ((lq_sta->last_tpt > TID_AGG_TPT_THREHOLD) && - (priv->lq_mngr.agg_ctrl.auto_agg)) { - priv->lq_mngr.agg_ctrl.tid_retry = - TID_ALL_SPECIFIED; - schedule_work(&priv->agg_work); +#ifdef CONFIG_IWL4965_HT + if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && + (lq_sta->tx_agg_tid_en & (1 << tid)) && + (tid != MAX_TID_COUNT)) { + IWL_DEBUG_HT("try to aggregate tid %d\n", tid); + rs_tl_turn_on_agg(priv, tid, lq_sta, sta); } -#endif /*CONFIG_IWL4965_HT_AGG */ +#endif /*CONFIG_IWL4965_HT */ lq_sta->action_counter = 0; rs_set_stay_in_table(0, lq_sta); } @@ -1942,21 +2135,21 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, out: rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green); i = index; - sta->last_txrate = i; + sta->last_txrate_idx = i; - /* sta->txrate is an index to A mode rates which start + /* sta->txrate_idx is an index to A mode rates which start * at IWL_FIRST_OFDM_RATE */ - if (lq_sta->phymode == (u8) MODE_IEEE80211A) - sta->txrate = i - IWL_FIRST_OFDM_RATE; + if (lq_sta->band == IEEE80211_BAND_5GHZ) + sta->txrate_idx = i - IWL_FIRST_OFDM_RATE; else - sta->txrate = i; + sta->txrate_idx = i; return; } -static void rs_initialize_lq(struct iwl4965_priv *priv, +static void rs_initialize_lq(struct iwl_priv *priv, struct ieee80211_conf *conf, struct sta_info *sta) { @@ -1972,7 +2165,7 @@ static void rs_initialize_lq(struct iwl4965_priv *priv, goto out; lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate; + i = sta->last_txrate_idx; if ((lq_sta->lq.sta_id == 0xff) && (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) @@ -1996,7 +2189,7 @@ static void rs_initialize_lq(struct iwl4965_priv *priv, mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; tbl->antenna_type = ANT_AUX; - rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx); + rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx); if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) rs_toggle_antenna(&mcs_rate, tbl); @@ -2010,7 +2203,8 @@ static void rs_initialize_lq(struct iwl4965_priv *priv, } static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel) { @@ -2020,11 +2214,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct sta_info *sta; u16 fc; - struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl4965_lq_sta *lq_sta; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest @@ -2032,14 +2228,12 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { - sel->rate = rate_lowest(local, local->oper_hw_mode, sta); - if (sta) - sta_info_put(sta); - return; + sel->rate = rate_lowest(local, sband, sta); + goto out; } lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate; + i = sta->last_txrate_idx; if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) { @@ -2062,14 +2256,15 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, goto done; } - done: +done: if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate = rate_lowest(local, local->oper_hw_mode, sta); - return; + sel->rate = rate_lowest(local, sband, sta); + goto out; } - sta_info_put(sta); sel->rate = &priv->ieee_rates[i]; +out: + rcu_read_unlock(); } static void *rs_alloc_sta(void *priv, gfp_t gfp) @@ -2099,13 +2294,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, { int i, j; struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_hw_mode *mode = local->oper_hw_mode; - struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; + struct ieee80211_supported_band *sband; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl4965_lq_sta *lq_sta = priv_sta; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + lq_sta->flush_timer = 0; - lq_sta->supp_rates = sta->supp_rates; - sta->txrate = 3; + lq_sta->supp_rates = sta->supp_rates[sband->band]; + sta->txrate_idx = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); @@ -2140,15 +2337,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, } /* Find highest tx rate supported by hardware and destination station */ - for (i = 0; i < mode->num_rates; i++) { - if ((sta->supp_rates & BIT(i)) && - (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) - sta->txrate = i; - } - sta->last_txrate = sta->txrate; + for (i = 0; i < sband->n_bitrates; i++) + if (sta->supp_rates[sband->band] & BIT(i)) + sta->txrate_idx = i; + + sta->last_txrate_idx = sta->txrate_idx; + /* WTF is with this bogus comment? A doesn't have cck rates */ /* For MODE_IEEE80211A, cck rates are at end of rate table */ - if (local->hw.conf.phymode == MODE_IEEE80211A) - sta->last_txrate += IWL_FIRST_OFDM_RATE; + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; lq_sta->valid_antenna = priv->valid_antenna; @@ -2157,7 +2354,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->active_rate = priv->active_rate; lq_sta->active_rate &= ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; - lq_sta->phymode = priv->phymode; + lq_sta->band = priv->band; #ifdef CONFIG_IWL4965_HT /* * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), @@ -2180,6 +2377,8 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n", lq_sta->active_siso_rate, lq_sta->active_mimo_rate); + /* as default allow aggregation for all tids */ + lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; #endif /*CONFIG_IWL4965_HT*/ #ifdef CONFIG_MAC80211_DEBUGFS lq_sta->drv = priv; @@ -2207,7 +2406,7 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, rs_dbgfs_set_mcs(lq_sta, tx_mcs, index); /* Interpret rate_n_flags */ - rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->phymode, + rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->band, &tbl_type, &rate_idx); /* How many times should we repeat the initial rate? */ @@ -2261,7 +2460,7 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, index++; } - rs_get_tbl_info_from_mcs(&new_rate, lq_sta->phymode, &tbl_type, + rs_get_tbl_info_from_mcs(&new_rate, lq_sta->band, &tbl_type, &rate_idx); /* Indicate to uCode which entries might be MIMO. @@ -2318,17 +2517,11 @@ static void rs_free(void *priv_rate) static void rs_clear(void *priv_rate) { - struct iwl4965_priv *priv = (struct iwl4965_priv *) priv_rate; + struct iwl_priv *priv = (struct iwl_priv *) priv_rate; IWL_DEBUG_RATE("enter\n"); priv->lq_mngr.lq_ready = 0; -#ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG - if (priv->lq_mngr.agg_ctrl.granted_ba) - iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED); -#endif /*CONFIG_IWL4965_HT_AGG */ -#endif /* CONFIG_IWL4965_HT */ IWL_DEBUG_RATE("leave\n"); } @@ -2354,7 +2547,7 @@ static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, { u32 base_rate; - if (lq_sta->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) base_rate = 0x800D; else base_rate = 0x820A; @@ -2495,6 +2688,12 @@ static void rs_add_debugfs(void *priv, void *priv_sta, lq_sta->rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", 0600, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); +#ifdef CONFIG_IWL4965_HT + lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = + debugfs_create_u8("tx_agg_tid_enable", 0600, dir, + &lq_sta->tx_agg_tid_en); +#endif + } static void rs_remove_debugfs(void *priv, void *priv_sta) @@ -2502,6 +2701,9 @@ static void rs_remove_debugfs(void *priv, void *priv_sta) struct iwl4965_lq_sta *lq_sta = priv_sta; debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); +#ifdef CONFIG_IWL4965_HT + debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); +#endif } #endif @@ -2525,7 +2727,7 @@ static struct rate_control_ops rs_ops = { int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) { struct ieee80211_local *local = hw_to_local(hw); - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; struct iwl4965_lq_sta *lq_sta; struct sta_info *sta; int cnt = 0, i; @@ -2534,13 +2736,15 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) u32 max_time = 0; u8 lq_type, antenna; + rcu_read_lock(); + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); if (!sta || !sta->rate_ctrl_priv) { - if (sta) { - sta_info_put(sta); + if (sta) IWL_DEBUG_RATE("leave - no private rate data!\n"); - } else + else IWL_DEBUG_RATE("leave - no station!\n"); + rcu_read_unlock(); return sprintf(buf, "station %d not found\n", sta_id); } @@ -2605,25 +2809,25 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d " "active_search %d rate index %d\n", lq_type, antenna, - lq_sta->search_better_tbl, sta->last_txrate); + lq_sta->search_better_tbl, sta->last_txrate_idx); - sta_info_put(sta); + rcu_read_unlock(); return cnt; } void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; priv->lq_mngr.lq_ready = 1; } -void iwl4965_rate_control_register(struct ieee80211_hw *hw) +int iwl4965_rate_control_register(void) { - ieee80211_rate_control_register(&rs_ops); + return ieee80211_rate_control_register(&rs_ops); } -void iwl4965_rate_control_unregister(struct ieee80211_hw *hw) +void iwl4965_rate_control_unregister(void) { ieee80211_rate_control_unregister(&rs_ops); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index 55f70738278..866e378aa38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -212,6 +212,18 @@ enum { #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ +/* load per tid defines for A-MPDU activation */ +#define IWL_AGG_TPT_THREHOLD 0 +#define IWL_AGG_LOAD_THRESHOLD 10 +#define IWL_AGG_ALL_TID 0xff +#define TID_QUEUE_CELL_SPACING 50 /*mS */ +#define TID_QUEUE_MAX_SIZE 20 +#define TID_ROUND_VALUE 5 /* mS */ +#define TID_MAX_LOAD_COUNT 8 + +#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) +#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) + extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; enum iwl4965_table_type { @@ -247,7 +259,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) return rate; } -extern int iwl4965_rate_index_from_plcp(int plcp); +extern int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags); /** * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation @@ -276,7 +288,7 @@ extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); * ieee80211_register_hw * */ -extern void iwl4965_rate_control_register(struct ieee80211_hw *hw); +extern int iwl4965_rate_control_register(void); /** * iwl4965_rate_control_unregister - Unregister the rate control callbacks @@ -284,6 +296,6 @@ extern void iwl4965_rate_control_register(struct ieee80211_hw *hw); * This should be called after calling ieee80211_unregister_hw, but before * the driver is unloaded. */ -extern void iwl4965_rate_control_unregister(struct ieee80211_hw *hw); +extern void iwl4965_rate_control_unregister(void); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 65767570be6..472ca3d7e03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -38,10 +38,21 @@ #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include "iwl-eeprom.h" #include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-io.h" #include "iwl-helpers.h" -static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv); +/* module parameters */ +static struct iwl_mod_params iwl4965_mod_params = { + .num_of_queues = IWL_MAX_NUM_QUEUES, + .enable_qos = 1, + .amsdu_size_8K = 1, + /* the rest are 0 by default */ +}; + +static void iwl4965_hw_card_show_info(struct iwl_priv *priv); #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ @@ -79,13 +90,120 @@ const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ }; +#ifdef CONFIG_IWL4965_HT + +static const u16 default_tid_to_tx_fifo[] = { + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_AC3 +}; + +#endif /*CONFIG_IWL4965_HT */ + +static int iwl4965_init_drv(struct iwl_priv *priv) +{ + int ret; + int i; + + priv->antenna = (enum iwl4965_antenna)priv->cfg->mod_params->antenna; + priv->retry_rate = 1; + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + spin_lock_init(&priv->lq_mngr.lock); + + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwlcore_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + priv->use_ant_b_for_management_frame = 1; /* start with ant B */ + priv->valid_antenna = 0x7; /* assume all 3 connected */ + priv->ps_mode = IWL_MIMO_PS_NONE; + + /* Choose which receivers/antennas to use */ + iwl4965_set_rxon_chain(priv); + + iwlcore_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; + + iwlcore_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + + ret = iwl_init_channel_map(priv); + if (ret) { + IWL_ERROR("initializing regulatory failed: %d\n", ret); + goto err; + } + + ret = iwl4965_init_geos(priv); + if (ret) { + IWL_ERROR("initializing geos failed: %d\n", ret); + goto err_free_channel_map; + } + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERROR("Failed to register network device (error %d)\n", + ret); + goto err_free_geos; + } + + priv->hw->conf.beacon_int = 100; + priv->mac80211_registered = 1; + + return 0; + +err_free_geos: + iwl4965_free_geos(priv); +err_free_channel_map: + iwl_free_channel_map(priv); +err: + return ret; +} + static int is_fat_channel(__le32 rxon_flags) { return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); } -static u8 is_single_stream(struct iwl4965_priv *priv) +static u8 is_single_stream(struct iwl_priv *priv) { #ifdef CONFIG_IWL4965_HT if (!priv->current_ht_config.is_ht || @@ -98,13 +216,71 @@ static u8 is_single_stream(struct iwl4965_priv *priv) return 0; } +int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) +{ + int idx = 0; + + /* 4965 HT rate format */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + + if (idx >= IWL_RATE_MIMO_6M_PLCP) + idx = idx - IWL_RATE_MIMO_6M_PLCP; + + idx += IWL_FIRST_OFDM_RATE; + /* skip 9M not supported in ht*/ + if (idx >= IWL_RATE_9M_INDEX) + idx += 1; + if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) + return idx; + + /* 4965 legacy rate format, search for match in table */ + } else { + for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) + if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx; + } + + return -1; +} + +/** + * translate ucode response to mac80211 tx status control values + */ +void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, + struct ieee80211_tx_control *control) +{ + int rate_index; + + control->antenna_sel_tx = + ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_A_POS); + if (rate_n_flags & RATE_MCS_HT_MSK) + control->flags |= IEEE80211_TXCTL_OFDM_HT; + if (rate_n_flags & RATE_MCS_GF_MSK) + control->flags |= IEEE80211_TXCTL_GREEN_FIELD; + if (rate_n_flags & RATE_MCS_FAT_MSK) + control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH; + if (rate_n_flags & RATE_MCS_DUP_MSK) + control->flags |= IEEE80211_TXCTL_DUP_DATA; + if (rate_n_flags & RATE_MCS_SGI_MSK) + control->flags |= IEEE80211_TXCTL_SHORT_GI; + /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use + * IEEE80211_BAND_2GHZ band as it contains all the rates */ + rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); + if (rate_index == -1) + control->tx_rate = NULL; + else + control->tx_rate = + &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; +} + /* * Determine how many receiver/antenna chains to use. * More provides better reception via diversity. Fewer saves power. * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. */ -static int iwl4965_get_rx_chain_counter(struct iwl4965_priv *priv, +static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, u8 *idle_state, u8 *rx_state) { u8 is_single = is_single_stream(priv); @@ -133,32 +309,32 @@ static int iwl4965_get_rx_chain_counter(struct iwl4965_priv *priv, return 0; } -int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv) +int iwl4965_hw_rxq_stop(struct iwl_priv *priv) { int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } /* stop Rx DMA */ - iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - rc = iwl4965_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + rc = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, (1 << 24), 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *addr) +u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr) { int i; int start = 0; @@ -171,7 +347,7 @@ u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *addr) start = IWL_STA_ID; if (is_broadcast_ether_addr(addr)) - return IWL4965_BROADCAST_ID; + return priv->hw_setting.bcast_sta_id; spin_lock_irqsave(&priv->sta_lock, flags); for (i = start; i < priv->hw_setting.max_stations; i++) @@ -190,13 +366,13 @@ u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *addr) return ret; } -static int iwl4965_nic_set_pwr_src(struct iwl4965_priv *priv, int pwr_max) +static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) { int ret; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - ret = iwl4965_grab_nic_access(priv); + ret = iwl_grab_nic_access(priv); if (ret) { spin_unlock_irqrestore(&priv->lock, flags); return ret; @@ -209,92 +385,92 @@ static int iwl4965_nic_set_pwr_src(struct iwl4965_priv *priv, int pwr_max) &val); if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) - iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VAUX, ~APMG_PS_CTRL_MSK_PWR_SRC); } else - iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return ret; } -static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq) +static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) { int rc; unsigned long flags; unsigned int rb_size; spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - if (iwl4965_param_amsdu_size_8K) + if (priv->cfg->mod_params->amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; /* Stop Rx DMA */ - iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); /* Reset driver's Rx queue write index */ - iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); /* Tell device where to find RBD circular buffer in DRAM */ - iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - rxq->dma_addr >> 8); + iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + rxq->dma_addr >> 8); /* Tell device where in DRAM to update its Rx status */ - iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->hw_setting.shared_phys + - offsetof(struct iwl4965_shared, val0)) >> 4); + iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, + (priv->hw_setting.shared_phys + + offsetof(struct iwl4965_shared, val0)) >> 4); /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ - iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | - FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - rb_size | + iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + rb_size | /*0x10 << 4 | */ - (RX_QUEUE_SIZE_LOG << + (RX_QUEUE_SIZE_LOG << FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); /* - * iwl4965_write32(priv,CSR_INT_COAL_REG,0); + * iwl_write32(priv,CSR_INT_COAL_REG,0); */ - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } /* Tell 4965 where to find the "keep warm" buffer */ -static int iwl4965_kw_init(struct iwl4965_priv *priv) +static int iwl4965_kw_init(struct iwl_priv *priv) { unsigned long flags; int rc; spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) goto out; - iwl4965_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG, + iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG, priv->kw.dma_addr >> 4); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); out: spin_unlock_irqrestore(&priv->lock, flags); return rc; } -static int iwl4965_kw_alloc(struct iwl4965_priv *priv) +static int iwl4965_kw_alloc(struct iwl_priv *priv) { struct pci_dev *dev = priv->pci_dev; struct iwl4965_kw *kw = &priv->kw; @@ -307,58 +483,10 @@ static int iwl4965_kw_alloc(struct iwl4965_priv *priv) return 0; } -#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ - ? # x " " : "") - -/** - * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. - * - * Does not set up a command, or touch hardware. - */ -int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel, - const struct iwl4965_eeprom_channel *eeprom_ch, - u8 fat_extension_channel) -{ - struct iwl4965_channel_info *ch_info; - - ch_info = (struct iwl4965_channel_info *) - iwl4965_get_channel_info(priv, phymode, channel); - - if (!is_channel_valid(ch_info)) - return -1; - - IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" - " %ddBm): Ad-Hoc %ssupported\n", - ch_info->channel, - is_channel_a_band(ch_info) ? - "5.2" : "2.4", - CHECK_AND_PRINT(IBSS), - CHECK_AND_PRINT(ACTIVE), - CHECK_AND_PRINT(RADAR), - CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(NARROW), - CHECK_AND_PRINT(DFS), - eeprom_ch->flags, - eeprom_ch->max_power_avg, - ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) - && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? - "" : "not "); - - ch_info->fat_eeprom = *eeprom_ch; - ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; - ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; - ch_info->fat_min_power = 0; - ch_info->fat_scan_power = eeprom_ch->max_power_avg; - ch_info->fat_flags = eeprom_ch->flags; - ch_info->fat_extension_channel = fat_extension_channel; - - return 0; -} - /** * iwl4965_kw_free - Free the "keep warm" buffer */ -static void iwl4965_kw_free(struct iwl4965_priv *priv) +static void iwl4965_kw_free(struct iwl_priv *priv) { struct pci_dev *dev = priv->pci_dev; struct iwl4965_kw *kw = &priv->kw; @@ -376,7 +504,7 @@ static void iwl4965_kw_free(struct iwl4965_priv *priv) * @param priv * @return error code */ -static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) +static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) { int rc = 0; int txq_id, slots_num; @@ -396,7 +524,7 @@ static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (unlikely(rc)) { IWL_ERROR("TX reset failed"); spin_unlock_irqrestore(&priv->lock, flags); @@ -404,8 +532,8 @@ static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) } /* Turn off all Tx DMA channels */ - iwl4965_write_prph(priv, KDR_SCD_TXFACT, 0); - iwl4965_release_nic_access(priv); + iwl_write_prph(priv, IWL49_SCD_TXFACT, 0); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); /* Tell 4965 where to find the keep-warm buffer */ @@ -438,7 +566,7 @@ static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) return rc; } -int iwl4965_hw_nic_init(struct iwl4965_priv *priv) +int iwl4965_hw_nic_init(struct iwl_priv *priv) { int rc; unsigned long flags; @@ -452,11 +580,11 @@ int iwl4965_hw_nic_init(struct iwl4965_priv *priv) /* nic_init */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS, + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl4965_poll_bit(priv, CSR_GP_CNTRL, + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (rc < 0) { @@ -465,26 +593,25 @@ int iwl4965_hw_nic_init(struct iwl4965_priv *priv) return rc; } - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl4965_read_prph(priv, APMG_CLK_CTRL_REG); + iwl_read_prph(priv, APMG_CLK_CTRL_REG); - iwl4965_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - iwl4965_read_prph(priv, APMG_CLK_CTRL_REG); + iwl_write_prph(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); + iwl_read_prph(priv, APMG_CLK_CTRL_REG); udelay(20); - iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl4965_release_nic_access(priv); - iwl4965_write32(priv, CSR_INT_COALESCING, 512 / 32); + iwl_release_nic_access(priv); + iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); /* Determine HW type */ @@ -520,25 +647,24 @@ int iwl4965_hw_nic_init(struct iwl4965_priv *priv) /* set CSR_HW_CONFIG_REG for uCode use */ - iwl4965_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | - CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR49_HW_IF_CONFIG_REG_BIT_4965_R | + CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); return rc; } - iwl4965_read_prph(priv, APMG_PS_CTRL_REG); - iwl4965_set_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); + iwl_read_prph(priv, APMG_PS_CTRL_REG); + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl4965_clear_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl4965_hw_card_show_info(priv); @@ -582,7 +708,7 @@ int iwl4965_hw_nic_init(struct iwl4965_priv *priv) return 0; } -int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv) +int iwl4965_hw_nic_stop_master(struct iwl_priv *priv) { int rc = 0; u32 reg_val; @@ -591,16 +717,16 @@ int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv) spin_lock_irqsave(&priv->lock, flags); /* set stop master bit */ - iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - reg_val = iwl4965_read32(priv, CSR_GP_CNTRL); + reg_val = iwl_read32(priv, CSR_GP_CNTRL); if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { - rc = iwl4965_poll_bit(priv, CSR_RESET, + rc = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { @@ -618,7 +744,7 @@ int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv) /** * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory */ -void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) +void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv) { int txq_id; @@ -627,18 +753,17 @@ void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) /* Stop each Tx DMA channel, and wait for it to be idle */ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { spin_lock_irqsave(&priv->lock, flags); - if (iwl4965_grab_nic_access(priv)) { + if (iwl_grab_nic_access(priv)) { spin_unlock_irqrestore(&priv->lock, flags); continue; } - iwl4965_write_direct32(priv, - IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - 0x0); - iwl4965_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, - IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE - (txq_id), 200); - iwl4965_release_nic_access(priv); + iwl_write_direct32(priv, + IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + iwl_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, + IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE + (txq_id), 200); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); } @@ -646,7 +771,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) iwl4965_hw_txq_ctx_free(priv); } -int iwl4965_hw_nic_reset(struct iwl4965_priv *priv) +int iwl4965_hw_nic_reset(struct iwl_priv *priv) { int rc = 0; unsigned long flags; @@ -655,29 +780,29 @@ int iwl4965_hw_nic_reset(struct iwl4965_priv *priv) spin_lock_irqsave(&priv->lock, flags); - iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); - iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl4965_poll_bit(priv, CSR_RESET, + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_RESET, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); udelay(10); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (!rc) { - iwl4965_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); - iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); } clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -707,7 +832,7 @@ int iwl4965_hw_nic_reset(struct iwl4965_priv *priv) */ static void iwl4965_bg_statistics_periodic(unsigned long data) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)data; + struct iwl_priv *priv = (struct iwl_priv *)data; queue_work(priv->workqueue, &priv->statistics_work); } @@ -719,7 +844,7 @@ static void iwl4965_bg_statistics_periodic(unsigned long data) */ static void iwl4965_bg_statistics_work(struct work_struct *work) { - struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, + struct iwl_priv *priv = container_of(work, struct iwl_priv, statistics_work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -733,17 +858,17 @@ static void iwl4965_bg_statistics_work(struct work_struct *work) #define CT_LIMIT_CONST 259 #define TM_CT_KILL_THRESHOLD 110 -void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv) +void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl4965_ct_kill_config cmd; u32 R1, R2, R3; u32 temp_th; u32 crit_temperature; unsigned long flags; - int rc = 0; + int ret = 0; spin_lock_irqsave(&priv->lock, flags); - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); @@ -761,9 +886,9 @@ void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv) crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; cmd.critical_temperature_R = cpu_to_le32(crit_temperature); - rc = iwl4965_send_cmd_pdu(priv, - REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); - if (rc) + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(cmd), &cmd); + if (ret) IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); else IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); @@ -779,7 +904,7 @@ void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv) * enough to receive all of our own network traffic, but not so * high that our DSP gets too busy trying to lock onto non-network * activity/noise. */ -static int iwl4965_sens_energy_cck(struct iwl4965_priv *priv, +static int iwl4965_sens_energy_cck(struct iwl_priv *priv, u32 norm_fa, u32 rx_enable_time, struct statistics_general_data *rx_info) @@ -970,7 +1095,7 @@ static int iwl4965_sens_energy_cck(struct iwl4965_priv *priv, } -static int iwl4965_sens_auto_corr_ofdm(struct iwl4965_priv *priv, +static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, u32 norm_fa, u32 rx_enable_time) { @@ -1035,25 +1160,25 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl4965_priv *priv, return 0; } -static int iwl4965_sensitivity_callback(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb) +static int iwl4965_sensitivity_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) { /* We didn't cache the SKB; let the caller free it */ return 1; } /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ -static int iwl4965_sensitivity_write(struct iwl4965_priv *priv, u8 flags) +static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) { - int rc = 0; struct iwl4965_sensitivity_cmd cmd ; struct iwl4965_sensitivity_data *data = NULL; - struct iwl4965_host_cmd cmd_out = { + struct iwl_host_cmd cmd_out = { .id = SENSITIVITY_CMD, .len = sizeof(struct iwl4965_sensitivity_cmd), .meta.flags = flags, .data = &cmd, }; + int ret; data = &(priv->sensitivity_data); @@ -1111,20 +1236,18 @@ static int iwl4965_sensitivity_write(struct iwl4965_priv *priv, u8 flags) memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE); - rc = iwl4965_send_cmd(priv, &cmd_out); - if (!rc) { - IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n"); - return rc; - } + ret = iwl_send_cmd(priv, &cmd_out); + if (ret) + IWL_ERROR("SENSITIVITY_CMD failed\n"); - return 0; + return ret; } -void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force) +void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) { - int rc = 0; - int i; struct iwl4965_sensitivity_data *data = NULL; + int i; + int ret = 0; IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); @@ -1168,8 +1291,8 @@ void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force) memset(&(priv->sensitivity_tbl[0]), 0, sizeof(u16)*HD_TABLE_SIZE); - rc |= iwl4965_sensitivity_write(priv, flags); - IWL_DEBUG_CALIB("<<return 0x%X\n", rc); + ret |= iwl4965_sensitivity_write(priv, flags); + IWL_DEBUG_CALIB("<<return 0x%X\n", ret); return; } @@ -1178,13 +1301,12 @@ void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force) /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ -void iwl4965_chain_noise_reset(struct iwl4965_priv *priv) +void iwl4965_chain_noise_reset(struct iwl_priv *priv) { struct iwl4965_chain_noise_data *data = NULL; - int rc = 0; data = &(priv->chain_noise_data); - if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl4965_is_associated(priv)) { + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { struct iwl4965_calibration_cmd cmd; memset(&cmd, 0, sizeof(cmd)); @@ -1192,8 +1314,8 @@ void iwl4965_chain_noise_reset(struct iwl4965_priv *priv) cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; - rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd); + iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd, NULL); msleep(4); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); @@ -1207,11 +1329,11 @@ void iwl4965_chain_noise_reset(struct iwl4965_priv *priv) * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers. */ -static void iwl4965_noise_calibration(struct iwl4965_priv *priv, +static void iwl4965_noise_calibration(struct iwl_priv *priv, struct iwl4965_notif_statistics *stat_resp) { struct iwl4965_chain_noise_data *data = NULL; - int rc = 0; + int ret = 0; u32 chain_noise_a; u32 chain_noise_b; @@ -1417,9 +1539,9 @@ static void iwl4965_noise_calibration(struct iwl4965_priv *priv, cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; - rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd); - if (rc) + if (ret) IWL_DEBUG_CALIB("fail sending cmd " "REPLY_PHY_CALIBRATION_CMD \n"); @@ -1440,10 +1562,9 @@ static void iwl4965_noise_calibration(struct iwl4965_priv *priv, return; } -static void iwl4965_sensitivity_calibration(struct iwl4965_priv *priv, +static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, struct iwl4965_notif_statistics *resp) { - int rc = 0; u32 rx_enable_time; u32 fa_cck; u32 fa_ofdm; @@ -1456,10 +1577,11 @@ static void iwl4965_sensitivity_calibration(struct iwl4965_priv *priv, struct statistics_rx *statistics = &(resp->rx); unsigned long flags; struct statistics_general_data statis; + int ret; data = &(priv->sensitivity_data); - if (!iwl4965_is_associated(priv)) { + if (!iwl_is_associated(priv)) { IWL_DEBUG_CALIB("<< - not associated\n"); return; } @@ -1540,14 +1662,14 @@ static void iwl4965_sensitivity_calibration(struct iwl4965_priv *priv, iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC); + ret = iwl4965_sensitivity_write(priv, CMD_ASYNC); return; } static void iwl4965_bg_sensitivity_work(struct work_struct *work) { - struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, + struct iwl_priv *priv = container_of(work, struct iwl_priv, sensitivity_work); mutex_lock(&priv->mutex); @@ -1577,7 +1699,7 @@ static void iwl4965_bg_sensitivity_work(struct work_struct *work) static void iwl4965_bg_txpower_work(struct work_struct *work) { - struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, + struct iwl_priv *priv = container_of(work, struct iwl_priv, txpower_work); /* If a scan happened to start before we got here @@ -1605,11 +1727,11 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* * Acquire priv->lock before calling this function ! */ -static void iwl4965_set_wr_ptrs(struct iwl4965_priv *priv, int txq_id, u32 index) +static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) { - iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, + iwl_write_direct32(priv, HBUS_TARG_WRPTR, (index & 0xff) | (txq_id << 8)); - iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(txq_id), index); + iwl_write_prph(priv, IWL49_SCD_QUEUE_RDPTR(txq_id), index); } /** @@ -1619,7 +1741,7 @@ static void iwl4965_set_wr_ptrs(struct iwl4965_priv *priv, int txq_id, u32 index * * NOTE: Acquire priv->lock before calling this function ! */ -static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv, +static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, int tx_fifo_id, int scd_retry) { @@ -1629,7 +1751,7 @@ static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv, int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; /* Set up and activate */ - iwl4965_write_prph(priv, KDR_SCD_QUEUE_STATUS_BITS(txq_id), + iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) | @@ -1653,22 +1775,22 @@ static const u16 default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -static inline void iwl4965_txq_ctx_activate(struct iwl4965_priv *priv, int txq_id) +static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) { set_bit(txq_id, &priv->txq_ctx_active_msk); } -static inline void iwl4965_txq_ctx_deactivate(struct iwl4965_priv *priv, int txq_id) +static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) { clear_bit(txq_id, &priv->txq_ctx_active_msk); } -int iwl4965_alive_notify(struct iwl4965_priv *priv) +int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; int i = 0; unsigned long flags; - int rc; + int ret; spin_lock_irqsave(&priv->lock, flags); @@ -1681,46 +1803,46 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) priv->chain_noise_data.delta_gain_code[i] = CHAIN_NOISE_DELTA_GAIN_INIT_VAL; #endif /* CONFIG_IWL4965_SENSITIVITY*/ - rc = iwl4965_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Clear 4965's internal Tx Scheduler data base */ - priv->scd_base_addr = iwl4965_read_prph(priv, KDR_SCD_SRAM_BASE_ADDR); + priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) - iwl4965_write_targ_mem(priv, a, 0); + iwl_write_targ_mem(priv, a, 0); for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4) - iwl4965_write_targ_mem(priv, a, 0); + iwl_write_targ_mem(priv, a, 0); for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4) - iwl4965_write_targ_mem(priv, a, 0); + iwl_write_targ_mem(priv, a, 0); /* Tel 4965 where to find Tx byte count tables */ - iwl4965_write_prph(priv, KDR_SCD_DRAM_BASE_ADDR, + iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, (priv->hw_setting.shared_phys + offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); /* Disable chain mode for all queues */ - iwl4965_write_prph(priv, KDR_SCD_QUEUECHAIN_SEL, 0); + iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); /* Initialize each Tx queue (including the command queue) */ for (i = 0; i < priv->hw_setting.max_txq_num; i++) { /* TFD circular buffer read/write indexes */ - iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(i), 0); - iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_prph(priv, IWL49_SCD_QUEUE_RDPTR(i), 0); + iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); /* Max Tx Window size for Scheduler-ACK mode */ - iwl4965_write_targ_mem(priv, priv->scd_base_addr + + iwl_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(i), (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); /* Frame limit */ - iwl4965_write_targ_mem(priv, priv->scd_base_addr + + iwl_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(i) + sizeof(u32), (SCD_FRAME_LIMIT << @@ -1728,11 +1850,11 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); } - iwl4965_write_prph(priv, KDR_SCD_INTERRUPT_MASK, + iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << priv->hw_setting.max_txq_num) - 1); /* Activate all Tx DMA/FIFO channels */ - iwl4965_write_prph(priv, KDR_SCD_TXFACT, + iwl_write_prph(priv, IWL49_SCD_TXFACT, SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); @@ -1744,10 +1866,10 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return ret; } /** @@ -1755,32 +1877,47 @@ int iwl4965_alive_notify(struct iwl4965_priv *priv) * * Called when initializing driver */ -int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv) +int iwl4965_hw_set_hw_setting(struct iwl_priv *priv) { + int ret = 0; + + if ((priv->cfg->mod_params->num_of_queues > IWL_MAX_NUM_QUEUES) || + (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); + ret = -EINVAL; + goto out; + } + /* Allocate area for Tx byte count tables and Rx queue status */ priv->hw_setting.shared_virt = pci_alloc_consistent(priv->pci_dev, sizeof(struct iwl4965_shared), &priv->hw_setting.shared_phys); - if (!priv->hw_setting.shared_virt) - return -1; + if (!priv->hw_setting.shared_virt) { + ret = -ENOMEM; + goto out; + } memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared)); - priv->hw_setting.max_txq_num = iwl4965_param_queues_num; - priv->hw_setting.ac_queue_count = AC_NUM; + priv->hw_setting.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (iwl4965_param_amsdu_size_8K) + if (priv->cfg->mod_params->amsdu_size_8K) priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K; else priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K; priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256; priv->hw_setting.max_stations = IWL4965_STATION_COUNT; priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID; - return 0; + + priv->hw_setting.tx_ant_num = 2; + +out: + return ret; } /** @@ -1788,7 +1925,7 @@ int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv) * * Destroy all TX DMA queues and structures */ -void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv) +void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv) { int txq_id; @@ -1806,7 +1943,7 @@ void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv) * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) +int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) { struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0]; struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; @@ -1859,7 +1996,7 @@ int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue * return 0; } -int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power) +int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) { IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n"); return -EINVAL; @@ -1914,12 +2051,13 @@ static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, return comp; } -static const struct iwl4965_channel_info * -iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, u8 phymode, u16 channel) +static const struct iwl_channel_info * +iwl4965_get_channel_txpower_info(struct iwl_priv *priv, + enum ieee80211_band band, u16 channel) { - const struct iwl4965_channel_info *ch_info; + const struct iwl_channel_info *ch_info; - ch_info = iwl4965_get_channel_info(priv, phymode, channel); + ch_info = iwl_get_channel_info(priv, band, channel); if (!is_channel_valid(ch_info)) return NULL; @@ -1953,7 +2091,7 @@ static s32 iwl4965_get_tx_atten_grp(u16 channel) return -1; } -static u32 iwl4965_get_sub_band(const struct iwl4965_priv *priv, u32 channel) +static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) { s32 b = -1; @@ -1989,7 +2127,7 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) * differences in channel frequencies, which is proportional to differences * in channel number. */ -static int iwl4965_interpolate_chan(struct iwl4965_priv *priv, u32 channel, +static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, struct iwl4965_eeprom_calib_ch_info *chan_info) { s32 s = -1; @@ -2322,7 +2460,7 @@ static const struct gain_entry gain_table[2][108] = { } }; -static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 channel, +static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, u8 is_fat, u8 ctrl_chan_high, struct iwl4965_tx_power_db *tx_power_tbl) { @@ -2336,7 +2474,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 chan s32 txatten_grp = CALIB_CH_GROUP_MAX; int i; int c; - const struct iwl4965_channel_info *ch_info = NULL; + const struct iwl_channel_info *ch_info = NULL; struct iwl4965_eeprom_calib_ch_info ch_eeprom_info; const struct iwl4965_eeprom_calib_measure *measurement; s16 voltage; @@ -2368,7 +2506,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 chan /* Get current (RXON) channel, band, width */ ch_info = - iwl4965_get_channel_txpower_info(priv, priv->phymode, channel); + iwl4965_get_channel_txpower_info(priv, priv->band, channel); IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band, is_fat); @@ -2579,10 +2717,10 @@ static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 chan * Uses the active RXON for channel, band, and characteristics (fat, high) * The power limit is taken from priv->user_txpower_limit. */ -int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv) +int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv) { struct iwl4965_txpowertable_cmd cmd = { 0 }; - int rc = 0; + int ret; u8 band = 0; u8 is_fat = 0; u8 ctrl_chan_high = 0; @@ -2595,8 +2733,7 @@ int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv) return -EAGAIN; } - band = ((priv->phymode == MODE_IEEE80211B) || - (priv->phymode == MODE_IEEE80211G)); + band = priv->band == IEEE80211_BAND_2GHZ; is_fat = is_fat_channel(priv->active_rxon.flags); @@ -2607,29 +2744,30 @@ int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv) cmd.band = band; cmd.channel = priv->active_rxon.channel; - rc = iwl4965_fill_txpower_tbl(priv, band, + ret = iwl4965_fill_txpower_tbl(priv, band, le16_to_cpu(priv->active_rxon.channel), is_fat, ctrl_chan_high, &cmd.tx_power); - if (rc) - return rc; + if (ret) + goto out; - rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); - return rc; + ret = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); + +out: + return ret; } -int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel) +int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; u8 is_fat = 0; u8 ctrl_chan_high = 0; struct iwl4965_channel_switch_cmd cmd = { 0 }; - const struct iwl4965_channel_info *ch_info; + const struct iwl_channel_info *ch_info; - band = ((priv->phymode == MODE_IEEE80211B) || - (priv->phymode == MODE_IEEE80211G)); + band = priv->band == IEEE80211_BAND_2GHZ; - ch_info = iwl4965_get_channel_info(priv, priv->phymode, channel); + ch_info = iwl_get_channel_info(priv, priv->band, channel); is_fat = is_fat_channel(priv->staging_rxon.flags); @@ -2655,15 +2793,15 @@ int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel) return rc; } - rc = iwl4965_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); + rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } #define RTS_HCCA_RETRY_LIMIT 3 #define RTS_DFAULT_RETRY_LIMIT 60 -void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, +void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int sta_id, int is_hcca) @@ -2674,7 +2812,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, u16 fc = le16_to_cpu(hdr->frame_control); u8 rate_plcp; u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); + int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); rate_plcp = iwl4965_rates[rate_idx].plcp; @@ -2729,19 +2867,19 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); } -int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv) +int iwl4965_hw_get_rx_read(struct iwl_priv *priv) { struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt; return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num); } -int iwl4965_hw_get_temperature(struct iwl4965_priv *priv) +int iwl4965_hw_get_temperature(struct iwl_priv *priv) { return priv->temperature; } -unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, +unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl4965_frame *frame, u8 rate) { struct iwl4965_tx_beacon_cmd *tx_beacon_cmd; @@ -2750,7 +2888,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, tx_beacon_cmd = &frame->u.beacon; memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID; + tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id; tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; frame_size = iwl4965_fill_beacon_frame(priv, @@ -2780,35 +2918,35 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA * channels supported in hardware. */ -int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) +int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) { int rc; unsigned long flags; int txq_id = txq->q.id; spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } /* Circular buffer (TFD queue in DRAM) physical base address */ - iwl4965_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), + iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); /* Enable DMA channel, using same id as for TFD queue */ - iwl4965_write_direct32( + iwl_write_direct32( priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *ptr, +int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, dma_addr_t addr, u16 len) { int index, is_odd; @@ -2842,7 +2980,7 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *ptr, return 0; } -static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv) +static void iwl4965_hw_card_show_info(struct iwl_priv *priv) { u16 hw_version = priv->eeprom.board_revision_4965; @@ -2860,7 +2998,7 @@ static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv) /** * iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array */ -int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, +int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, u16 byte_cnt) { int len; @@ -2891,7 +3029,7 @@ int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, * Selects how many and which Rx receivers/antennas/chains to use. * This should not be used for scan command ... it puts data in wrong place. */ -void iwl4965_set_rxon_chain(struct iwl4965_priv *priv) +void iwl4965_set_rxon_chain(struct iwl_priv *priv) { u8 is_single = is_single_stream(priv); u8 idle_state, rx_state; @@ -2922,378 +3060,6 @@ void iwl4965_set_rxon_chain(struct iwl4965_priv *priv) IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); } -#ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG -/* - get the traffic load value for tid -*/ -static u32 iwl4965_tl_get_load(struct iwl4965_priv *priv, u8 tid) -{ - u32 load = 0; - u32 current_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - unsigned long flags; - struct iwl4965_traffic_load *tid_ptr = NULL; - - if (tid >= TID_MAX_LOAD_COUNT) - return 0; - - tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]); - - current_time -= current_time % TID_ROUND_VALUE; - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - if (!(tid_ptr->queue_count)) - goto out; - - time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time); - index = time_diff / TID_QUEUE_CELL_SPACING; - - if (index >= TID_QUEUE_MAX_SIZE) { - u32 oldest_time = current_time - TID_MAX_TIME_DIFF; - - while (tid_ptr->queue_count && - (tid_ptr->time_stamp < oldest_time)) { - tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head]; - tid_ptr->packet_count[tid_ptr->head] = 0; - tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING; - tid_ptr->queue_count--; - tid_ptr->head++; - if (tid_ptr->head >= TID_QUEUE_MAX_SIZE) - tid_ptr->head = 0; - } - } - load = tid_ptr->total; - - out: - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - return load; -} - -/* - increment traffic load value for tid and also remove - any old values if passed the certian time period -*/ -static void iwl4965_tl_add_packet(struct iwl4965_priv *priv, u8 tid) -{ - u32 current_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - unsigned long flags; - struct iwl4965_traffic_load *tid_ptr = NULL; - - if (tid >= TID_MAX_LOAD_COUNT) - return; - - tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]); - - current_time -= current_time % TID_ROUND_VALUE; - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - if (!(tid_ptr->queue_count)) { - tid_ptr->total = 1; - tid_ptr->time_stamp = current_time; - tid_ptr->queue_count = 1; - tid_ptr->head = 0; - tid_ptr->packet_count[0] = 1; - goto out; - } - - time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time); - index = time_diff / TID_QUEUE_CELL_SPACING; - - if (index >= TID_QUEUE_MAX_SIZE) { - u32 oldest_time = current_time - TID_MAX_TIME_DIFF; - - while (tid_ptr->queue_count && - (tid_ptr->time_stamp < oldest_time)) { - tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head]; - tid_ptr->packet_count[tid_ptr->head] = 0; - tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING; - tid_ptr->queue_count--; - tid_ptr->head++; - if (tid_ptr->head >= TID_QUEUE_MAX_SIZE) - tid_ptr->head = 0; - } - } - - index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE; - tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1; - tid_ptr->total = tid_ptr->total + 1; - - if ((index + 1) > tid_ptr->queue_count) - tid_ptr->queue_count = index + 1; - out: - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - -} - -#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7 -enum HT_STATUS { - BA_STATUS_FAILURE = 0, - BA_STATUS_INITIATOR_DELBA, - BA_STATUS_RECIPIENT_DELBA, - BA_STATUS_RENEW_ADDBA_REQUEST, - BA_STATUS_ACTIVE, -}; - -/** - * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available - */ -static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv) -{ - int i; - struct iwl4965_lq_mngr *lq; - u8 count = 0; - u16 msk; - - lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); - - /* Find out how many agg queues are in use */ - for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) { - msk = 1 << i; - if ((lq->agg_ctrl.granted_ba & msk) || - (lq->agg_ctrl.wait_for_agg_status & msk)) - count++; - } - - if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS) - return 1; - - return 0; -} - -static void iwl4965_ba_status(struct iwl4965_priv *priv, - u8 tid, enum HT_STATUS status); - -static int iwl4965_perform_addba(struct iwl4965_priv *priv, u8 tid, u32 length, - u32 ba_timeout) -{ - int rc; - - rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid); - if (rc) - iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE); - - return rc; -} - -static int iwl4965_perform_delba(struct iwl4965_priv *priv, u8 tid) -{ - int rc; - - rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid); - if (rc) - iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE); - - return rc; -} - -static void iwl4965_turn_on_agg_for_tid(struct iwl4965_priv *priv, - struct iwl4965_lq_mngr *lq, - u8 auto_agg, u8 tid) -{ - u32 tid_msk = (1 << tid); - unsigned long flags; - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); -/* - if ((auto_agg) && (!lq->enable_counter)){ - lq->agg_ctrl.next_retry = 0; - lq->agg_ctrl.tid_retry = 0; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - return; - } -*/ - if (!(lq->agg_ctrl.granted_ba & tid_msk) && - (lq->agg_ctrl.requested_ba & tid_msk)) { - u8 available_queues; - u32 load; - - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - available_queues = iwl4964_tl_ba_avail(priv); - load = iwl4965_tl_get_load(priv, tid); - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - if (!available_queues) { - if (auto_agg) - lq->agg_ctrl.tid_retry |= tid_msk; - else { - lq->agg_ctrl.requested_ba &= ~tid_msk; - lq->agg_ctrl.wait_for_agg_status &= ~tid_msk; - } - } else if ((auto_agg) && - ((load <= lq->agg_ctrl.tid_traffic_load_threshold) || - ((lq->agg_ctrl.wait_for_agg_status & tid_msk)))) - lq->agg_ctrl.tid_retry |= tid_msk; - else { - lq->agg_ctrl.wait_for_agg_status |= tid_msk; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - iwl4965_perform_addba(priv, tid, 0x40, - lq->agg_ctrl.ba_timeout); - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - } - } - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); -} - -static void iwl4965_turn_on_agg(struct iwl4965_priv *priv, u8 tid) -{ - struct iwl4965_lq_mngr *lq; - unsigned long flags; - - lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); - - if ((tid < TID_MAX_LOAD_COUNT)) - iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg, - tid); - else if (tid == TID_ALL_SPECIFIED) { - if (lq->agg_ctrl.requested_ba) { - for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) - iwl4965_turn_on_agg_for_tid(priv, lq, - lq->agg_ctrl.auto_agg, tid); - } else { - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - lq->agg_ctrl.tid_retry = 0; - lq->agg_ctrl.next_retry = 0; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - } - } - -} - -void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid) -{ - u32 tid_msk; - struct iwl4965_lq_mngr *lq; - unsigned long flags; - - lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); - - if ((tid < TID_MAX_LOAD_COUNT)) { - tid_msk = 1 << tid; - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - lq->agg_ctrl.wait_for_agg_status |= tid_msk; - lq->agg_ctrl.requested_ba &= ~tid_msk; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - iwl4965_perform_delba(priv, tid); - } else if (tid == TID_ALL_SPECIFIED) { - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) { - tid_msk = 1 << tid; - lq->agg_ctrl.wait_for_agg_status |= tid_msk; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - iwl4965_perform_delba(priv, tid); - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - } - lq->agg_ctrl.requested_ba = 0; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - } -} - -/** - * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status - */ -static void iwl4965_ba_status(struct iwl4965_priv *priv, - u8 tid, enum HT_STATUS status) -{ - struct iwl4965_lq_mngr *lq; - u32 tid_msk = (1 << tid); - unsigned long flags; - - lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); - - if ((tid >= TID_MAX_LOAD_COUNT)) - goto out; - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - switch (status) { - case BA_STATUS_ACTIVE: - if (!(lq->agg_ctrl.granted_ba & tid_msk)) - lq->agg_ctrl.granted_ba |= tid_msk; - break; - default: - if ((lq->agg_ctrl.granted_ba & tid_msk)) - lq->agg_ctrl.granted_ba &= ~tid_msk; - break; - } - - lq->agg_ctrl.wait_for_agg_status &= ~tid_msk; - if (status != BA_STATUS_ACTIVE) { - if (lq->agg_ctrl.auto_agg) { - lq->agg_ctrl.tid_retry |= tid_msk; - lq->agg_ctrl.next_retry = - jiffies + msecs_to_jiffies(500); - } else - lq->agg_ctrl.requested_ba &= ~tid_msk; - } - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - out: - return; -} - -static void iwl4965_bg_agg_work(struct work_struct *work) -{ - struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, - agg_work); - - u32 tid; - u32 retry_tid; - u32 tid_msk; - unsigned long flags; - struct iwl4965_lq_mngr *lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - retry_tid = lq->agg_ctrl.tid_retry; - lq->agg_ctrl.tid_retry = 0; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - - if (retry_tid == TID_ALL_SPECIFIED) - iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED); - else { - for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) { - tid_msk = (1 << tid); - if (retry_tid & tid_msk) - iwl4965_turn_on_agg(priv, tid); - } - } - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - if (lq->agg_ctrl.tid_retry) - lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500); - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - return; -} - -/* TODO: move this functionality to rate scaling */ -void iwl4965_tl_get_stats(struct iwl4965_priv *priv, - struct ieee80211_hdr *hdr) -{ - __le16 *qc = ieee80211_get_qos_ctrl(hdr); - - if (qc && - (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) { - u8 tid = 0; - tid = (u8) (le16_to_cpu(*qc) & 0xF); - if (tid < TID_MAX_LOAD_COUNT) - iwl4965_tl_add_packet(priv, tid); - } - - if (priv->lq_mngr.agg_ctrl.next_retry && - (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) { - unsigned long flags; - - spin_lock_irqsave(&priv->lq_mngr.lock, flags); - priv->lq_mngr.agg_ctrl.next_retry = 0; - spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); - schedule_work(&priv->agg_work); - } -} - -#endif /*CONFIG_IWL4965_HT_AGG */ -#endif /* CONFIG_IWL4965_HT */ - /** * sign_extend - Sign extend a value using specified bit as sign-bit * @@ -3316,7 +3082,7 @@ static s32 sign_extend(u32 oper, int index) * * A return of <0 indicates bogus data in the statistics */ -int iwl4965_get_temperature(const struct iwl4965_priv *priv) +int iwl4965_get_temperature(const struct iwl_priv *priv) { s32 temperature; s32 vt; @@ -3384,7 +3150,7 @@ int iwl4965_get_temperature(const struct iwl4965_priv *priv) * Assumes caller will replace priv->last_temperature once calibration * executed. */ -static int iwl4965_is_temp_calib_needed(struct iwl4965_priv *priv) +static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) { int temp_diff; @@ -3417,7 +3183,7 @@ static int iwl4965_is_temp_calib_needed(struct iwl4965_priv *priv) /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl4965_rx_calc_noise(struct iwl4965_priv *priv) +static void iwl4965_rx_calc_noise(struct iwl_priv *priv) { struct statistics_rx_non_phy *rx_info = &(priv->statistics.rx.general); @@ -3454,7 +3220,7 @@ static void iwl4965_rx_calc_noise(struct iwl4965_priv *priv) priv->last_rx_noise); } -void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb) +void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; int change; @@ -3488,6 +3254,8 @@ void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, struct iwl4965_rx_mem_b #endif } + iwl_leds_background(priv); + /* If the hardware hasn't reported a change in * temperature then don't bother computing a * calibrated temperature value */ @@ -3518,7 +3286,7 @@ void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, struct iwl4965_rx_mem_b queue_work(priv->workqueue, &priv->txpower_work); } -static void iwl4965_add_radiotap(struct iwl4965_priv *priv, +static void iwl4965_add_radiotap(struct iwl_priv *priv, struct sk_buff *skb, struct iwl4965_rx_phy_res *rx_start, struct ieee80211_rx_status *stats, @@ -3526,8 +3294,9 @@ static void iwl4965_add_radiotap(struct iwl4965_priv *priv, { s8 signal = stats->ssi; s8 noise = 0; - int rate = stats->rate; + int rate = stats->rate_idx; u64 tsf = stats->mactime; + __le16 antenna; __le16 phy_flags_hw = rx_start->phy_flags; struct iwl4965_rt_rx_hdr { struct ieee80211_radiotap_header rt_hdr; @@ -3594,7 +3363,6 @@ static void iwl4965_add_radiotap(struct iwl4965_priv *priv, IEEE80211_CHAN_2GHZ), &iwl4965_rt->rt_chbitmask); - rate = iwl4965_rate_index_from_plcp(rate); if (rate == -1) iwl4965_rt->rt_rate = 0; else @@ -3613,8 +3381,8 @@ static void iwl4965_add_radiotap(struct iwl4965_priv *priv, * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ - iwl4965_rt->rt_antenna = - le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; + iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; /* set the preamble flag if appropriate */ if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) @@ -3623,7 +3391,74 @@ static void iwl4965_add_radiotap(struct iwl4965_priv *priv, stats->flag |= RX_FLAG_RADIOTAP; } -static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data, +static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->rx_stats[idx].cnt++; + priv->rx_stats[idx].bytes += len; +} + +static u32 iwl4965_translate_rx_status(u32 decrypt_in) +{ + u32 decrypt_out = 0; + + if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == + RX_RES_STATUS_STATION_FOUND) + decrypt_out |= (RX_RES_STATUS_STATION_FOUND | + RX_RES_STATUS_NO_STATION_INFO_MISMATCH); + + decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); + + /* packet was not encrypted */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_NONE) + return decrypt_out; + + /* packet was encrypted with unknown alg */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_ERR) + return decrypt_out; + + /* decryption was not done in HW */ + if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != + RX_MPDU_RES_STATUS_DEC_DONE_MSK) + return decrypt_out; + + switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { + + case RX_RES_STATUS_SEC_TYPE_CCMP: + /* alg is CCM: check MIC only */ + if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) + /* Bad MIC */ + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + + break; + + case RX_RES_STATUS_SEC_TYPE_TKIP: + if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { + /* Bad TTAK */ + decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; + break; + } + /* fall through if TTAK OK */ + default: + if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + break; + }; + + IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", + decrypt_in, decrypt_out); + + return decrypt_out; +} + +static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, int include_phy, struct iwl4965_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) @@ -3636,6 +3471,7 @@ static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data, __le32 *rx_end; unsigned int skblen; u32 ampdu_status; + u32 ampdu_status_legacy; if (!include_phy && priv->last_phy_res[0]) rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; @@ -3672,6 +3508,12 @@ static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data, ampdu_status = le32_to_cpu(*rx_end); skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32); + if (!include_phy) { + /* New status scheme, need to translate */ + ampdu_status_legacy = ampdu_status; + ampdu_status = iwl4965_translate_rx_status(ampdu_status); + } + /* start from MAC */ skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); skb_put(rxb->skb, len); /* end where data ends */ @@ -3686,19 +3528,16 @@ static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data, stats->flag = 0; hdr = (struct ieee80211_hdr *)rxb->skb->data; - if (iwl4965_param_hwcrypto) + if (priv->cfg->mod_params->hw_crypto) iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); if (priv->add_radiotap) iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); + iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); priv->alloc_rxb_skb--; rxb->skb = NULL; -#ifdef LED - priv->led_packets += len; - iwl4965_setup_activity_timer(priv); -#endif } /* Calc max signal level (dBm) among 3 possible receivers */ @@ -3737,85 +3576,16 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) #ifdef CONFIG_IWL4965_HT -/* Parsed Information Elements */ -struct ieee802_11_elems { - u8 *ds_params; - u8 ds_params_len; - u8 *tim; - u8 tim_len; - u8 *ibss_params; - u8 ibss_params_len; - u8 *erp_info; - u8 erp_info_len; - u8 *ht_cap_param; - u8 ht_cap_param_len; - u8 *ht_extra_param; - u8 ht_extra_param_len; -}; - -static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) -{ - size_t left = len; - u8 *pos = start; - int unknown = 0; - - memset(elems, 0, sizeof(*elems)); - - while (left >= 2) { - u8 id, elen; - - id = *pos++; - elen = *pos++; - left -= 2; - - if (elen > left) - return -1; - - switch (id) { - case WLAN_EID_DS_PARAMS: - elems->ds_params = pos; - elems->ds_params_len = elen; - break; - case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; - break; - case WLAN_EID_IBSS_PARAMS: - elems->ibss_params = pos; - elems->ibss_params_len = elen; - break; - case WLAN_EID_ERP_INFO: - elems->erp_info = pos; - elems->erp_info_len = elen; - break; - case WLAN_EID_HT_CAPABILITY: - elems->ht_cap_param = pos; - elems->ht_cap_param_len = elen; - break; - case WLAN_EID_HT_EXTRA_INFO: - elems->ht_extra_param = pos; - elems->ht_extra_param_len = elen; - break; - default: - unknown++; - break; - } - - left -= elen; - pos += elen; - } - - return 0; -} - -void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode) +void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band) { ht_info->cap = 0; memset(ht_info->supp_mcs_set, 0, 16); ht_info->ht_supported = 1; - if (mode == MODE_IEEE80211A) { + if (band == IEEE80211_BAND_5GHZ) { ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; ht_info->supp_mcs_set[4] = 0x01; @@ -3824,10 +3594,9 @@ void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode) ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & (IWL_MIMO_PS_NONE << 2)); - if (iwl4965_param_amsdu_size_8K) { - printk(KERN_DEBUG "iwl4965 in A-MSDU 8K support mode\n"); + + if (priv->cfg->mod_params->amsdu_size_8K) ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; - } ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; @@ -3837,7 +3606,7 @@ void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode) } #endif /* CONFIG_IWL4965_HT */ -static void iwl4965_sta_modify_ps_wake(struct iwl4965_priv *priv, int sta_id) +static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -3851,7 +3620,7 @@ static void iwl4965_sta_modify_ps_wake(struct iwl4965_priv *priv, int sta_id) iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *addr) +static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) { /* FIXME: need locking over ps_status ??? */ u8 sta_id = iwl4965_hw_find_station(priv, addr); @@ -3868,44 +3637,201 @@ static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *ad } } } +#ifdef CONFIG_IWLWIFI_DEBUG -#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) +/** + * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions + * + * You may hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: This was originally written for 3945, need to audit for + * proper operation with 4965. + */ +static void iwl4965_dbg_report_frame(struct iwl_priv *priv, + struct iwl4965_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + if (likely(!(iwl_debug_level & IWL_DL_RX))) + return; -/* Called for REPLY_4965_RX (legacy ABG frames), or + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + int rate_idx; + u32 bitrate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate_idx = iwl4965_hwrate_to_plcp_idx(rate_sym); + if (unlikely(rate_idx == -1)) + bitrate = 0; + else + bitrate = iwl4965_rates[rate_idx].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, bitrate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(IWL_DL_RX, data, length); +} +#else +static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, + struct iwl4965_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) +{ +} +#endif + + + +/* Called for REPLY_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_rx(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; /* Use phy data (Rx signal strength, etc.) contained within * this rx packet for legacy frames, * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_4965_RX); + int include_phy = (pkt->hdr.cmd == REPLY_RX); struct iwl4965_rx_phy_res *rx_start = (include_phy) ? (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; __le32 *rx_end; unsigned int len = 0; - struct ieee80211_hdr *header; u16 fc; - struct ieee80211_rx_status stats = { - .mactime = le64_to_cpu(rx_start->timestamp), - .channel = le16_to_cpu(rx_start->channel), - .phymode = - (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - MODE_IEEE80211G : MODE_IEEE80211A, - .antenna = 0, - .rate = iwl4965_hw_get_rate(rx_start->rate_n_flags), - .flag = 0, - }; u8 network_packet; + rx_status.mactime = le64_to_cpu(rx_start->timestamp); + rx_status.freq = + ieee80211_frequency_to_channel(le16_to_cpu(rx_start->channel)); + rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.rate_idx = + iwl4965_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); + if (rx_status.band == IEEE80211_BAND_5GHZ) + rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; + + rx_status.antenna = 0; + rx_status.flag = 0; + if ((unlikely(rx_start->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP - ("dsp size out of range [0,20]: " - "%d/n", rx_start->cfg_phy_cnt); + IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", + rx_start->cfg_phy_cnt); return; } + if (!include_phy) { if (priv->last_phy_res[0]) rx_start = (struct iwl4965_rx_phy_res *) @@ -3924,7 +3850,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, + rx_start->cfg_phy_cnt); len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt + + rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + sizeof(struct iwl4965_rx_phy_res) + len); } else { struct iwl4965_rx_mpdu_res_start *amsdu = @@ -3946,43 +3872,38 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); - stats.freq = ieee80211chan2mhz(stats.channel); - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - stats.ssi = iwl4965_calc_rssi(rx_start); + rx_status.ssi = iwl4965_calc_rssi(rx_start); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise * only for the associated network channel ... * Ignore these noise values while scanning (other channels) */ - if (iwl4965_is_associated(priv) && + if (iwl_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { - stats.noise = priv->last_rx_noise; - stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise); + rx_status.noise = priv->last_rx_noise; + rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, + rx_status.noise); } else { - stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0); + rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); } /* Reset beacon noise level if not associated. */ - if (!iwl4965_is_associated(priv)) + if (!iwl_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; -#ifdef CONFIG_IWL4965_DEBUG - /* TODO: Parts of iwl4965_report_frame are broken for 4965 */ - if (iwl4965_debug_level & (IWL_DL_RX)) - /* Set "1" to report good data frames in groups of 100 */ - iwl4965_report_frame(priv, pkt, header, 1); + /* Set "1" to report good data frames in groups of 100 */ + /* FIXME: need to optimze the call: */ + iwl4965_dbg_report_frame(priv, pkt, header, 1); - if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS)) - IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", - stats.ssi, stats.noise, stats.signal, - (long unsigned int)le64_to_cpu(rx_start->timestamp)); -#endif + IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", + rx_status.ssi, rx_status.noise, rx_status.signal, + (unsigned long long)rx_status.mactime); network_packet = iwl4965_is_network_packet(priv, header); if (network_packet) { - priv->last_rx_rssi = stats.ssi; + priv->last_rx_rssi = rx_status.ssi; priv->last_beacon_time = priv->ucode_beacon_time; priv->last_tsf = le64_to_cpu(rx_start->timestamp); } @@ -3990,102 +3911,10 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, fc = le16_to_cpu(header->frame_control); switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, header->addr2); - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_BEACON: - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA && - !compare_ether_addr(header->addr2, priv->bssid)) || - (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && - !compare_ether_addr(header->addr3, priv->bssid))) { - struct ieee80211_mgmt *mgmt = - (struct ieee80211_mgmt *)header; - u64 timestamp = - le64_to_cpu(mgmt->u.beacon.timestamp); - - priv->timestamp0 = timestamp & 0xFFFFFFFF; - priv->timestamp1 = - (timestamp >> 32) & 0xFFFFFFFF; - priv->beacon_int = le16_to_cpu( - mgmt->u.beacon.beacon_int); - if (priv->call_post_assoc_from_beacon && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - priv->call_post_assoc_from_beacon = 0; - queue_work(priv->workqueue, - &priv->post_associate.work); - } - } - break; - - case IEEE80211_STYPE_ACTION: - break; - - /* - * TODO: Use the new callback function from - * mac80211 instead of sniffing these packets. - */ - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - if (network_packet) { -#ifdef CONFIG_IWL4965_HT - u8 *pos = NULL; - struct ieee802_11_elems elems; -#endif /*CONFIG_IWL4965_HT */ - struct ieee80211_mgmt *mgnt = - (struct ieee80211_mgmt *)header; - - /* We have just associated, give some - * time for the 4-way handshake if - * any. Don't start scan too early. */ - priv->next_scan_jiffies = jiffies + - IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; - - priv->assoc_id = (~((1 << 15) | (1 << 14)) - & le16_to_cpu(mgnt->u.assoc_resp.aid)); - priv->assoc_capability = - le16_to_cpu( - mgnt->u.assoc_resp.capab_info); -#ifdef CONFIG_IWL4965_HT - pos = mgnt->u.assoc_resp.variable; - if (!parse_elems(pos, - len - (pos - (u8 *) mgnt), - &elems)) { - if (elems.ht_extra_param && - elems.ht_cap_param) - break; - } -#endif /*CONFIG_IWL4965_HT */ - /* assoc_id is 0 no association */ - if (!priv->assoc_id) - break; - if (priv->beacon_int) - queue_work(priv->workqueue, - &priv->post_associate.work); - else - priv->call_post_assoc_from_beacon = 1; - } - - break; - - case IEEE80211_STYPE_PROBE_REQ: - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !iwl4965_is_associated(priv)) { - DECLARE_MAC_BUF(mac1); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - - IWL_DEBUG_DROP("Dropping (non network): " - "%s, %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - return; - } - } - iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats); + iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); break; case IEEE80211_FTYPE_CTL: @@ -4094,7 +3923,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, case IEEE80211_STYPE_BACK_REQ: IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); iwl4965_handle_data_packet(priv, 0, include_phy, - rxb, &stats); + rxb, &rx_status); break; default: break; @@ -4124,7 +3953,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, print_mac(mac3, header->addr3)); else iwl4965_handle_data_packet(priv, 1, include_phy, rxb, - &stats); + &rx_status); break; } default: @@ -4135,7 +3964,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static void iwl4965_rx_reply_rx_phy(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -4143,8 +3972,7 @@ static void iwl4965_rx_reply_rx_phy(struct iwl4965_priv *priv, memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), sizeof(struct iwl4965_rx_phy_res)); } - -static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { @@ -4165,31 +3993,12 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv, } #endif /*CONFIG_IWL4965_SENSITIVITY*/ } - #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG - -/** - * iwl4965_set_tx_status - Update driver's record of one Tx frame's status - * - * This will get sent to mac80211. - */ -static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx, - u32 status, u32 retry_count, u32 rate) -{ - struct ieee80211_tx_status *tx_status = - &(priv->txq[txq_id].txb[idx].status); - - tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0; - tx_status->retry_count += retry_count; - tx_status->control.tx_rate = rate; -} - /** * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table */ -static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv, +static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) { unsigned long flags; @@ -4204,24 +4013,24 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv, iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } - /** * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack * * Go through block-ack's bitmap of ACK'd frames, update driver's record of * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. */ -static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, +static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, struct iwl4965_ht_agg *agg, struct iwl4965_compressed_ba_resp* ba_resp) { int i, sh, ack; - u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl); - u32 bitmap0, bitmap1; - u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0); - u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1); + u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); + u64 bitmap; + int successes = 0; + struct ieee80211_tx_status *tx_status; if (unlikely(!agg->wait_for_ba)) { IWL_ERROR("Received BA when not expected\n"); @@ -4230,17 +4039,15 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, /* Mark that the expected block-ack response arrived */ agg->wait_for_ba = 0; - IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl); + IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); /* Calculate shift to align block-ack bits with our Tx window bits */ - sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl >> 4); + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); if (sh < 0) /* tbw something is wrong with indices */ sh += 0x100; /* don't use 64-bit values for now */ - bitmap0 = resp_bitmap0 >> sh; - bitmap1 = resp_bitmap1 >> sh; - bitmap0 |= (resp_bitmap1 & ((1 << sh) | ((1 << sh) - 1))) << (32 - sh); + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; if (agg->frame_count > (64 - sh)) { IWL_DEBUG_TX_REPLY("more frames than bitmap size"); @@ -4249,26 +4056,116 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, /* check for success or failure according to the * transmitted bitmap and block-ack bitmap */ - bitmap0 &= agg->bitmap0; - bitmap1 &= agg->bitmap1; + bitmap &= agg->bitmap; /* For each frame attempted in aggregation, * update driver's record of tx frame's status. */ for (i = 0; i < agg->frame_count ; i++) { - int idx = (agg->start_idx + i) & 0xff; - ack = bitmap0 & (1 << i); + ack = bitmap & (1 << i); + successes += !!ack; IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", - ack? "ACK":"NACK", i, idx, agg->start_idx + i); - iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0, - agg->rate_n_flags); + ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, + agg->start_idx + i); + } + + tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status; + tx_status->flags = IEEE80211_TX_STATUS_ACK; + tx_status->flags |= IEEE80211_TX_STATUS_AMPDU; + tx_status->ampdu_ack_map = successes; + tx_status->ampdu_ack_len = agg->frame_count; + iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, + &tx_status->control); + + IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); + + return 0; +} + +/** + * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration + */ +static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, + u16 txq_id) +{ + /* Simply stop the queue, but don't change any configuration; + * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ + iwl_write_prph(priv, + IWL49_SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + +/** + * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + * priv->lock must be held by the caller + */ +static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) +{ + int ret = 0; + if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { + IWL_WARNING("queue number too small: %d, must be > %d\n", + txq_id, IWL_BACK_QUEUE_FIRST_ID); + return -EINVAL; } - IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1); + ret = iwl_grab_nic_access(priv); + if (ret) + return ret; + + iwl4965_tx_queue_stop_scheduler(priv, txq_id); + + iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); + + priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); + priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); + + iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl4965_txq_ctx_deactivate(priv, txq_id); + iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); + + iwl_release_nic_access(priv); return 0; } +int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, + u8 tid, int txq_id) +{ + struct iwl4965_queue *q = &priv->txq[txq_id].q; + u8 *addr = priv->stations[sta_id].sta.sta.addr; + struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; + + switch (priv->stations[sta_id].tid[tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_DELBA: + /* We are reclaiming the last packet of the */ + /* aggregated HW queue */ + if (txq_id == tid_data->agg.txq_id && + q->read_ptr == q->write_ptr) { + u16 ssn = SEQ_TO_SN(tid_data->seq_number); + int tx_fifo = default_tid_to_tx_fifo[tid]; + IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); + iwl4965_tx_queue_agg_disable(priv, txq_id, + ssn, tx_fifo); + tid_data->agg.state = IWL_AGG_OFF; + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); + } + break; + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* We are reclaiming the last packet of the queue */ + if (tid_data->tfds_in_queue == 0) { + IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n"); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); + } + break; + } + return 0; +} + /** * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed * @index -- current index @@ -4285,7 +4182,7 @@ static inline int iwl4965_queue_dec_wrap(int index, int n_bd) * Handles block-acknowledge notification from device, which reports success * of frames sent via aggregation. */ -static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -4293,48 +4190,43 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, int index; struct iwl4965_tx_queue *txq = NULL; struct iwl4965_ht_agg *agg; + DECLARE_MAC_BUF(mac); /* "flow" corresponds to Tx queue */ - u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow); + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); /* "ssn" is start of block-ack Tx window, corresponds to index * (in Tx queue's circular buffer) of first TFD/frame in window */ u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); - if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) { + if (scd_flow >= ARRAY_SIZE(priv->txq)) { IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); return; } - txq = &priv->txq[ba_resp_scd_flow]; + txq = &priv->txq[scd_flow]; agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; /* Find index just before block-ack window */ index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); /* TODO: Need to get this copy more safely - now good for debug */ -/* - { - DECLARE_MAC_BUF(mac); + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " "sta_id = %d\n", agg->wait_for_ba, print_mac(mac, (u8*) &ba_resp->sta_addr_lo32), ba_resp->sta_id); - IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = " + IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " "%d, scd_ssn = %d\n", ba_resp->tid, - ba_resp->ba_seq_ctl, - ba_resp->ba_bitmap1, - ba_resp->ba_bitmap0, + ba_resp->seq_ctl, + (unsigned long long)le64_to_cpu(ba_resp->bitmap), ba_resp->scd_flow, ba_resp->scd_ssn); - IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n", + IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", agg->start_idx, - agg->bitmap1, - agg->bitmap0); - } -*/ + (unsigned long long)agg->bitmap); /* Update driver's record of ACK vs. not for each frame in window */ iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); @@ -4342,29 +4234,23 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, /* Release all TFDs before the SSN, i.e. all TFDs in front of * block-ack window (we assume that they've been successfully * transmitted ... if not, it's too late anyway). */ - if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) - iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index); - -} - - -/** - * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration - */ -static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id) -{ - /* Simply stop the queue, but don't change any configuration; - * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ - iwl4965_write_prph(priv, - KDR_SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); + if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { + int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); + priv->stations[ba_resp->sta_id]. + tid[ba_resp->tid].tfds_in_queue -= freed; + if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) + ieee80211_wake_queue(priv->hw, scd_flow); + iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id, + ba_resp->tid, scd_flow); + } } /** * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue */ -static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid, +static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, u16 txq_id) { u32 tbl_dw_addr; @@ -4376,25 +4262,26 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid, tbl_dw_addr = priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); - tbl_dw = iwl4965_read_targ_mem(priv, tbl_dw_addr); + tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); if (txq_id & 0x1) tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); else tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); - iwl4965_write_targ_mem(priv, tbl_dw_addr, tbl_dw); + iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw); return 0; } + /** * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue * * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID, * i.e. it must be one of the higher queues used for aggregation */ -static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, +static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { @@ -4412,7 +4299,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; @@ -4425,7 +4312,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); /* Set this queue as a chain-building queue */ - iwl4965_set_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id)); + iwl_set_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); /* Place first TFD at index corresponding to start sequence number. * Assumes that ssn_idx is valid (!= 0xFFF) */ @@ -4434,69 +4321,27 @@ static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); /* Set up Tx window size and frame limit for this queue */ - iwl4965_write_targ_mem(priv, + iwl_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); - iwl4965_write_targ_mem(priv, priv->scd_base_addr + + iwl_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); - iwl4965_set_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - iwl4965_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -/** - * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID - */ -static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) -{ - unsigned long flags; - int rc; - - if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { - IWL_WARNING("queue number too small: %d, must be > %d\n", - txq_id, IWL_BACK_QUEUE_FIRST_ID); - return -EINVAL; - } - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - - iwl4965_tx_queue_stop_scheduler(priv, txq_id); - - iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id)); - - priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); - priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); - /* supposes that ssn_idx is valid (!= 0xFFF) */ - iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); - - iwl4965_clear_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl4965_txq_ctx_deactivate(priv, txq_id); - iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -#endif/* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ /** @@ -4513,7 +4358,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, * which requires station table entry to exist). */ -void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) +void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { int i, r; struct iwl4965_link_quality_cmd link_cmd = { @@ -4525,7 +4370,7 @@ void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) * all the way down to 1M in IEEE order, and then spin on 1M */ if (is_ap) r = IWL_RATE_54M_INDEX; - else if (priv->phymode == MODE_IEEE80211A) + else if (priv->band == IEEE80211_BAND_5GHZ) r = IWL_RATE_6M_INDEX; else r = IWL_RATE_1M_INDEX; @@ -4550,24 +4395,25 @@ void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); /* Update the rate scaling for control frame Tx to AP */ - link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID; + link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_setting.bcast_sta_id; - iwl4965_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), - &link_cmd); + iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, + sizeof(link_cmd), &link_cmd, NULL); } #ifdef CONFIG_IWL4965_HT -static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode, - u16 channel, u8 extension_chan_offset) +static u8 iwl4965_is_channel_extension(struct iwl_priv *priv, + enum ieee80211_band band, + u16 channel, u8 extension_chan_offset) { - const struct iwl4965_channel_info *ch_info; + const struct iwl_channel_info *ch_info; - ch_info = iwl4965_get_channel_info(priv, phymode, channel); + ch_info = iwl_get_channel_info(priv, band, channel); if (!is_channel_valid(ch_info)) return 0; - if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) + if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE) return 0; if ((ch_info->fat_extension_channel == extension_chan_offset) || @@ -4577,14 +4423,14 @@ static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode, return 0; } -static u8 iwl4965_is_fat_tx_allowed(struct iwl4965_priv *priv, +static u8 iwl4965_is_fat_tx_allowed(struct iwl_priv *priv, struct ieee80211_ht_info *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; if ((!iwl_ht_conf->is_ht) || (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)) + (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)) return 0; if (sta_ht_inf) { @@ -4593,12 +4439,12 @@ static u8 iwl4965_is_fat_tx_allowed(struct iwl4965_priv *priv, return 0; } - return (iwl4965_is_channel_extension(priv, priv->phymode, + return (iwl4965_is_channel_extension(priv, priv->band, iwl_ht_conf->control_channel, iwl_ht_conf->extension_chan_offset)); } -void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info) +void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) { struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; u32 val; @@ -4629,9 +4475,7 @@ void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info) case IWL_EXT_CHANNEL_OFFSET_BELOW: rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; - case IWL_EXT_CHANNEL_OFFSET_AUTO: - rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; - break; + case IWL_EXT_CHANNEL_OFFSET_NONE: default: rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; break; @@ -4654,7 +4498,7 @@ void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info) return; } -void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index, +void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, struct ieee80211_ht_info *sta_ht_inf) { __le32 sta_flags; @@ -4699,7 +4543,7 @@ void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index, return; } -static void iwl4965_sta_modify_add_ba_tid(struct iwl4965_priv *priv, +static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, int sta_id, int tid, u16 ssn) { unsigned long flags; @@ -4715,7 +4559,7 @@ static void iwl4965_sta_modify_add_ba_tid(struct iwl4965_priv *priv, iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -static void iwl4965_sta_modify_del_ba_tid(struct iwl4965_priv *priv, +static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, int sta_id, int tid) { unsigned long flags; @@ -4730,63 +4574,13 @@ static void iwl4965_sta_modify_del_ba_tid(struct iwl4965_priv *priv, iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 ssn) -{ - struct iwl4965_priv *priv = hw->priv; - int sta_id; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ", - print_mac(mac, addr), tid); - sta_id = iwl4965_hw_find_station(priv, addr); - switch (action) { - case IEEE80211_AMPDU_RX_START: - IWL_DEBUG_HT("start Rx\n"); - iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, ssn); - break; - case IEEE80211_AMPDU_RX_STOP: - IWL_DEBUG_HT("stop Rx\n"); - iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); - break; - default: - IWL_DEBUG_HT("unknown\n"); - return -EINVAL; - break; - } - return 0; -} - -#ifdef CONFIG_IWL4965_HT_AGG - -static const u16 default_tid_to_tx_fifo[] = { - IWL_TX_FIFO_AC1, - IWL_TX_FIFO_AC0, - IWL_TX_FIFO_AC0, - IWL_TX_FIFO_AC1, - IWL_TX_FIFO_AC2, - IWL_TX_FIFO_AC2, - IWL_TX_FIFO_AC3, - IWL_TX_FIFO_AC3, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_NONE, - IWL_TX_FIFO_AC3 -}; - /* * Find first available (lowest unused) Tx Queue, mark it "active". * Called only when finding queue for aggregation. * Should never return anything < 7, because they should already * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). */ -static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv) +static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv) { int txq_id; @@ -4796,70 +4590,78 @@ static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv) return -1; } -int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, - u16 *start_seq_num) +static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da, + u16 tid, u16 *start_seq_num) { - - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; int sta_id; int tx_fifo; int txq_id; int ssn = -1; + int ret = 0; unsigned long flags; struct iwl4965_tid_data *tid_data; DECLARE_MAC_BUF(mac); - /* Determine Tx DMA/FIFO channel for this Traffic ID */ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s" - " tid=%d\n", print_mac(mac, da), tid); + IWL_WARNING("%s on da = %s tid = %d\n", + __func__, print_mac(mac, da), tid); - /* Get index into station table */ sta_id = iwl4965_hw_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) return -ENXIO; - /* Find available Tx queue for aggregation */ + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { + IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n"); + return -ENXIO; + } + txq_id = iwl4965_txq_ctx_activate_free(priv); if (txq_id == -1) return -ENXIO; spin_lock_irqsave(&priv->sta_lock, flags); tid_data = &priv->stations[sta_id].tid[tid]; - - /* Get starting sequence number for 1st frame in block ack window. - * We'll use least signif byte as 1st frame's index into Tx queue. */ ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; spin_unlock_irqrestore(&priv->sta_lock, flags); *start_seq_num = ssn; + ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, + sta_id, tid, ssn); + if (ret) + return ret; - /* Update driver's link quality manager */ - iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE); - - /* Set up and enable aggregation for selected Tx queue and FIFO */ - return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, ssn); + ret = 0; + if (tid_data->tfds_in_queue == 0) { + printk(KERN_ERR "HW queue is empty\n"); + tid_data->agg.state = IWL_AGG_ON; + ieee80211_start_tx_ba_cb_irqsafe(hw, da, tid); + } else { + IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n", + tid_data->tfds_in_queue); + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; + } + return ret; } - -int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, - int generator) +static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da, + u16 tid) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl4965_tid_data *tid_data; - int rc; + int ret, write_ptr, read_ptr; + unsigned long flags; DECLARE_MAC_BUF(mac); if (!da) { - IWL_ERROR("%s: da = NULL\n", __func__); + IWL_ERROR("da = NULL\n"); return -EINVAL; } @@ -4873,31 +4675,82 @@ int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, if (sta_id == IWL_INVALID_STATION) return -ENXIO; + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) + IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n"); + tid_data = &priv->stations[sta_id].tid[tid]; ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; txq_id = tid_data->agg.txq_id; + write_ptr = priv->txq[txq_id].q.write_ptr; + read_ptr = priv->txq[txq_id].q.read_ptr; + + /* The queue is not empty */ + if (write_ptr != read_ptr) { + IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n"); + priv->stations[sta_id].tid[tid].agg.state = + IWL_EMPTYING_HW_QUEUE_DELBA; + return 0; + } - rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); - /* FIXME: need more safe way to handle error condition */ - if (rc) - return rc; + IWL_DEBUG_HT("HW queue empty\n");; + priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid); - iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA); IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n", - print_mac(mac, da), tid); + print_mac(mac, da), tid); return 0; } +int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 *ssn) +{ + struct iwl_priv *priv = hw->priv; + int sta_id; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ", + print_mac(mac, addr), tid); + sta_id = iwl4965_hw_find_station(priv, addr); + switch (action) { + case IEEE80211_AMPDU_RX_START: + IWL_DEBUG_HT("start Rx\n"); + iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, *ssn); + break; + case IEEE80211_AMPDU_RX_STOP: + IWL_DEBUG_HT("stop Rx\n"); + iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); + break; + case IEEE80211_AMPDU_TX_START: + IWL_DEBUG_HT("start Tx\n"); + return iwl4965_mac_ht_tx_agg_start(hw, addr, tid, ssn); + case IEEE80211_AMPDU_TX_STOP: + IWL_DEBUG_HT("stop Tx\n"); + return iwl4965_mac_ht_tx_agg_stop(hw, addr, tid); + default: + IWL_DEBUG_HT("unknown\n"); + return -EINVAL; + break; + } + return 0; +} -#endif /* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ /* Set up 4965-specific Rx frame reply handlers */ -void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv) +void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv) { /* Legacy Rx frames */ - priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx; + priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; /* High-throughput (HT) Rx frames */ priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; @@ -4907,71 +4760,83 @@ void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv) iwl4965_rx_missed_beacon_notif; #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; -#endif /* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ } -void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv) +void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv) { INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work); #ifdef CONFIG_IWL4965_SENSITIVITY INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); #endif -#ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG - INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work); -#endif /* CONFIG_IWL4965_HT_AGG */ -#endif /* CONFIG_IWL4965_HT */ init_timer(&priv->statistics_periodic); priv->statistics_periodic.data = (unsigned long)priv; priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; } -void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv) +void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv) { del_timer_sync(&priv->statistics_periodic); cancel_delayed_work(&priv->init_alive_start); } -struct pci_device_id iwl4965_hw_card_ids[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4229)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4230)}, - {0} +static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { + .enqueue_hcmd = iwl4965_enqueue_hcmd, }; -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv) -{ - u16 count; - int rc; +static struct iwl_lib_ops iwl4965_lib = { + .init_drv = iwl4965_init_drv, + .eeprom_ops = { + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + }, + .radio_kill_sw = iwl4965_radio_kill_sw, +}; - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - rc = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (rc >= 0) { - IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", - count+1); - return rc; - } - } +static struct iwl_ops iwl4965_ops = { + .lib = &iwl4965_lib, + .utils = &iwl4965_hcmd_utils, +}; - return rc; -} +static struct iwl_cfg iwl4965_agn_cfg = { + .name = "4965AGN", + .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl4965_ops, + .mod_params = &iwl4965_mod_params, +}; + +struct pci_device_id iwl4965_hw_card_ids[] = { + {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, + {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, + {0} +}; MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids); + +module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); +module_param_named(disable, iwl4965_mod_params.disable, int, 0444); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); +module_param_named(hwcrypto, iwl4965_mod_params.hw_crypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, + "using hardware crypto engine (default 0 [software])\n"); +module_param_named(debug, iwl4965_mod_params.debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); +module_param_named( + disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); + +module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); +MODULE_PARM_DESC(queues_num, "number of hw queues."); + +/* QoS */ +module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); +module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); + diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 9cb82be0ff8..65e53678270 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -40,9 +40,20 @@ extern struct pci_device_id iwl4965_hw_card_ids[]; #define DRV_NAME "iwl4965" +#include "iwl-rfkill.h" +#include "iwl-eeprom.h" #include "iwl-4965-hw.h" +#include "iwl-csr.h" #include "iwl-prph.h" -#include "iwl-4965-debug.h" +#include "iwl-debug.h" +#include "iwl-led.h" + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL4965_UCODE_API "-1" + /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -57,11 +68,6 @@ extern struct pci_device_id iwl4965_hw_card_ids[]; * averages within an s8's (used in some apps) range of negative values. */ #define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) -/* Module parameters accessible from iwl-*.c */ -extern int iwl4965_param_hwcrypto; -extern int iwl4965_param_queues_num; -extern int iwl4965_param_amsdu_size_8K; - enum iwl4965_antenna { IWL_ANTENNA_DIVERSITY, IWL_ANTENNA_MAIN, @@ -133,7 +139,7 @@ struct iwl4965_tx_info { struct iwl4965_tx_queue { struct iwl4965_queue q; struct iwl4965_tfd_frame *bd; - struct iwl4965_cmd *cmd; + struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; struct iwl4965_tx_info *txb; int need_update; @@ -190,7 +196,7 @@ enum { */ #define IWL4965_MAX_RATE (33) -struct iwl4965_channel_info { +struct iwl_channel_info { struct iwl4965_channel_tgd_info tgd; struct iwl4965_channel_tgh_info tgh; struct iwl4965_eeprom_channel eeprom; /* EEPROM regulatory limit */ @@ -206,7 +212,7 @@ struct iwl4965_channel_info { u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ - u8 phymode; /* MODE_IEEE80211{A,B,G} */ + enum ieee80211_band band; /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -288,8 +294,8 @@ struct iwl4965_frame { #define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) #define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) -#define SEQ_TO_INDEX(x) (x & 0xff) -#define INDEX_TO_SEQ(x) (x & 0xff) +#define SEQ_TO_INDEX(x) ((u8)(x & 0xff)) +#define INDEX_TO_SEQ(x) ((u8)(x & 0xff)) #define SEQ_HUGE_FRAME (0x4000) #define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) @@ -305,15 +311,15 @@ enum { CMD_WANT_SKB = (1 << 2), }; -struct iwl4965_cmd; -struct iwl4965_priv; +struct iwl_cmd; +struct iwl_priv; -struct iwl4965_cmd_meta { - struct iwl4965_cmd_meta *source; +struct iwl_cmd_meta { + struct iwl_cmd_meta *source; union { struct sk_buff *skb; - int (*callback)(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb); + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb); } __attribute__ ((packed)) u; /* The CMD_SIZE_HUGE flag bit indicates that the command @@ -323,15 +329,15 @@ struct iwl4965_cmd_meta { } __attribute__ ((packed)); /** - * struct iwl4965_cmd + * struct iwl_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for a scan command * (which is relatively huge; space is allocated separately). */ -struct iwl4965_cmd { - struct iwl4965_cmd_meta meta; /* driver data */ - struct iwl4965_cmd_header hdr; /* uCode API */ +struct iwl_cmd { + struct iwl_cmd_meta meta; /* driver data */ + struct iwl_cmd_header hdr; /* uCode API */ union { struct iwl4965_addsta_cmd addsta; struct iwl4965_led_cmd led; @@ -351,15 +357,15 @@ struct iwl4965_cmd { } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); -struct iwl4965_host_cmd { +struct iwl_host_cmd { u8 id; u16 len; - struct iwl4965_cmd_meta meta; + struct iwl_cmd_meta meta; const void *data; }; -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \ - sizeof(struct iwl4965_cmd_meta)) +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) /* * RX related structures and functions @@ -408,32 +414,12 @@ struct iwl4965_rx_queue { #define MAX_B_CHANNELS 14 #define MIN_B_CHANNELS 1 -#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ -#define STATUS_INT_ENABLED 1 -#define STATUS_RF_KILL_HW 2 -#define STATUS_RF_KILL_SW 3 -#define STATUS_INIT 4 -#define STATUS_ALIVE 5 -#define STATUS_READY 6 -#define STATUS_TEMPERATURE 7 -#define STATUS_GEO_CONFIGURED 8 -#define STATUS_EXIT_PENDING 9 -#define STATUS_IN_SUSPEND 10 -#define STATUS_STATISTICS 11 -#define STATUS_SCANNING 12 -#define STATUS_SCAN_ABORTING 13 -#define STATUS_SCAN_HW 14 -#define STATUS_POWER_PMI 15 -#define STATUS_FW_ERROR 16 -#define STATUS_CONF_PENDING 17 - #define MAX_TID_COUNT 9 #define IWL_INVALID_RATE 0xFF #define IWL_INVALID_VALUE -1 #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG /** * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack * @txq_id: Tx queue used for Tx attempt @@ -453,25 +439,29 @@ struct iwl4965_ht_agg { u16 frame_count; u16 wait_for_ba; u16 start_idx; - u32 bitmap0; - u32 bitmap1; + u64 bitmap; u32 rate_n_flags; +#define IWL_AGG_OFF 0 +#define IWL_AGG_ON 1 +#define IWL_EMPTYING_HW_QUEUE_ADDBA 2 +#define IWL_EMPTYING_HW_QUEUE_DELBA 3 + u8 state; }; -#endif /* CONFIG_IWL4965_HT_AGG */ + #endif /* CONFIG_IWL4965_HT */ struct iwl4965_tid_data { u16 seq_number; + u16 tfds_in_queue; #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG struct iwl4965_ht_agg agg; -#endif /* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ }; struct iwl4965_hw_key { enum ieee80211_key_alg alg; int keylen; + struct ieee80211_key_conf *conf; u8 key[32]; }; @@ -508,8 +498,6 @@ struct iwl_ht_info { }; #endif /*CONFIG_IWL4965_HT */ -#ifdef CONFIG_IWL4965_QOS - union iwl4965_qos_capabity { struct { u8 edca_count:4; /* bit 0-3 */ @@ -537,7 +525,6 @@ struct iwl4965_qos_info { union iwl4965_qos_capabity qos_cap; struct iwl4965_qosparam_cmd def_qos_parm; }; -#endif /*CONFIG_IWL4965_QOS */ #define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_SLEEP 1 @@ -581,8 +568,8 @@ struct iwl4965_ibss_seq { /** * struct iwl4965_driver_hw_info * @max_txq_num: Max # Tx queues supported - * @ac_queue_count: # Tx queues for EDCA Access Categories (AC) * @tx_cmd_len: Size of Tx command (but not including frame itself) + * @tx_ant_num: Number of TX antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) * @rx_buffer_size: * @max_rxq_log: Log-base-2 of max_rxq_size @@ -593,8 +580,8 @@ struct iwl4965_ibss_seq { */ struct iwl4965_driver_hw_info { u16 max_txq_num; - u16 ac_queue_count; u16 tx_cmd_len; + u16 tx_ant_num; u16 max_rxq_size; u32 rx_buf_size; u32 max_pkt_size; @@ -626,62 +613,50 @@ struct iwl4965_driver_hw_info { * *****************************************************************************/ struct iwl4965_addsta_cmd; -extern int iwl4965_send_add_station(struct iwl4965_priv *priv, +extern int iwl4965_send_add_station(struct iwl_priv *priv, struct iwl4965_addsta_cmd *sta, u8 flags); -extern u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, +extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, void *ht_data); -extern int iwl4965_is_network_packet(struct iwl4965_priv *priv, +extern int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); -extern int iwl4965_power_init_handle(struct iwl4965_priv *priv); -extern int iwl4965_eeprom_init(struct iwl4965_priv *priv); -#ifdef CONFIG_IWL4965_DEBUG -extern void iwl4965_report_frame(struct iwl4965_priv *priv, - struct iwl4965_rx_packet *pkt, - struct ieee80211_hdr *header, int group100); -#else -static inline void iwl4965_report_frame(struct iwl4965_priv *priv, - struct iwl4965_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) {} -#endif -extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv, +extern int iwl4965_power_init_handle(struct iwl_priv *priv); +extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb, void *data, short len, struct ieee80211_rx_status *stats, u16 phy_flags); -extern int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv, +extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header); -extern int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv); -extern void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, +extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv); +extern void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq); extern int iwl4965_calc_db_from_ratio(int sig_ratio); extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl4965_tx_queue_init(struct iwl4965_priv *priv, +extern int iwl4965_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, int count, u32 id); extern void iwl4965_rx_replenish(void *data); -extern void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq); -extern int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len, - const void *data); -extern int __must_check iwl4965_send_cmd(struct iwl4965_priv *priv, - struct iwl4965_host_cmd *cmd); -extern unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv, +extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); -extern int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, +extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q); -extern int iwl4965_send_statistics_request(struct iwl4965_priv *priv); -extern void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb, +extern int iwl4965_send_statistics_request(struct iwl_priv *priv); +extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, u32 decrypt_res, struct ieee80211_rx_status *stats); extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); +int iwl4965_init_geos(struct iwl_priv *priv); +void iwl4965_free_geos(struct iwl_priv *priv); extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; +int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /* * Currently used by iwl-3945-rs... look at restructuring so that it doesn't * call this... todo... fix that. */ -extern u8 iwl4965_sync_station(struct iwl4965_priv *priv, int sta_id, +extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags); /****************************************************************************** @@ -700,36 +675,36 @@ extern u8 iwl4965_sync_station(struct iwl4965_priv *priv, int sta_id, * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ -extern void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv); -extern void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv); -extern void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv); -extern int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv); -extern int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv); -extern int iwl4965_hw_nic_init(struct iwl4965_priv *priv); -extern int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv); -extern void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv); -extern void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv); -extern int iwl4965_hw_nic_reset(struct iwl4965_priv *priv); -extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *tfd, +extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv); +extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); +extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); +extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv); +extern int iwl4965_hw_set_hw_setting(struct iwl_priv *priv); +extern int iwl4965_hw_nic_init(struct iwl_priv *priv); +extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); +extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv); +extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); +extern int iwl4965_hw_nic_reset(struct iwl_priv *priv); +extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len); -extern int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq); -extern int iwl4965_hw_get_temperature(struct iwl4965_priv *priv); -extern int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, +extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); +extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); +extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); -extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, +extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl4965_frame *frame, u8 rate); -extern int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv); -extern void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, +extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); +extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int sta_id, int tx_id); -extern int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv); -extern int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power); -extern void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, +extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); +extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); +extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb); -extern void iwl4965_disable_events(struct iwl4965_priv *priv); -extern int iwl4965_get_temperature(const struct iwl4965_priv *priv); +extern void iwl4965_disable_events(struct iwl_priv *priv); +extern int iwl4965_get_temperature(const struct iwl_priv *priv); /** * iwl4965_hw_find_station - Find station id for a given BSSID @@ -739,54 +714,51 @@ extern int iwl4965_get_temperature(const struct iwl4965_priv *priv); * not yet been merged into a single common layer for managing the * station tables. */ -extern u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *bssid); - -extern int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel); -extern int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index); +extern u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *bssid); -struct iwl4965_priv; +extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); +extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); +extern int iwl4965_queue_space(const struct iwl4965_queue *q); +struct iwl_priv; +extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); /* * Forward declare iwl-4965.c functions for iwl-base.c */ -extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv); - -extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, +extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, u16 byte_cnt); -extern void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, +extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); -extern void iwl4965_set_rxon_chain(struct iwl4965_priv *priv); -extern int iwl4965_alive_notify(struct iwl4965_priv *priv); -extern void iwl4965_update_rate_scaling(struct iwl4965_priv *priv, u8 mode); -extern void iwl4965_chain_noise_reset(struct iwl4965_priv *priv); -extern void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, +extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); +extern int iwl4965_alive_notify(struct iwl_priv *priv); +extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); +extern void iwl4965_chain_noise_reset(struct iwl_priv *priv); +extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force); -extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, - u16 channel, - const struct iwl4965_eeprom_channel *eeprom_ch, - u8 fat_extension_channel); -extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv); +extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); +extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, + u32 rate_n_flags, + struct ieee80211_tx_control *control); #ifdef CONFIG_IWL4965_HT -extern void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, - int mode); -extern void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, - struct iwl_ht_info *ht_info); -extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index, +void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band); +void iwl4965_set_rxon_ht(struct iwl_priv *priv, + struct iwl_ht_info *ht_info); +void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, struct ieee80211_ht_info *sta_ht_inf); -extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, +int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 ssn); -#ifdef CONFIG_IWL4965_HT_AGG -extern int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, - u16 tid, u16 *start_seq_num); -extern int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, - u16 tid, int generator); -extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid); -extern void iwl4965_tl_get_stats(struct iwl4965_priv *priv, - struct ieee80211_hdr *hdr); -#endif /* CONFIG_IWL4965_HT_AGG */ + const u8 *addr, u16 tid, u16 *ssn); +int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, + u8 tid, int txq_id); +#else +static inline void iwl4965_init_ht_hw_capab(struct iwl_priv *priv, + struct ieee80211_ht_info *ht_info, + enum ieee80211_band band) {} + #endif /*CONFIG_IWL4965_HT */ /* Structures, enum, and defines specific to the 4965 */ @@ -798,18 +770,6 @@ struct iwl4965_kw { size_t size; }; -#define TID_QUEUE_CELL_SPACING 50 /*mS */ -#define TID_QUEUE_MAX_SIZE 20 -#define TID_ROUND_VALUE 5 /* mS */ -#define TID_MAX_LOAD_COUNT 8 - -#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) -#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) - -#define TID_ALL_ENABLED 0x7f -#define TID_ALL_SPECIFIED 0xff -#define TID_AGG_TPT_THREHOLD 0x0 - #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 @@ -823,48 +783,17 @@ struct iwl4965_kw { #define IWL_OPERATION_MODE_MIXED 2 #define IWL_OPERATION_MODE_20MHZ 3 -#define IWL_EXT_CHANNEL_OFFSET_AUTO 0 -#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 -#define IWL_EXT_CHANNEL_OFFSET_ 2 -#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 -#define IWL_EXT_CHANNEL_OFFSET_MAX 4 +#define IWL_EXT_CHANNEL_OFFSET_NONE 0 +#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 +#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2 +#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS (3) #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 -struct iwl4965_traffic_load { - unsigned long time_stamp; - u32 packet_count[TID_QUEUE_MAX_SIZE]; - u8 queue_count; - u8 head; - u32 total; -}; - -#ifdef CONFIG_IWL4965_HT_AGG -/** - * struct iwl4965_agg_control - * @requested_ba: bit map of tids requesting aggregation/block-ack - * @granted_ba: bit map of tids granted aggregation/block-ack - */ -struct iwl4965_agg_control { - unsigned long next_retry; - u32 wait_for_agg_status; - u32 tid_retry; - u32 requested_ba; - u32 granted_ba; - u8 auto_agg; - u32 tid_traffic_load_threshold; - u32 ba_timeout; - struct iwl4965_traffic_load traffic_load[TID_MAX_LOAD_COUNT]; -}; -#endif /*CONFIG_IWL4965_HT_AGG */ - struct iwl4965_lq_mngr { -#ifdef CONFIG_IWL4965_HT_AGG - struct iwl4965_agg_control agg_ctrl; -#endif spinlock_t lock; s32 max_window_size; s32 *expected_tpt; @@ -877,7 +806,6 @@ struct iwl4965_lq_mngr { u8 lq_ready; }; - /* Sensitivity and chain noise calibration */ #define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) #define INITIALIZATION_VALUE 0xFFFF @@ -1014,25 +942,26 @@ enum { #endif -struct iwl4965_priv { +struct iwl_priv { /* ieee device used by generic ieee processing code */ struct ieee80211_hw *hw; struct ieee80211_channel *ieee_channels; struct ieee80211_rate *ieee_rates; + struct iwl_cfg *cfg; /* temporary frame storage list */ struct list_head free_frames; int frames_count; - u8 phymode; + enum ieee80211_band band; int alloc_rxb_skb; bool add_radiotap; - void (*rx_handlers[REPLY_MAX])(struct iwl4965_priv *priv, + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb); - const struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ @@ -1044,7 +973,7 @@ struct iwl4965_priv { /* we allocate array of iwl4965_channel_info for NIC's valid channels. * Access via channel # using indirect index array */ - struct iwl4965_channel_info *channel_info; /* channel info array */ + struct iwl_channel_info *channel_info; /* channel info array */ u8 channel_count; /* # of channels */ /* each calibration channel group in the EEPROM has a derived @@ -1104,18 +1033,21 @@ struct iwl4965_priv { * 4965's initialize alive response contains some calibration data. */ struct iwl4965_init_alive_resp card_alive_init; struct iwl4965_alive_resp card_alive; +#ifdef CONFIG_IWLCORE_RFKILL + struct iwl_rfkill_mngr rfkill_mngr; +#endif -#ifdef LED - /* LED related variables */ - struct iwl4965_activity_blink activity; - unsigned long led_packets; - int led_state; +#ifdef CONFIG_IWLWIFI_LEDS + struct iwl4965_led led[IWL_LED_TRG_MAX]; + unsigned long last_blink_time; + u8 last_blink_rate; + u8 allow_blinking; + u64 led_tpt; #endif u16 active_rate; u16 active_rate_basic; - u8 call_post_assoc_from_beacon; u8 assoc_station_added; u8 use_ant_b_for_management_frame; /* Tx antenna selection */ u8 valid_antenna; /* Bit mask of antennas actually connected */ @@ -1150,11 +1082,16 @@ struct iwl4965_priv { u32 scd_base_addr; /* scheduler sram base address */ unsigned long status; - u32 config; int last_rx_rssi; /* From Rx packet statisitics */ int last_rx_noise; /* From beacon statistics */ + /* counts mgmt, ctl, and data packets */ + struct traffic_stats { + u32 cnt; + u64 bytes; + } tx_stats[3], rx_stats[3]; + struct iwl4965_power_mgr power_data; struct iwl4965_notif_statistics statistics; @@ -1177,10 +1114,9 @@ struct iwl4965_priv { struct iwl4965_station_entry stations[IWL_STATION_COUNT]; /* Indication if ieee80211_ops->open has been called */ - int is_open; + u8 is_open; u8 mac80211_registered; - int is_abg; u32 notif_missed_beacons; @@ -1199,13 +1135,12 @@ struct iwl4965_priv { /* eeprom */ struct iwl4965_eeprom eeprom; - int iw_mode; + enum ieee80211_if_types iw_mode; struct sk_buff *ibss_beacon; /* Last Rx'd beacon timestamp */ - u32 timestamp0; - u32 timestamp1; + u64 timestamp; u16 beacon_int; struct iwl4965_driver_hw_info hw_setting; struct ieee80211_vif *vif; @@ -1216,9 +1151,7 @@ struct iwl4965_priv { u16 assoc_capability; u8 ps_mode; -#ifdef CONFIG_IWL4965_QOS struct iwl4965_qos_info qos_data; -#endif /*CONFIG_IWL4965_QOS */ struct workqueue_struct *workqueue; @@ -1253,11 +1186,15 @@ struct iwl4965_priv { u32 pm_state[16]; #endif -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ u32 framecnt_to_us; atomic_t restrict_refcnt; -#endif +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* debugfs */ + struct iwl_debugfs *dbgfs; +#endif /* CONFIG_IWLWIFI_DEBUGFS */ +#endif /* CONFIG_IWLWIFI_DEBUG */ struct work_struct txpower_work; #ifdef CONFIG_IWL4965_SENSITIVITY @@ -1265,59 +1202,53 @@ struct iwl4965_priv { #endif struct work_struct statistics_work; struct timer_list statistics_periodic; +}; /*iwl_priv */ -#ifdef CONFIG_IWL4965_HT_AGG - struct work_struct agg_work; -#endif -}; /*iwl4965_priv */ - -static inline int iwl4965_is_associated(struct iwl4965_priv *priv) +static inline int iwl_is_associated(struct iwl_priv *priv) { return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; } -static inline int is_channel_valid(const struct iwl4965_channel_info *ch_info) +static inline int is_channel_valid(const struct iwl_channel_info *ch_info) { if (ch_info == NULL) return 0; return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; } -static inline int is_channel_narrow(const struct iwl4965_channel_info *ch_info) +static inline int is_channel_narrow(const struct iwl_channel_info *ch_info) { return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; } -static inline int is_channel_radar(const struct iwl4965_channel_info *ch_info) +static inline int is_channel_radar(const struct iwl_channel_info *ch_info) { return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; } -static inline u8 is_channel_a_band(const struct iwl4965_channel_info *ch_info) +static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info) { - return ch_info->phymode == MODE_IEEE80211A; + return ch_info->band == IEEE80211_BAND_5GHZ; } -static inline u8 is_channel_bg_band(const struct iwl4965_channel_info *ch_info) +static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info) { - return ((ch_info->phymode == MODE_IEEE80211B) || - (ch_info->phymode == MODE_IEEE80211G)); + return ch_info->band == IEEE80211_BAND_2GHZ; } -static inline int is_channel_passive(const struct iwl4965_channel_info *ch) +static inline int is_channel_passive(const struct iwl_channel_info *ch) { return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; } -static inline int is_channel_ibss(const struct iwl4965_channel_info *ch) +static inline int is_channel_ibss(const struct iwl_channel_info *ch) { return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -extern const struct iwl4965_channel_info *iwl4965_get_channel_info( - const struct iwl4965_priv *priv, int phymode, u16 channel); +extern const struct iwl_channel_info *iwl_get_channel_info( + const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); -/* Requires full declaration of iwl4965_priv before including */ -#include "iwl-4965-io.h" +/* Requires full declaration of iwl_priv before including */ #endif /* __iwl4965_4965_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c new file mode 100644 index 00000000000..d8a226e68ed --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -0,0 +1,279 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <net/mac80211.h> + +struct iwl_priv; /* FIXME: remove */ +#include "iwl-debug.h" +#include "iwl-eeprom.h" +#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-core.h" +#include "iwl-rfkill.h" + + +MODULE_DESCRIPTION("iwl core"); +MODULE_VERSION(IWLWIFI_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_IWLWIFI_DEBUG +u32 iwl_debug_level; +EXPORT_SYMBOL(iwl_debug_level); +#endif + +/* This function both allocates and initializes hw and priv. */ +struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, + struct ieee80211_ops *hw_ops) +{ + struct iwl_priv *priv; + + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + struct ieee80211_hw *hw = + ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); + if (hw == NULL) { + IWL_ERROR("Can not allocate network device\n"); + goto out; + } + + priv = hw->priv; + priv->hw = hw; + +out: + return hw; +} +EXPORT_SYMBOL(iwl_alloc_all); + +/** + * iwlcore_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ +void iwlcore_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} +EXPORT_SYMBOL(iwlcore_clear_stations_table); + +void iwlcore_reset_qos(struct iwl_priv *priv) +{ + u16 cw_min = 15; + u16 cw_max = 1023; + u8 aifs = 2; + u8 is_legacy = 0; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.qos_active = 0; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + if (!(priv->active_rate & 0xfff0)) { + cw_min = 31; + is_legacy = 1; + } + } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + cw_min = 31; + is_legacy = 1; + } + + if (priv->qos_data.qos_active) + aifs = 3; + + priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; + + if (priv->qos_data.qos_active) { + i = 1; + priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 7; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 2; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(6016); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3008); + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 3; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 4 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16((cw_max + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3264); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(1504); + } else { + for (i = 1; i < 4; i++) { + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + } + } + IWL_DEBUG_QOS("set QoS to default \n"); + + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwlcore_reset_qos); + +/** + * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON + * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz + * @channel: Any channel valid for the requested phymode + + * In addition to setting the staging RXON, priv->phymode is also set. + * + * NOTE: Does not commit to the hardware; it sets appropriate bit fields + * in the staging RXON flag structure based on the phymode + */ +int iwlcore_set_rxon_channel(struct iwl_priv *priv, + enum ieee80211_band band, + u16 channel) +{ + if (!iwl_get_channel_info(priv, band, channel)) { + IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", + channel, band); + return -EINVAL; + } + + if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && + (priv->band == band)) + return 0; + + priv->staging_rxon.channel = cpu_to_le16(channel); + if (band == IEEE80211_BAND_5GHZ) + priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + + priv->band = band; + + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); + + return 0; +} +EXPORT_SYMBOL(iwlcore_set_rxon_channel); + +static void iwlcore_init_hw(struct iwl_priv *priv) +{ + struct ieee80211_hw *hw = priv->hw; + hw->rate_control_algorithm = "iwl-4965-rs"; + + /* Tell mac80211 and its clients (e.g. Wireless Extensions) + * the range of signal quality values that we'll provide. + * Negative values for level/noise indicate that we'll provide dBm. + * For WE, at least, non-0 values here *enable* display of values + * in app (iwconfig). */ + hw->max_rssi = -20; /* signal level, negative indicates dBm */ + hw->max_noise = -20; /* noise level, negative indicates dBm */ + hw->max_signal = 100; /* link quality indication (%) */ + + /* Tell mac80211 our Tx characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + + /* Default value; 4 EDCA QOS priorities */ + hw->queues = 4; +#ifdef CONFIG_IWL4965_HT + /* Enhanced value; more queues, to support 11n aggregation */ + hw->queues = 16; +#endif /* CONFIG_IWL4965_HT */ +} + +int iwl_setup(struct iwl_priv *priv) +{ + int ret = 0; + iwlcore_init_hw(priv); + ret = priv->cfg->ops->lib->init_drv(priv); + return ret; +} +EXPORT_SYMBOL(iwl_setup); + +/* Low level driver call this function to update iwlcore with + * driver status. + */ +int iwlcore_low_level_notify(struct iwl_priv *priv, + enum iwlcore_card_notify notify) +{ + int ret; + switch (notify) { + case IWLCORE_INIT_EVT: + ret = iwl_rfkill_init(priv); + if (ret) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", ret); + break; + case IWLCORE_START_EVT: + break; + case IWLCORE_STOP_EVT: + break; + case IWLCORE_REMOVE_EVT: + iwl_rfkill_unregister(priv); + break; + } + + return 0; +} +EXPORT_SYMBOL(iwlcore_low_level_notify); + diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h new file mode 100644 index 00000000000..6d82376f43f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -0,0 +1,218 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_core_h__ +#define __iwl_core_h__ + +/************************ + * forward declarations * + ************************/ +struct iwl_host_cmd; +struct iwl_cmd; + + +#define IWLWIFI_VERSION "1.2.26k" +#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" + +#define IWL_PCI_DEVICE(dev, subdev, cfg) \ + .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = (subdev), \ + .driver_data = (kernel_ulong_t)&(cfg) + +#define IWL_SKU_G 0x1 +#define IWL_SKU_A 0x2 +#define IWL_SKU_N 0x8 + +struct iwl_hcmd_utils_ops { + int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +}; + +struct iwl_lib_ops { + /* iwlwifi driver (priv) init */ + int (*init_drv)(struct iwl_priv *priv); + /* eeprom operations (as defined in iwl-eeprom.h) */ + struct iwl_eeprom_ops eeprom_ops; + void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio); +}; + +struct iwl_ops { + const struct iwl_lib_ops *lib; + const struct iwl_hcmd_utils_ops *utils; +}; + +struct iwl_mod_params { + int disable; /* def: 0 = enable radio */ + int hw_crypto; /* def: 0 = using software encryption */ + int debug; /* def: 0 = minimal debug log messages */ + int disable_hw_scan; /* def: 0 = use h/w scan */ + int num_of_queues; /* def: HW dependent */ + int enable_qos; /* def: 1 = use quality of service */ + int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ + int antenna; /* def: 0 = both antennas (use diversity) */ +}; + +struct iwl_cfg { + const char *name; + const char *fw_name; + unsigned int sku; + const struct iwl_ops *ops; + const struct iwl_mod_params *mod_params; +}; + +/*************************** + * L i b * + ***************************/ + +struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, + struct ieee80211_ops *hw_ops); + +void iwlcore_clear_stations_table(struct iwl_priv *priv); +void iwlcore_reset_qos(struct iwl_priv *priv); +int iwlcore_set_rxon_channel(struct iwl_priv *priv, + enum ieee80211_band band, + u16 channel); + +int iwl_setup(struct iwl_priv *priv); + +/***************************************************** + * S e n d i n g H o s t C o m m a n d s * + *****************************************************/ + +const char *get_cmd_string(u8 cmd); +int __must_check iwl_send_cmd_sync(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, + u16 len, const void *data); +int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, + const void *data, + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb)); +/*************** DRIVER STATUS FUNCTIONS *****/ + +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ +#define STATUS_INT_ENABLED 2 +#define STATUS_RF_KILL_HW 3 +#define STATUS_RF_KILL_SW 4 +#define STATUS_INIT 5 +#define STATUS_ALIVE 6 +#define STATUS_READY 7 +#define STATUS_TEMPERATURE 8 +#define STATUS_GEO_CONFIGURED 9 +#define STATUS_EXIT_PENDING 10 +#define STATUS_IN_SUSPEND 11 +#define STATUS_STATISTICS 12 +#define STATUS_SCANNING 13 +#define STATUS_SCAN_ABORTING 14 +#define STATUS_SCAN_HW 15 +#define STATUS_POWER_PMI 16 +#define STATUS_FW_ERROR 17 +#define STATUS_CONF_PENDING 18 + + +static inline int iwl_is_ready(struct iwl_priv *priv) +{ + /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are + * set but EXIT_PENDING is not */ + return test_bit(STATUS_READY, &priv->status) && + test_bit(STATUS_GEO_CONFIGURED, &priv->status) && + !test_bit(STATUS_EXIT_PENDING, &priv->status); +} + +static inline int iwl_is_alive(struct iwl_priv *priv) +{ + return test_bit(STATUS_ALIVE, &priv->status); +} + +static inline int iwl_is_init(struct iwl_priv *priv) +{ + return test_bit(STATUS_INIT, &priv->status); +} + +static inline int iwl_is_rfkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +static inline int iwl_is_ready_rf(struct iwl_priv *priv) +{ + + if (iwl_is_rfkill(priv)) + return 0; + + return iwl_is_ready(priv); +} + + +enum iwlcore_card_notify { + IWLCORE_INIT_EVT = 0, + IWLCORE_START_EVT = 1, + IWLCORE_STOP_EVT = 2, + IWLCORE_REMOVE_EVT = 3, +}; + +int iwlcore_low_level_notify(struct iwl_priv *priv, + enum iwlcore_card_notify notify); +#endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h new file mode 100644 index 00000000000..12725796ea5 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -0,0 +1,265 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +/*=== CSR (control and status registers) ===*/ +#define CSR_BASE (0x000) + +#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ +#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ +#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ +#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ +#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ +#define CSR_GP_CNTRL (CSR_BASE+0x024) + +/* + * Hardware revision info + * Bit fields: + * 31-8: Reserved + * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 + * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D + * 1-0: "Dash" value, as in A-1, etc. + * + * NOTE: Revision step affects calculation of CCK txpower for 4965. + */ +#define CSR_HW_REV (CSR_BASE+0x028) + +/* EEPROM reads */ +#define CSR_EEPROM_REG (CSR_BASE+0x02c) +#define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GP_UCODE (CSR_BASE+0x044) +#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) +#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) +#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) +#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_LED_REG (CSR_BASE+0x094) + +/* Analog phase-lock-loop configuration (3945 only) + * Set bit 24. */ +#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) +/* + * Indicates hardware rev, to determine CCK backoff for txpower calculation. + * Bit fields: + * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step + */ +#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) + +/* Bits for CSR_HW_IF_CONFIG_REG */ +#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) +#define CSR49_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) +#define CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) +#define CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) + +#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) +#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) +#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) +#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) +#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) +#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) + +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) + +/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), + * acknowledged (reset) by host writing "1" to flagged bits. */ +#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ +#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ +#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ +#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ +#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ +#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ +#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ +#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ +#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ + +#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ + CSR_INT_BIT_HW_ERR | \ + CSR_INT_BIT_FH_TX | \ + CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_RF_KILL | \ + CSR_INT_BIT_SW_RX | \ + CSR_INT_BIT_WAKEUP | \ + CSR_INT_BIT_ALIVE) + +/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ +#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ +#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ +#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ +#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ +#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ +#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ +#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ +#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ + +#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR39_FH_INT_BIT_RX_CHNL2 | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) + + +#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ + CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) + +#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) + +#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) + + +/* RESET */ +#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) +#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) +#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) +#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) +#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) + +/* GP (general purpose) CONTROL */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) +#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) +#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) +#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) + +#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) + +#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) +#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) + + +/* EEPROM REG */ +#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) +#define CSR_EEPROM_REG_BIT_CMD (0x00000002) + +/* EEPROM GP */ +#define CSR_EEPROM_GP_VALID_MSK (0x00000006) +#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) +#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) + +/* UCODE DRV GP */ +#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) +#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) +#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) +#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) + +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER + +/* GI Chicken Bits */ +#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) +#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) + +/* LED */ +#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) +#define CSR_LED_REG_TRUN_ON (0x78) +#define CSR_LED_REG_TRUN_OFF (0x38) + +/*=== HBUS (Host-side Bus) ===*/ +#define HBUS_BASE (0x400) +/* + * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM + * structures, error log, event log, verifying uCode load). + * First write to address register, then read from or write to data register + * to complete the job. Once the address register is set up, accesses to + * data registers auto-increment the address by one dword. + * Bit usage for address registers (read or write): + * 0-31: memory address within device + */ +#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) +#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) +#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) +#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) + +/* + * Registers for accessing device's internal peripheral registers + * (e.g. SCD, BSM, etc.). First write to address register, + * then read from or write to data register to complete the job. + * Bit usage for address registers (read or write): + * 0-15: register address (offset) within device + * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) + */ +#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) +#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) +#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) +#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) + +/* + * Per-Tx-queue write pointer (index, really!) (3945 and 4965). + * Indicates index to next TFD that driver will fill (1 past latest filled). + * Bit usage: + * 0-7: queue write index + * 11-8: queue selector + */ +#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) +#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) + +#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) + + + diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 36696bbf170..c60724c21db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -26,20 +26,49 @@ * *****************************************************************************/ -#ifndef __iwl4965_debug_h__ -#define __iwl4965_debug_h__ +#ifndef __iwl_debug_h__ +#define __iwl_debug_h__ -#ifdef CONFIG_IWL4965_DEBUG -extern u32 iwl4965_debug_level; +#ifdef CONFIG_IWLWIFI_DEBUG +extern u32 iwl_debug_level; #define IWL_DEBUG(level, fmt, args...) \ -do { if (iwl4965_debug_level & (level)) \ +do { if (iwl_debug_level & (level)) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ -do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \ +do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + +static inline void iwl_print_hex_dump(int level, void *p, u32 len) +{ + if (!(iwl_debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +struct iwl_debugfs { + const char *name; + struct dentry *dir_drv; + struct dentry *dir_data; + struct dir_data_files{ + struct dentry *file_sram; + struct dentry *file_stations; + struct dentry *file_rx_statistics; + struct dentry *file_tx_statistics; + } dbgfs_data_files; + u32 sram_offset; + u32 sram_len; +}; + +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); +void iwl_dbgfs_unregister(struct iwl_priv *priv); +#endif + #else static inline void IWL_DEBUG(int level, const char *fmt, ...) { @@ -47,7 +76,22 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...) static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) { } -#endif /* CONFIG_IWL4965_DEBUG */ +static inline void iwl_print_hex_dump(int level, void *p, u32 len) +{ +} +#endif /* CONFIG_IWLWIFI_DEBUG */ + + + +#ifndef CONFIG_IWLWIFI_DEBUGFS +static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) +{ + return 0; +} +static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) +{ +} +#endif /* CONFIG_IWLWIFI_DEBUGFS */ /* * To use the debug system; @@ -68,10 +112,10 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) * * % cat /proc/net/iwl/debug_level * - * you simply need to add your entry to the iwl4965_debug_levels array. + * you simply need to add your entry to the iwl_debug_levels array. * * If you do not see debug_level in /proc/net/iwl then you do not have - * CONFIG_IWL4965_DEBUG defined in your kernel configuration + * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration * */ @@ -143,6 +187,7 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) +#define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c new file mode 100644 index 00000000000..23632e54aab --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -0,0 +1,320 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/debugfs.h> + +#include <linux/ieee80211.h> +#include <net/mac80211.h> + + +#include "iwl-4965.h" +#include "iwl-debug.h" +#include "iwl-core.h" +#include "iwl-io.h" + + +/* create and remove of files */ +#define DEBUGFS_ADD_DIR(name, parent) do { \ + dbgfs->dir_##name = debugfs_create_dir(#name, parent); \ + if (!(dbgfs->dir_##name)) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_FILE(name, parent) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ + &iwl_dbgfs_##name##_ops); \ + if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ + goto err; \ +} while (0) + +#define DEBUGFS_REMOVE(name) do { \ + debugfs_remove(name); \ + name = NULL; \ +} while (0); + +/* file operation */ +#define DEBUGFS_READ_FUNC(name) \ +static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos); + +#define DEBUGFS_WRITE_FUNC(name) \ +static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos); + + +static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define DEBUGFS_READ_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .read = iwl_dbgfs_##name##_read, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + +#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .read = iwl_dbgfs_##name##_read, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + + +static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[256]; + int pos = 0; + + pos += sprintf(buf+pos, "mgmt: %u\n", priv->tx_stats[0].cnt); + pos += sprintf(buf+pos, "ctrl: %u\n", priv->tx_stats[1].cnt); + pos += sprintf(buf+pos, "data: %u\n", priv->tx_stats[2].cnt); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[256]; + int pos = 0; + + pos += sprintf(buf+pos, "mgmt: %u\n", priv->rx_stats[0].cnt); + pos += sprintf(buf+pos, "ctrl: %u\n", priv->rx_stats[1].cnt); + pos += sprintf(buf+pos, "data: %u\n", priv->rx_stats[2].cnt); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +#define BYTE1_MASK 0x000000ff; +#define BYTE2_MASK 0x0000ffff; +#define BYTE3_MASK 0x00ffffff; +static ssize_t iwl_dbgfs_sram_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + u32 val; + char buf[1024]; + ssize_t ret; + int i; + int pos = 0; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + + printk(KERN_DEBUG "offset is: 0x%x\tlen is: 0x%x\n", + priv->dbgfs->sram_offset, priv->dbgfs->sram_len); + + iwl_grab_nic_access(priv); + for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { + val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ + priv->dbgfs->sram_len - i); + if (i < 4) { + switch (i) { + case 1: + val &= BYTE1_MASK; + break; + case 2: + val &= BYTE2_MASK; + break; + case 3: + val &= BYTE3_MASK; + break; + } + } + pos += sprintf(buf+pos, "0x%08x ", val); + } + pos += sprintf(buf+pos, "\n"); + iwl_release_nic_access(priv); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + +static ssize_t iwl_dbgfs_sram_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[64]; + int buf_size; + u32 offset, len; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%x,%x", &offset, &len) == 2) { + priv->dbgfs->sram_offset = offset; + priv->dbgfs->sram_len = len; + } else { + priv->dbgfs->sram_offset = 0; + priv->dbgfs->sram_len = 0; + } + + return count; +} + +static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl4965_station_entry *station; + int max_sta = priv->hw_setting.max_stations; + char *buf; + int i, j, pos = 0; + ssize_t ret; + /* Add 30 for initial string */ + const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations); + DECLARE_MAC_BUF(mac); + + buf = kmalloc(bufsz, GFP_KERNEL); + if(!buf) + return -ENOMEM; + + pos += sprintf(buf+pos, "num of stations: %d\n\n", + priv->num_stations); + + for (i = 0; i < max_sta; i++) { + station = &priv->stations[i]; + if (station->used) { + pos += sprintf(buf+pos, "station %d:\ngeneral data:\n", + i+1); + print_mac(mac, station->sta.sta.addr); + pos += sprintf(buf+pos, "id: %u\n", + station->sta.sta.sta_id); + pos += sprintf(buf+pos, "mode: %u\n", + station->sta.mode); + pos += sprintf(buf+pos, "flags: 0x%x\n", + station->sta.station_flags_msk); + pos += sprintf(buf+pos, "ps_status: %u\n", + station->ps_status); + + pos += sprintf(buf+pos, "tid data:\n"); + + pos += sprintf(buf+pos, "seq_num\t\ttxq_id\t"); + pos += sprintf(buf+pos, "frame_count\twait_for_ba\t"); + pos += sprintf(buf+pos, "start_idx\tbitmap0\t"); + pos += sprintf(buf+pos, "bitmap1\trate_n_flags\n"); + + for (j = 0; j < MAX_TID_COUNT; j++) { + pos += sprintf(buf+pos, "[%d]:\t\t%u\t", + j, station->tid[j].seq_number); + pos += sprintf(buf+pos, "%u\t\t%u\t\t%u\t\t", + station->tid[j].agg.txq_id, + station->tid[j].agg.frame_count, + station->tid[j].agg.wait_for_ba); + pos += sprintf(buf+pos, "%u\t%llu\t%u\n", + station->tid[j].agg.start_idx, + (unsigned long long)station->tid[j].agg.bitmap, + station->tid[j].agg.rate_n_flags); + } + pos += sprintf(buf+pos, "\n"); + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + +DEBUGFS_READ_WRITE_FILE_OPS(sram); +DEBUGFS_READ_FILE_OPS(stations); +DEBUGFS_READ_FILE_OPS(rx_statistics); +DEBUGFS_READ_FILE_OPS(tx_statistics); + +/* + * Create the debugfs files and directories + * + */ +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) +{ + struct iwl_debugfs *dbgfs; + + dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); + if (!dbgfs) { + goto err; + } + + priv->dbgfs = dbgfs; + dbgfs->name = name; + dbgfs->dir_drv = debugfs_create_dir(name, NULL); + if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){ + goto err; + } + + DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_FILE(sram, data); + DEBUGFS_ADD_FILE(stations, data); + DEBUGFS_ADD_FILE(rx_statistics, data); + DEBUGFS_ADD_FILE(tx_statistics, data); + + return 0; + +err: + IWL_ERROR("Can't open the debugfs directory\n"); + iwl_dbgfs_unregister(priv); + return -ENOENT; +} +EXPORT_SYMBOL(iwl_dbgfs_register); + +/** + * Remove the debugfs files and directories + * + */ +void iwl_dbgfs_unregister(struct iwl_priv *priv) +{ + if (!(priv->dbgfs)) + return; + + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); + DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dir_drv); + kfree(priv->dbgfs); + priv->dbgfs = NULL; +} +EXPORT_SYMBOL(iwl_dbgfs_unregister); + + diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c new file mode 100644 index 00000000000..a07d5dcb7ab --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -0,0 +1,561 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> + +#include <net/mac80211.h> + +#include "iwl-4965-commands.h" +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-debug.h" +#include "iwl-eeprom.h" +#include "iwl-io.h" + +/************************** EEPROM BANDS **************************** + * + * The iwl_eeprom_band definitions below provide the mapping from the + * EEPROM contents to the specific channel number supported for each + * band. + * + * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * definition below maps to physical channel 42 in the 5.2GHz spectrum. + * The specific geography and calibration information for that channel + * is contained in the eeprom map itself. + * + * During init, we copy the eeprom information and channel map + * information into priv->channel_info_24/52 and priv->channel_map_24/52 + * + * channel_map_24/52 provides the index in the channel_info array for a + * given channel. We have to have two separate maps as there is channel + * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and + * band_2 + * + * A value of 0xff stored in the channel_map indicates that the channel + * is not supported by the hardware at all. + * + * A value of 0xfe in the channel_map indicates that the channel is not + * valid for Tx with the current hardware. This means that + * while the system can tune and receive on a given channel, it may not + * be able to associate or transmit any frames on that + * channel. There is no corresponding channel information for that + * entry. + * + *********************************************************************/ + +/* 2.4 GHz */ +const u8 iwl_eeprom_band_1[14] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +/* 5.2 GHz bands */ +static const u8 iwl_eeprom_band_2[] = { /* 4915-5080MHz */ + 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 +}; + +static const u8 iwl_eeprom_band_3[] = { /* 5170-5320MHz */ + 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 +}; + +static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ + 145, 149, 153, 157, 161, 165 +}; + +static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ + 1, 2, 3, 4, 5, 6, 7 +}; + +static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ + 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 +}; + +/****************************************************************************** + * + * EEPROM related functions + * +******************************************************************************/ + +int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) +{ + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); + return -ENOENT; + } + return 0; +} +EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); + +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int ret; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + /* Request semaphore */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (ret >= 0) { + IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", + count+1); + return ret; + } + } + + return ret; +} +EXPORT_SYMBOL(iwlcore_eeprom_acquire_semaphore); + +void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + +} +EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); + + +/** + * iwl_eeprom_init - read EEPROM contents + * + * Load the EEPROM contents from adapter into priv->eeprom + * + * NOTE: This routine uses the non-debug IO access functions. + */ +int iwl_eeprom_init(struct iwl_priv *priv) +{ + u16 *e = (u16 *)&priv->eeprom; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + u32 r; + int sz = sizeof(priv->eeprom); + int ret; + int i; + u16 addr; + + /* The EEPROM structure has several padding buffers within it + * and when adding new EEPROM maps is subject to programmer errors + * which may be very difficult to identify without explicitly + * checking the resulting size of the eeprom map. */ + BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + + if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); + return -ENOENT; + } + + /* Make sure driver (instead of uCode) is allowed to read EEPROM */ + ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); + if (ret < 0) { + IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); + return -ENOENT; + } + + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + + for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; + i += IWL_EEPROM_ACCESS_DELAY) { + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + if (r & CSR_EEPROM_REG_READ_VALID_MSK) + break; + udelay(IWL_EEPROM_ACCESS_DELAY); + } + + if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + IWL_ERROR("Time out reading EEPROM[%d]", addr); + ret = -ETIMEDOUT; + goto done; + } + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + } + ret = 0; + +done: + priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); + return ret; +} +EXPORT_SYMBOL(iwl_eeprom_init); + + +void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) +{ + memcpy(mac, priv->eeprom.mac_address, 6); +} +EXPORT_SYMBOL(iwl_eeprom_get_mac); + +static void iwl_init_band_reference(const struct iwl_priv *priv, + int band, + int *eeprom_ch_count, + const struct iwl4965_eeprom_channel + **eeprom_ch_info, + const u8 **eeprom_ch_index) +{ + switch (band) { + case 1: /* 2.4GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_info = priv->eeprom.band_1_channels; + *eeprom_ch_index = iwl_eeprom_band_1; + break; + case 2: /* 4.9GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + *eeprom_ch_info = priv->eeprom.band_2_channels; + *eeprom_ch_index = iwl_eeprom_band_2; + break; + case 3: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_info = priv->eeprom.band_3_channels; + *eeprom_ch_index = iwl_eeprom_band_3; + break; + case 4: /* 5.5GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + *eeprom_ch_info = priv->eeprom.band_4_channels; + *eeprom_ch_index = iwl_eeprom_band_4; + break; + case 5: /* 5.7GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + *eeprom_ch_info = priv->eeprom.band_5_channels; + *eeprom_ch_index = iwl_eeprom_band_5; + break; + case 6: /* 2.4GHz FAT channels */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); + *eeprom_ch_info = priv->eeprom.band_24_channels; + *eeprom_ch_index = iwl_eeprom_band_6; + break; + case 7: /* 5 GHz FAT channels */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); + *eeprom_ch_info = priv->eeprom.band_52_channels; + *eeprom_ch_index = iwl_eeprom_band_7; + break; + default: + BUG(); + return; + } +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +/** + * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. + * + * Does not set up a command, or touch hardware. + */ +static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, + enum ieee80211_band band, u16 channel, + const struct iwl4965_eeprom_channel *eeprom_ch, + u8 fat_extension_channel) +{ + struct iwl_channel_info *ch_info; + + ch_info = (struct iwl_channel_info *) + iwl_get_channel_info(priv, band, channel); + + if (!is_channel_valid(ch_info)) + return -1; + + IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch->flags, + eeprom_ch->max_power_avg, + ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? + "" : "not "); + + ch_info->fat_eeprom = *eeprom_ch; + ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; + ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; + ch_info->fat_min_power = 0; + ch_info->fat_scan_power = eeprom_ch->max_power_avg; + ch_info->fat_flags = eeprom_ch->flags; + ch_info->fat_extension_channel = fat_extension_channel; + + return 0; +} + +#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +/** + * iwl_init_channel_map - Set up driver's info for all possible channels + */ +int iwl_init_channel_map(struct iwl_priv *priv) +{ + int eeprom_ch_count = 0; + const u8 *eeprom_ch_index = NULL; + const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL; + int band, ch; + struct iwl_channel_info *ch_info; + + if (priv->channel_count) { + IWL_DEBUG_INFO("Channel map already initialized.\n"); + return 0; + } + + if (priv->eeprom.version < 0x2f) { + IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", + priv->eeprom.version); + return -EINVAL; + } + + IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); + + priv->channel_count = + ARRAY_SIZE(iwl_eeprom_band_1) + + ARRAY_SIZE(iwl_eeprom_band_2) + + ARRAY_SIZE(iwl_eeprom_band_3) + + ARRAY_SIZE(iwl_eeprom_band_4) + + ARRAY_SIZE(iwl_eeprom_band_5); + + IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); + + priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_count, GFP_KERNEL); + if (!priv->channel_info) { + IWL_ERROR("Could not allocate channel_info\n"); + priv->channel_count = 0; + return -ENOMEM; + } + + ch_info = priv->channel_info; + + /* Loop through the 5 EEPROM bands adding them in order to the + * channel map we maintain (that contains additional information than + * what just in the EEPROM) */ + for (band = 1; band <= 5; band++) { + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + ch_info->channel = eeprom_ch_index[ch]; + ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ; + + /* permanently store EEPROM's channel regulatory flags + * and max power in channel info database. */ + ch_info->eeprom = eeprom_ch_info[ch]; + + /* Copy the run-time flags so they are there even on + * invalid channels */ + ch_info->flags = eeprom_ch_info[ch].flags; + + if (!(is_channel_valid(ch_info))) { + IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " + "No traffic\n", + ch_info->channel, + ch_info->flags, + is_channel_a_band(ch_info) ? + "5.2" : "2.4"); + ch_info++; + continue; + } + + /* Initialize regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + eeprom_ch_info[ch].max_power_avg; + ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; + ch_info->min_power = 0; + + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT_I(VALID), + CHECK_AND_PRINT_I(IBSS), + CHECK_AND_PRINT_I(ACTIVE), + CHECK_AND_PRINT_I(RADAR), + CHECK_AND_PRINT_I(WIDE), + CHECK_AND_PRINT_I(NARROW), + CHECK_AND_PRINT_I(DFS), + eeprom_ch_info[ch].flags, + eeprom_ch_info[ch].max_power_avg, + ((eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_RADAR)) + ? "" : "not "); + + /* Set the user_txpower_limit to the highest power + * supported by any channel */ + if (eeprom_ch_info[ch].max_power_avg > + priv->user_txpower_limit) + priv->user_txpower_limit = + eeprom_ch_info[ch].max_power_avg; + + ch_info++; + } + } + + /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ + for (band = 6; band <= 7; band++) { + enum ieee80211_band ieeeband; + u8 fat_extension_chan; + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ + ieeeband = + (band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + + if ((band == 6) && + ((eeprom_ch_index[ch] == 5) || + (eeprom_ch_index[ch] == 6) || + (eeprom_ch_index[ch] == 7))) + fat_extension_chan = HT_IE_EXT_CHANNEL_MAX; + else + fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; + + /* Set up driver's info for lower half */ + iwl4965_set_fat_chan_info(priv, ieeeband, + eeprom_ch_index[ch], + &(eeprom_ch_info[ch]), + fat_extension_chan); + + /* Set up driver's info for upper half */ + iwl4965_set_fat_chan_info(priv, ieeeband, + (eeprom_ch_index[ch] + 4), + &(eeprom_ch_info[ch]), + HT_IE_EXT_CHANNEL_BELOW); + } + } + + return 0; +} +EXPORT_SYMBOL(iwl_init_channel_map); + +/* + * iwl_free_channel_map - undo allocations in iwl4965_init_channel_map + */ +void iwl_free_channel_map(struct iwl_priv *priv) +{ + kfree(priv->channel_info); + priv->channel_count = 0; +} +EXPORT_SYMBOL(iwl_free_channel_map); + +/** + * iwl_get_channel_info - Find driver's private channel info + * + * Based on band and channel number. + */ +const struct iwl_channel_info *iwl_get_channel_info( + const struct iwl_priv *priv, + enum ieee80211_band band, u16 channel) +{ + int i; + + switch (band) { + case IEEE80211_BAND_5GHZ: + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel == channel) + return &priv->channel_info[i]; + } + break; + case IEEE80211_BAND_2GHZ: + if (channel >= 1 && channel <= 14) + return &priv->channel_info[channel - 1]; + break; + default: + BUG(); + } + + return NULL; +} +EXPORT_SYMBOL(iwl_get_channel_info); + diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h new file mode 100644 index 00000000000..bd0a042ca77 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -0,0 +1,375 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_eeprom_h__ +#define __iwl_eeprom_h__ + +struct iwl_priv; + +/* + * EEPROM access time values: + * + * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, + * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit + * CSR_EEPROM_REG_BIT_CMD (0x2). + * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). + * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. + * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. + */ +#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ +#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ + +#define IWL_EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ + + +/* + * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags. + * + * IBSS and/or AP operation is allowed *only* on those channels with + * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because + * RADAR detection is not supported by the 4965 driver, but is a + * requirement for establishing a new network for legal operation on channels + * requiring RADAR detection or restricting ACTIVE scanning. + * + * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. + * It only indicates that 20 MHz channel use is supported; FAT channel + * usage is indicated by a separate set of regulatory flags for each + * FAT channel pair. + * + * NOTE: Using a channel inappropriately will result in a uCode error! + */ +#define IWL_NUM_TX_CALIB_GROUPS 5 +enum { + EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ + EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ + /* Bit 2 Reserved */ + EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ + EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ + EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ + EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ +}; + +/* SKU Capabilities */ +#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) +#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) + +/* *regulatory* channel data format in eeprom, one for each channel. + * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ +struct iwl4965_eeprom_channel { + u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ + s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ +} __attribute__ ((packed)); + +/* 4965 has two radio transmitters (and 3 radio receivers) */ +#define EEPROM_TX_POWER_TX_CHAINS (2) + +/* 4965 has room for up to 8 sets of txpower calibration data */ +#define EEPROM_TX_POWER_BANDS (8) + +/* 4965 factory calibration measures txpower gain settings for + * each of 3 target output levels */ +#define EEPROM_TX_POWER_MEASUREMENTS (3) + +#define EEPROM_4965_TX_POWER_VERSION (2) + +/* 4965 driver does not work with txpower calibration version < 5. + * Look for this in calib_version member of struct iwl4965_eeprom. */ +#define EEPROM_TX_POWER_VERSION_NEW (5) + +/* 2.4 GHz */ +extern const u8 iwl_eeprom_band_1[14]; + +/* + * 4965 factory calibration data for one txpower level, on one channel, + * measured on one of the 2 tx chains (radio transmitter and associated + * antenna). EEPROM contains: + * + * 1) Temperature (degrees Celsius) of device when measurement was made. + * + * 2) Gain table index used to achieve the target measurement power. + * This refers to the "well-known" gain tables (see iwl-4965-hw.h). + * + * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). + * + * 4) RF power amplifier detector level measurement (not used). + */ +struct iwl4965_eeprom_calib_measure { + u8 temperature; /* Device temperature (Celsius) */ + u8 gain_idx; /* Index into gain table */ + u8 actual_pow; /* Measured RF output power, half-dBm */ + s8 pa_det; /* Power amp detector level (not used) */ +} __attribute__ ((packed)); + + +/* + * 4965 measurement set for one channel. EEPROM contains: + * + * 1) Channel number measured + * + * 2) Measurements for each of 3 power levels for each of 2 radio transmitters + * (a.k.a. "tx chains") (6 measurements altogether) + */ +struct iwl4965_eeprom_calib_ch_info { + u8 ch_num; + struct iwl4965_eeprom_calib_measure + measurements[EEPROM_TX_POWER_TX_CHAINS] + [EEPROM_TX_POWER_MEASUREMENTS]; +} __attribute__ ((packed)); + +/* + * 4965 txpower subband info. + * + * For each frequency subband, EEPROM contains the following: + * + * 1) First and last channels within range of the subband. "0" values + * indicate that this sample set is not being used. + * + * 2) Sample measurement sets for 2 channels close to the range endpoints. + */ +struct iwl4965_eeprom_calib_subband_info { + u8 ch_from; /* channel number of lowest channel in subband */ + u8 ch_to; /* channel number of highest channel in subband */ + struct iwl4965_eeprom_calib_ch_info ch1; + struct iwl4965_eeprom_calib_ch_info ch2; +} __attribute__ ((packed)); + + +/* + * 4965 txpower calibration info. EEPROM contains: + * + * 1) Factory-measured saturation power levels (maximum levels at which + * tx power amplifier can output a signal without too much distortion). + * There is one level for 2.4 GHz band and one for 5 GHz band. These + * values apply to all channels within each of the bands. + * + * 2) Factory-measured power supply voltage level. This is assumed to be + * constant (i.e. same value applies to all channels/bands) while the + * factory measurements are being made. + * + * 3) Up to 8 sets of factory-measured txpower calibration values. + * These are for different frequency ranges, since txpower gain + * characteristics of the analog radio circuitry vary with frequency. + * + * Not all sets need to be filled with data; + * struct iwl4965_eeprom_calib_subband_info contains range of channels + * (0 if unused) for each set of data. + */ +struct iwl4965_eeprom_calib_info { + u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ + u8 saturation_power52; /* half-dBm */ + s16 voltage; /* signed */ + struct iwl4965_eeprom_calib_subband_info + band_info[EEPROM_TX_POWER_BANDS]; +} __attribute__ ((packed)); + + + +/* + * 4965 EEPROM map + */ +struct iwl4965_eeprom { + u8 reserved0[16]; + u16 device_id; /* abs.ofs: 16 */ + u8 reserved1[2]; + u16 pmc; /* abs.ofs: 20 */ + u8 reserved2[20]; + u8 mac_address[6]; /* abs.ofs: 42 */ + u8 reserved3[58]; + u16 board_revision; /* abs.ofs: 106 */ + u8 reserved4[11]; + u8 board_pba_number[9]; /* abs.ofs: 119 */ + u8 reserved5[8]; + u16 version; /* abs.ofs: 136 */ + u8 sku_cap; /* abs.ofs: 138 */ + u8 leds_mode; /* abs.ofs: 139 */ + u16 oem_mode; + u16 wowlan_mode; /* abs.ofs: 142 */ + u16 leds_time_interval; /* abs.ofs: 144 */ + u8 leds_off_time; /* abs.ofs: 146 */ + u8 leds_on_time; /* abs.ofs: 147 */ + u8 almgor_m_version; /* abs.ofs: 148 */ + u8 antenna_switch_type; /* abs.ofs: 149 */ + u8 reserved6[8]; + u16 board_revision_4965; /* abs.ofs: 158 */ + u8 reserved7[13]; + u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ + u8 reserved8[10]; + u8 sku_id[4]; /* abs.ofs: 192 */ + +/* + * Per-channel regulatory data. + * + * Each channel that *might* be supported by 3945 or 4965 has a fixed location + * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory + * txpower (MSB). + * + * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * channels (only for 4965, not supported by 3945) appear later in the EEPROM. + * + * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + */ + u16 band_1_count; /* abs.ofs: 196 */ + struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ + +/* + * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, + * 5.0 GHz channels 7, 8, 11, 12, 16 + * (4915-5080MHz) (none of these is ever supported) + */ + u16 band_2_count; /* abs.ofs: 226 */ + struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ + +/* + * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 + * (5170-5320MHz) + */ + u16 band_3_count; /* abs.ofs: 254 */ + struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ + +/* + * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 + * (5500-5700MHz) + */ + u16 band_4_count; /* abs.ofs: 280 */ + struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ + +/* + * 5.7 GHz channels 145, 149, 153, 157, 161, 165 + * (5725-5825MHz) + */ + u16 band_5_count; /* abs.ofs: 304 */ + struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ + + u8 reserved10[2]; + + +/* + * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) + * + * The channel listed is the center of the lower 20 MHz half of the channel. + * The overall center frequency is actually 2 channels (10 MHz) above that, + * and the upper half of each FAT channel is centered 4 channels (20 MHz) away + * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, + * and the overall FAT channel width centers on channel 3. + * + * NOTE: The RXON command uses 20 MHz channel numbers to specify the + * control channel to which to tune. RXON also specifies whether the + * control channel is the upper or lower half of a FAT channel. + * + * NOTE: 4965 does not support FAT channels on 2.4 GHz. + */ + struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ + u8 reserved11[2]; + +/* + * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), + * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) + */ + struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ + u8 reserved12[6]; + +/* + * 4965 driver requires txpower calibration format version 5 or greater. + * Driver does not work with txpower calibration version < 5. + * This value is simply a 16-bit number, no major/minor versions here. + */ + u16 calib_version; /* abs.ofs: 364 */ + u8 reserved13[2]; + u8 reserved14[96]; /* abs.ofs: 368 */ + +/* + * 4965 Txpower calibration data. + */ + struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ + + u8 reserved16[140]; /* fill out to full 1024 byte block */ + + +} __attribute__ ((packed)); + +#define IWL_EEPROM_IMAGE_SIZE 1024 + +/* End of EEPROM */ + +struct iwl_eeprom_ops { + int (*verify_signature) (struct iwl_priv *priv); + int (*acquire_semaphore) (struct iwl_priv *priv); + void (*release_semaphore) (struct iwl_priv *priv); +}; + + +void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); +int iwl_eeprom_init(struct iwl_priv *priv); + +int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); +int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); +void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); + +int iwl_init_channel_map(struct iwl_priv *priv); +void iwl_free_channel_map(struct iwl_priv *priv); +const struct iwl_channel_info *iwl_get_channel_info( + const struct iwl_priv *priv, + enum ieee80211_band band, u16 channel); + +#endif /* __iwl_eeprom_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c new file mode 100644 index 00000000000..1f8c2999805 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -0,0 +1,277 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler <tomas.winkler@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <net/mac80211.h> + +#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-debug.h" +#include "iwl-eeprom.h" +#include "iwl-core.h" + + +#define IWL_CMD(x) case x : return #x + +const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(RADAR_NOTIFICATION); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); + IWL_CMD(SENSITIVITY_CMD); + IWL_CMD(REPLY_PHY_CALIBRATION_CMD); + IWL_CMD(REPLY_RX_PHY_CMD); + IWL_CMD(REPLY_RX_MPDU_CMD); + IWL_CMD(REPLY_RX); + IWL_CMD(REPLY_COMPRESSED_BA); + default: + return "UNKNOWN"; + + } +} +EXPORT_SYMBOL(get_cmd_string); + +#define HOST_COMPLETE_TIMEOUT (HZ / 2) + +static int iwl_generic_cmd_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl4965_rx_packet *pkt = NULL; + + if (!skb) { + IWL_ERROR("Error: Response NULL in %s.\n", + get_cmd_string(cmd->hdr.cmd)); + return 1; + } + + pkt = (struct iwl4965_rx_packet *)skb->data; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from %s (0x%08X)\n", + get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); + return 1; + } + + IWL_DEBUG_HC("back from %s (0x%08X)\n", + get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); + + /* Let iwl_tx_complete free the response skb */ + return 1; +} + +static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int ret; + + BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + + /* An asynchronous command can not expect an SKB to be set. */ + BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + + /* Assign a generic callback if one is not provided */ + if (!cmd->meta.u.callback) + cmd->meta.u.callback = iwl_generic_cmd_callback; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EBUSY; + + ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + if (ret < 0) { + IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + return ret; + } + return 0; +} + +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int cmd_idx; + int ret; + + BUG_ON(cmd->meta.flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ + BUG_ON(cmd->meta.u.callback != NULL); + + if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: Already sending a host command\n", + get_cmd_string(cmd->id)); + ret = -EBUSY; + goto out; + } + + set_bit(STATUS_HCMD_ACTIVE, &priv->status); + + if (cmd->meta.flags & CMD_WANT_SKB) + cmd->meta.source = &cmd->meta; + + cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + if (cmd_idx < 0) { + ret = cmd_idx; + IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + goto out; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: time out after %dms.\n", + get_cmd_string(cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ret = -ETIMEDOUT; + goto cancel; + } + } + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + ret = -ECANCELED; + goto fail; + } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_DEBUG_INFO("Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto fail; + } + if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + IWL_ERROR("Error: Response NULL in '%s'\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto out; + } + + ret = 0; + goto out; + +cancel: + if (cmd->meta.flags & CMD_WANT_SKB) { + struct iwl_cmd *qcmd; + + /* Cancel the CMD_WANT_SKB flag for the cmd in the + * TX cmd queue. Otherwise in case the cmd comes + * in later, it will possibly set an invalid + * address (cmd->meta.source). */ + qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; + qcmd->meta.flags &= ~CMD_WANT_SKB; + } +fail: + if (cmd->meta.u.skb) { + dev_kfree_skb_any(cmd->meta.u.skb); + cmd->meta.u.skb = NULL; + } +out: + clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); + return ret; +} +EXPORT_SYMBOL(iwl_send_cmd_sync); + +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + if (cmd->meta.flags & CMD_ASYNC) + return iwl_send_cmd_async(priv, cmd); + + return iwl_send_cmd_sync(priv, cmd); +} +EXPORT_SYMBOL(iwl_send_cmd); + +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} +EXPORT_SYMBOL(iwl_send_cmd_pdu); + +int iwl_send_cmd_pdu_async(struct iwl_priv *priv, + u8 id, u16 len, const void *data, + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb)) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + cmd.meta.flags |= CMD_ASYNC; + cmd.meta.u.callback = callback; + + return iwl_send_cmd_async(priv, &cmd); +} +EXPORT_SYMBOL(iwl_send_cmd_pdu_async); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8993cca81b4..a443472bea6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -254,6 +254,26 @@ static inline u8 iwl_get_dma_hi_address(dma_addr_t addr) return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; } +/** + * iwl_queue_inc_wrap - increment queue index, wrap back to beginning + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl_queue_inc_wrap(int index, int n_bd) +{ + return ++index & (n_bd - 1); +} + +/** + * iwl_queue_dec_wrap - decrement queue index, wrap back to end + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return --index & (n_bd - 1); +} + /* TODO: Move fw_desc functions to iwl-pci.ko */ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h new file mode 100644 index 00000000000..5bc3df432d2 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -0,0 +1,429 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_io_h__ +#define __iwl_io_h__ + +#include <linux/io.h> + +#include "iwl-debug.h" + +/* + * IO, register, and NIC memory access functions + * + * NOTE on naming convention and macro usage for these + * + * A single _ prefix before a an access function means that no state + * check or debug information is printed when that function is called. + * + * A double __ prefix before an access function means that state is checked + * and the current line number and caller function name are printed in addition + * to any other debug output. + * + * The non-prefixed name is the #define that maps the caller into a + * #define that provides the caller's name and __LINE__ to the double + * prefix version. + * + * If you wish to call the function without any debug or state checking, + * you should use the single _ prefix version (as is used by dependent IO + * routines, for example _iwl_read_direct32 calls the non-check version of + * _iwl_read32.) + * + * These declarations are *extremely* useful in quickly isolating code deltas + * which result in misconfiguring of the hardware I/O. In combination with + * git-bisect and the IO debug level you can quickly determine the specific + * commit which breaks the IO sequence to the hardware. + * + */ + +#define _iwl_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, + u32 ofs, u32 val) +{ + IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); + _iwl_write32(priv, ofs, val); +} +#define iwl_write32(priv, ofs, val) \ + __iwl_write32(__FILE__, __LINE__, priv, ofs, val) +#else +#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) +#endif + +#define _iwl_read32(priv, ofs) readl((priv)->hw_base + (ofs)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) +{ + IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); + return _iwl_read32(priv, ofs); +} +#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) +#else +#define iwl_read32(p, o) _iwl_read32(p, o) +#endif + +static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_poll_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); + IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", + addr, bits, mask, + unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + return ret; +} +#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ + __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) +#else +#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) +#endif + +static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read32(priv, reg) | mask; + IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl_write32(priv, reg, val); +} +#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) +#endif + +static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_clear_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read32(priv, reg) & ~mask; + IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl_write32(priv, reg, val); +} +#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) +#endif + +static inline int _iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret; + u32 gp_ctl; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (atomic_read(&priv->restrict_refcnt)) + return 0; +#endif + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("WARNING: Requesting MAC access during RFKILL " + "wakes up NIC\n"); + + /* 10 msec allows time for NIC to complete its data save */ + gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL); + if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { + IWL_DEBUG_RF_KILL("Wait for complete power-down, " + "gpctl = 0x%08x\n", gp_ctl); + mdelay(10); + } else + IWL_DEBUG_RF_KILL("power-down complete, " + "gpctl = 0x%08x\n", gp_ctl); + } + + /* this bit wakes up the NIC */ + _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); + if (ret < 0) { + IWL_ERROR("MAC is in deep sleep!\n"); + return -EIO; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + atomic_inc(&priv->restrict_refcnt); +#endif + return 0; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_grab_nic_access(const char *f, u32 l, + struct iwl_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Grabbing access while already held %s %d.\n", f, l); + + IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l); + return _iwl_grab_nic_access(priv); +} +#define iwl_grab_nic_access(priv) \ + __iwl_grab_nic_access(__FILE__, __LINE__, priv) +#else +#define iwl_grab_nic_access(priv) \ + _iwl_grab_nic_access(priv) +#endif + +static inline void _iwl_release_nic_access(struct iwl_priv *priv) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (atomic_dec_and_test(&priv->restrict_refcnt)) +#endif + _iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_release_nic_access(const char *f, u32 l, + struct iwl_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt) <= 0) + IWL_ERROR("Release unheld nic access at line %s %d.\n", f, l); + + IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l); + _iwl_release_nic_access(priv); +} +#define iwl_release_nic_access(priv) \ + __iwl_release_nic_access(__FILE__, __LINE__, priv) +#else +#define iwl_release_nic_access(priv) \ + _iwl_release_nic_access(priv) +#endif + +static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + return _iwl_read32(priv, reg); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read_direct32(const char *f, u32 l, + struct iwl_priv *priv, u32 reg) +{ + u32 value = _iwl_read_direct32(priv, reg); + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s %d\n", f, l); + IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, + f, l); + return value; +} +#define iwl_read_direct32(priv, reg) \ + __iwl_read_direct32(__FILE__, __LINE__, priv, reg) +#else +#define iwl_read_direct32 _iwl_read_direct32 +#endif + +static inline void _iwl_write_direct32(struct iwl_priv *priv, + u32 reg, u32 value) +{ + _iwl_write32(priv, reg, value); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static void __iwl_write_direct32(const char *f , u32 line, + struct iwl_priv *priv, u32 reg, u32 value) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s line %d\n", f, line); + _iwl_write_direct32(priv, reg, value); +} +#define iwl_write_direct32(priv, reg, value) \ + __iwl_write_direct32(__func__, __LINE__, priv, reg, value) +#else +#define iwl_write_direct32 _iwl_write_direct32 +#endif + +static inline void iwl_write_reg_buf(struct iwl_priv *priv, + u32 reg, u32 len, u32 *values) +{ + u32 count = sizeof(u32); + + if ((priv != NULL) && (values != NULL)) { + for (; 0 < len; len -= count, reg += count, values++) + _iwl_write_direct32(priv, reg, *values); + } +} + +static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl_read_direct32(priv, addr) & mask) == mask) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_poll_direct_bit(const char *f, u32 l, + struct iwl_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); + + if (unlikely(ret == -ETIMEDOUT)) + IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - " + "timedout - %s %d\n", addr, mask, f, l); + else + IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " + "- %s %d\n", addr, mask, ret, f, l); + return ret; +} +#define iwl_poll_direct_bit(priv, addr, mask, timeout) \ + __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) +#else +#define iwl_poll_direct_bit _iwl_poll_direct_bit +#endif + +static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read_prph(const char *f, u32 line, + struct iwl_priv *priv, u32 reg) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s line %d\n", f, line); + return _iwl_read_prph(priv, reg); +} + +#define iwl_read_prph(priv, reg) \ + __iwl_read_prph(__func__, __LINE__, priv, reg) +#else +#define iwl_read_prph _iwl_read_prph +#endif + +static inline void _iwl_write_prph(struct iwl_priv *priv, + u32 addr, u32 val) +{ + _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write_prph(const char *f, u32 line, + struct iwl_priv *priv, u32 addr, u32 val) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s line %d\n", f, line); + _iwl_write_prph(priv, addr, val); +} + +#define iwl_write_prph(priv, addr, val) \ + __iwl_write_prph(__func__, __LINE__, priv, addr, val); +#else +#define iwl_write_prph _iwl_write_prph +#endif + +#define _iwl_set_bits_prph(priv, reg, mask) \ + _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bits_prph(const char *f, u32 line, + struct iwl_priv *priv, + u32 reg, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s line %d\n", f, line); + + _iwl_set_bits_prph(priv, reg, mask); +} +#define iwl_set_bits_prph(priv, reg, mask) \ + __iwl_set_bits_prph(__func__, __LINE__, priv, reg, mask) +#else +#define iwl_set_bits_prph _iwl_set_bits_prph +#endif + +#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ + _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bits_mask_prph(const char *f, u32 line, + struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s line %d\n", f, line); + _iwl_set_bits_mask_prph(priv, reg, bits, mask); +} +#define iwl_set_bits_mask_prph(priv, reg, bits, mask) \ + __iwl_set_bits_mask_prph(__func__, __LINE__, priv, reg, bits, mask) +#else +#define iwl_set_bits_mask_prph _iwl_set_bits_mask_prph +#endif + +static inline void iwl_clear_bits_prph(struct iwl_priv + *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read_prph(priv, reg); + _iwl_write_prph(priv, reg, (val & ~mask)); +} + +static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +} + +static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +{ + iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); +} + +static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, + u32 len, u32 *values) +{ + iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + for (; 0 < len; len -= sizeof(u32), values++) + iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c new file mode 100644 index 00000000000..03fdf5b434a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -0,0 +1,449 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <net/mac80211.h> +#include <linux/etherdevice.h> +#include <asm/unaligned.h> + +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-helpers.h" + +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (10) + +static const struct { + u16 tpt; + u8 on_time; + u8 of_time; +} blink_tbl[] = +{ + {300, 25, 25}, + {200, 40, 40}, + {100, 55, 55}, + {70, 65, 65}, + {50, 75, 75}, + {20, 85, 85}, + {15, 95, 95 }, + {10, 110, 110}, + {5, 130, 130}, + {0, 167, 167} +}; + +static int iwl_led_cmd_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + return 1; +} + + +/* Send led command */ +static int iwl_send_led_cmd(struct iwl_priv *priv, + struct iwl4965_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl4965_led_cmd), + .data = led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl_led_cmd_callback + }; + u32 reg; + + reg = iwl_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + + +/* Set led on command */ +static int iwl4965_led_on(struct iwl_priv *priv, int led_id) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = IWL_LED_SOLID, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led on command */ +static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, + enum led_brightness brightness) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + if (brightness == LED_FULL) { + led_cmd.on = IWL_LED_SOLID; + led_cmd.off = 0; + } + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led register off */ +static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED("led on %d\n", led_id); + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); + return 0; +} + +#if 0 +/* Set led off command */ +int iwl4965_led_off(struct iwl_priv *priv, int led_id) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = 0, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + IWL_DEBUG_LED("led off %d\n", led_id); + return iwl_send_led_cmd(priv, &led_cmd); +} +#endif + + +/* Set led register off */ +static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED("radio off\n"); + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); + return 0; +} + +/* Set led blink command */ +static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id, + u8 brightness) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + + return iwl_send_led_cmd(priv, &led_cmd); +} + + +/* + * brightness call back function for Tx/Rx LED + */ +static int iwl4965_led_associated(struct iwl_priv *priv, int led_id) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return 0; + + + /* start counting Tx/Rx bytes */ + if (!priv->last_blink_time && priv->allow_blinking) + priv->last_blink_time = jiffies; + return 0; +} + +/* + * brightness call back for association and radio + */ +static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct iwl4965_led *led = container_of(led_cdev, + struct iwl4965_led, led_dev); + struct iwl_priv *priv = led->priv; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + switch (brightness) { + case LED_FULL: + if (led->type == IWL_LED_TRG_ASSOC) + priv->allow_blinking = 1; + + if (led->led_on) + led->led_on(priv, IWL_LED_LINK); + break; + case LED_OFF: + if (led->type == IWL_LED_TRG_ASSOC) + priv->allow_blinking = 0; + + if (led->led_off) + led->led_off(priv, IWL_LED_LINK); + break; + default: + if (led->led_pattern) + led->led_pattern(priv, IWL_LED_LINK, brightness); + break; + } +} + + + +/* + * Register led class with the system + */ +static int iwl_leds_register_led(struct iwl_priv *priv, + struct iwl4965_led *led, + enum led_type type, u8 set_led, + const char *name, char *trigger) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret; + + led->led_dev.name = name; + led->led_dev.brightness_set = iwl4965_led_brightness_set; + led->led_dev.default_trigger = trigger; + + led->priv = priv; + led->type = type; + + ret = led_classdev_register(device, &led->led_dev); + if (ret) { + IWL_ERROR("Error: failed to register led handler.\n"); + return ret; + } + + led->registered = 1; + + if (set_led && led->led_on) + led->led_on(priv, IWL_LED_LINK); + + return 0; +} + + +/* + * calculate blink rate according to last 2 sec Tx/Rx activities + */ +static inline u8 get_blink_rate(struct iwl_priv *priv) +{ + int i; + u8 blink_rate; + u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + s64 tpt = current_tpt - priv->led_tpt; + + if (tpt < 0) /* wrapparound */ + tpt = -tpt; + + priv->led_tpt = current_tpt; + + if (tpt < IWL_LED_THRESHOLD) { + i = IWL_MAX_BLINK_TBL; + } else { + for (i = 0; i < IWL_MAX_BLINK_TBL; i++) + if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) + break; + } + /* if 0 frame is transfered */ + if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) + blink_rate = IWL_LED_SOLID; + else + blink_rate = blink_tbl[i].on_time; + + return blink_rate; +} + +static inline int is_rf_kill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +/* + * this function called from handler. Since setting Led command can + * happen very frequent we postpone led command to be called from + * REPLY handler so we know ucode is up + */ +void iwl_leds_background(struct iwl_priv *priv) +{ + u8 blink_rate; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + priv->last_blink_time = 0; + return; + } + if (is_rf_kill(priv)) { + priv->last_blink_time = 0; + return; + } + + if (!priv->allow_blinking) { + priv->last_blink_time = 0; + if (priv->last_blink_rate != IWL_LED_SOLID) { + priv->last_blink_rate = IWL_LED_SOLID; + iwl4965_led_on(priv, IWL_LED_LINK); + } + return; + } + if (!priv->last_blink_time || + !time_after(jiffies, priv->last_blink_time + + msecs_to_jiffies(1000))) + return; + + blink_rate = get_blink_rate(priv); + + /* call only if blink rate change */ + if (blink_rate != priv->last_blink_rate) { + if (blink_rate != IWL_LED_SOLID) { + priv->last_blink_time = jiffies + + msecs_to_jiffies(1000); + iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate); + } else { + priv->last_blink_time = 0; + iwl4965_led_on(priv, IWL_LED_LINK); + } + } + + priv->last_blink_rate = blink_rate; +} +EXPORT_SYMBOL(iwl_leds_background); + +/* Register all led handler */ +int iwl_leds_register(struct iwl_priv *priv) +{ + char *trigger; + char name[32]; + int ret; + + priv->last_blink_rate = 0; + priv->led_tpt = 0; + priv->last_blink_time = 0; + priv->allow_blinking = 0; + + trigger = ieee80211_get_radio_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:radio", + wiphy_name(priv->hw->wiphy)); + + priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; + + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_RADIO], + IWL_LED_TRG_RADIO, 1, + name, trigger); + if (ret) + goto exit_fail; + + trigger = ieee80211_get_assoc_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:assoc", + wiphy_name(priv->hw->wiphy)); + + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_ASSOC], + IWL_LED_TRG_ASSOC, 0, + name, trigger); + /* for assoc always turn led on */ + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_rx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:RX", + wiphy_name(priv->hw->wiphy)); + + + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_RX], + IWL_LED_TRG_RX, 0, + name, trigger); + + priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated; + priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated; + priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_tx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:TX", + wiphy_name(priv->hw->wiphy)); + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_TX], + IWL_LED_TRG_TX, 0, + name, trigger); + priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated; + priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated; + priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; + + if (ret) + goto exit_fail; + + return 0; + +exit_fail: + iwl_leds_unregister(priv); + return ret; +} +EXPORT_SYMBOL(iwl_leds_register); + +/* unregister led class */ +static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led) +{ + if (!led->registered) + return; + + led_classdev_unregister(&led->led_dev); + + if (set_led) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->registered = 0; +} + +/* Unregister all led handlers */ +void iwl_leds_unregister(struct iwl_priv *priv) +{ + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); +} +EXPORT_SYMBOL(iwl_leds_unregister); + diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h new file mode 100644 index 00000000000..5bb04128cd6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_leds_h__ +#define __iwl_leds_h__ + + +struct iwl_priv; + +#ifdef CONFIG_IWLWIFI_LEDS +#include <linux/leds.h> + +#define IWL_LED_SOLID 11 +#define IWL_LED_NAME_LEN 31 +#define IWL_DEF_LED_INTRVL __constant_cpu_to_le32(1000) + +#define IWL_LED_ACTIVITY (0<<1) +#define IWL_LED_LINK (1<<1) + +enum led_type { + IWL_LED_TRG_TX, + IWL_LED_TRG_RX, + IWL_LED_TRG_ASSOC, + IWL_LED_TRG_RADIO, + IWL_LED_TRG_MAX, +}; + + +struct iwl4965_led { + struct iwl_priv *priv; + struct led_classdev led_dev; + + int (*led_on) (struct iwl_priv *priv, int led_id); + int (*led_off) (struct iwl_priv *priv, int led_id); + int (*led_pattern) (struct iwl_priv *priv, int led_id, + enum led_brightness brightness); + + enum led_type type; + unsigned int registered; +}; + +int iwl_leds_register(struct iwl_priv *priv); +void iwl_leds_unregister(struct iwl_priv *priv); +void iwl_leds_background(struct iwl_priv *priv); + +#else +static inline int iwl_leds_register(struct iwl_priv *priv) +{ + return 0; +} +static inline void iwl_leds_unregister(struct iwl_priv *priv) +{ +} +static inline void iwl_leds_background(struct iwl_priv *priv) +{ +} + +#endif /* CONFIG_IWLWIFI_LEDS */ +#endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 4ba12163487..c9cf8eef1a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -243,44 +243,48 @@ * 4965 Tx Scheduler registers. * Details are documented in iwl-4965-hw.h */ -#define KDR_SCD_BASE (PRPH_BASE + 0xa02c00) +#define IWL49_SCD_BASE (PRPH_BASE + 0xa02c00) -#define KDR_SCD_SRAM_BASE_ADDR (KDR_SCD_BASE + 0x0) -#define KDR_SCD_EMPTY_BITS (KDR_SCD_BASE + 0x4) -#define KDR_SCD_DRAM_BASE_ADDR (KDR_SCD_BASE + 0x10) -#define KDR_SCD_AIT (KDR_SCD_BASE + 0x18) -#define KDR_SCD_TXFACT (KDR_SCD_BASE + 0x1c) -#define KDR_SCD_QUEUE_WRPTR(x) (KDR_SCD_BASE + 0x24 + (x) * 4) -#define KDR_SCD_QUEUE_RDPTR(x) (KDR_SCD_BASE + 0x64 + (x) * 4) -#define KDR_SCD_SETQUEUENUM (KDR_SCD_BASE + 0xa4) -#define KDR_SCD_SET_TXSTAT_TXED (KDR_SCD_BASE + 0xa8) -#define KDR_SCD_SET_TXSTAT_DONE (KDR_SCD_BASE + 0xac) -#define KDR_SCD_SET_TXSTAT_NOT_SCHD (KDR_SCD_BASE + 0xb0) -#define KDR_SCD_DECREASE_CREDIT (KDR_SCD_BASE + 0xb4) -#define KDR_SCD_DECREASE_SCREDIT (KDR_SCD_BASE + 0xb8) -#define KDR_SCD_LOAD_CREDIT (KDR_SCD_BASE + 0xbc) -#define KDR_SCD_LOAD_SCREDIT (KDR_SCD_BASE + 0xc0) -#define KDR_SCD_BAR (KDR_SCD_BASE + 0xc4) -#define KDR_SCD_BAR_DW0 (KDR_SCD_BASE + 0xc8) -#define KDR_SCD_BAR_DW1 (KDR_SCD_BASE + 0xcc) -#define KDR_SCD_QUEUECHAIN_SEL (KDR_SCD_BASE + 0xd0) -#define KDR_SCD_QUERY_REQ (KDR_SCD_BASE + 0xd8) -#define KDR_SCD_QUERY_RES (KDR_SCD_BASE + 0xdc) -#define KDR_SCD_PENDING_FRAMES (KDR_SCD_BASE + 0xe0) -#define KDR_SCD_INTERRUPT_MASK (KDR_SCD_BASE + 0xe4) -#define KDR_SCD_INTERRUPT_THRESHOLD (KDR_SCD_BASE + 0xe8) -#define KDR_SCD_QUERY_MIN_FRAME_SIZE (KDR_SCD_BASE + 0x100) -#define KDR_SCD_QUEUE_STATUS_BITS(x) (KDR_SCD_BASE + 0x104 + (x) * 4) +#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_BASE + 0x0) +#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_BASE + 0x4) +#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_BASE + 0x10) +#define IWL49_SCD_AIT (IWL49_SCD_BASE + 0x18) +#define IWL49_SCD_TXFACT (IWL49_SCD_BASE + 0x1c) +#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_BASE + 0x24 + (x) * 4) +#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_BASE + 0x64 + (x) * 4) +#define IWL49_SCD_SETQUEUENUM (IWL49_SCD_BASE + 0xa4) +#define IWL49_SCD_SET_TXSTAT_TXED (IWL49_SCD_BASE + 0xa8) +#define IWL49_SCD_SET_TXSTAT_DONE (IWL49_SCD_BASE + 0xac) +#define IWL49_SCD_SET_TXSTAT_NOT_SCHD (IWL49_SCD_BASE + 0xb0) +#define IWL49_SCD_DECREASE_CREDIT (IWL49_SCD_BASE + 0xb4) +#define IWL49_SCD_DECREASE_SCREDIT (IWL49_SCD_BASE + 0xb8) +#define IWL49_SCD_LOAD_CREDIT (IWL49_SCD_BASE + 0xbc) +#define IWL49_SCD_LOAD_SCREDIT (IWL49_SCD_BASE + 0xc0) +#define IWL49_SCD_BAR (IWL49_SCD_BASE + 0xc4) +#define IWL49_SCD_BAR_DW0 (IWL49_SCD_BASE + 0xc8) +#define IWL49_SCD_BAR_DW1 (IWL49_SCD_BASE + 0xcc) +#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_BASE + 0xd0) +#define IWL49_SCD_QUERY_REQ (IWL49_SCD_BASE + 0xd8) +#define IWL49_SCD_QUERY_RES (IWL49_SCD_BASE + 0xdc) +#define IWL49_SCD_PENDING_FRAMES (IWL49_SCD_BASE + 0xe0) +#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_BASE + 0xe4) +#define IWL49_SCD_INTERRUPT_THRESHOLD (IWL49_SCD_BASE + 0xe8) +#define IWL49_SCD_QUERY_MIN_FRAME_SIZE (IWL49_SCD_BASE + 0x100) +#define IWL49_SCD_QUEUE_STATUS_BITS(x) (IWL49_SCD_BASE + 0x104 + (x) * 4) /* SP SCD */ -#define SHL_SCD_BASE (PRPH_BASE + 0xa02c00) +#define IWL50_SCD_BASE (PRPH_BASE + 0xa02c00) -#define SHL_SCD_AIT (SHL_SCD_BASE + 0x0c) -#define SHL_SCD_TXFACT (SHL_SCD_BASE + 0x10) -#define SHL_SCD_QUEUE_WRPTR(x) (SHL_SCD_BASE + 0x18 + (x) * 4) -#define SHL_SCD_QUEUE_RDPTR(x) (SHL_SCD_BASE + 0x68 + (x) * 4) -#define SHL_SCD_QUEUECHAIN_SEL (SHL_SCD_BASE + 0xe8) -#define SHL_SCD_AGGR_SEL (SHL_SCD_BASE + 0x248) -#define SHL_SCD_INTERRUPT_MASK (SHL_SCD_BASE + 0x108) +#define IWL50_SCD_SRAM_BASE_ADDR (IWL50_SCD_BASE + 0x0) +#define IWL50_SCD_DRAM_BASE_ADDR (IWL50_SCD_BASE + 0x8) +#define IWL50_SCD_AIT (IWL50_SCD_BASE + 0x0c) +#define IWL50_SCD_TXFACT (IWL50_SCD_BASE + 0x10) +#define IWL50_SCD_ACTIVE (IWL50_SCD_BASE + 0x14) +#define IWL50_SCD_QUEUE_WRPTR(x) (IWL50_SCD_BASE + 0x18 + (x) * 4) +#define IWL50_SCD_QUEUE_RDPTR(x) (IWL50_SCD_BASE + 0x68 + (x) * 4) +#define IWL50_SCD_QUEUECHAIN_SEL (IWL50_SCD_BASE + 0xe8) +#define IWL50_SCD_AGGR_SEL (IWL50_SCD_BASE + 0x248) +#define IWL50_SCD_INTERRUPT_MASK (IWL50_SCD_BASE + 0x108) +#define IWL50_SCD_QUEUE_STATUS_BITS(x) (IWL50_SCD_BASE + 0x10c + (x) * 4) #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c new file mode 100644 index 00000000000..8f38c24491c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> + +#include <net/mac80211.h> + +#include "iwl-eeprom.h" +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-helpers.h" + + +/* software rf-kill from user */ +static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) +{ + struct iwl_priv *priv = data; + int err = 0; + + if (!priv->rfkill_mngr.rfkill) + return 0; + + IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + mutex_lock(&priv->mutex); + + switch (state) { + case RFKILL_STATE_ON: + priv->cfg->ops->lib->radio_kill_sw(priv, 0); + /* if HW rf-kill is set dont allow ON state */ + if (iwl_is_rfkill(priv)) + err = -EBUSY; + break; + case RFKILL_STATE_OFF: + priv->cfg->ops->lib->radio_kill_sw(priv, 1); + if (!iwl_is_rfkill(priv)) + err = -EBUSY; + break; + } + mutex_unlock(&priv->mutex); + + return err; +} + +int iwl_rfkill_init(struct iwl_priv *priv) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret = 0; + + BUG_ON(device == NULL); + + IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); + priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!priv->rfkill_mngr.rfkill) { + IWL_ERROR("Unable to allocate rfkill device.\n"); + ret = -ENOMEM; + goto error; + } + + priv->rfkill_mngr.rfkill->name = priv->cfg->name; + priv->rfkill_mngr.rfkill->data = priv; + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + priv->rfkill_mngr.rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; + priv->rfkill_mngr.rfkill->user_claim_unsupported = 1; + + priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; + priv->rfkill_mngr.rfkill->dev.class->resume = NULL; + + priv->rfkill_mngr.input_dev = input_allocate_device(); + if (!priv->rfkill_mngr.input_dev) { + IWL_ERROR("Unable to allocate rfkill input device.\n"); + ret = -ENOMEM; + goto freed_rfkill; + } + + priv->rfkill_mngr.input_dev->name = priv->cfg->name; + priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); + priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; + priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; + priv->rfkill_mngr.input_dev->dev.parent = device; + priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); + + ret = rfkill_register(priv->rfkill_mngr.rfkill); + if (ret) { + IWL_ERROR("Unable to register rfkill: %d\n", ret); + goto free_input_dev; + } + + ret = input_register_device(priv->rfkill_mngr.input_dev); + if (ret) { + IWL_ERROR("Unable to register rfkill input device: %d\n", ret); + goto unregister_rfkill; + } + + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; + +unregister_rfkill: + rfkill_unregister(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +free_input_dev: + input_free_device(priv->rfkill_mngr.input_dev); + priv->rfkill_mngr.input_dev = NULL; + +freed_rfkill: + if (priv->rfkill_mngr.rfkill != NULL) + rfkill_free(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +error: + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; +} +EXPORT_SYMBOL(iwl_rfkill_init); + +void iwl_rfkill_unregister(struct iwl_priv *priv) +{ + + if (priv->rfkill_mngr.input_dev) + input_unregister_device(priv->rfkill_mngr.input_dev); + + if (priv->rfkill_mngr.rfkill) + rfkill_unregister(priv->rfkill_mngr.rfkill); + + priv->rfkill_mngr.input_dev = NULL; + priv->rfkill_mngr.rfkill = NULL; +} +EXPORT_SYMBOL(iwl_rfkill_unregister); + +/* set rf-kill to the right state. */ +void iwl_rfkill_set_hw_state(struct iwl_priv *priv) +{ + + if (!priv->rfkill_mngr.rfkill) + return; + + if (!iwl_is_rfkill(priv)) + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + else + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF; +} +EXPORT_SYMBOL(iwl_rfkill_set_hw_state); diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h new file mode 100644 index 00000000000..e7aa51a1db1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#ifndef __iwl_rf_kill_h__ +#define __iwl_rf_kill_h__ + +struct iwl_priv; + +#include <linux/rfkill.h> +#include <linux/input.h> + + +#ifdef CONFIG_IWLCORE_RFKILL +struct iwl_rfkill_mngr { + struct rfkill *rfkill; + struct input_dev *input_dev; +}; + +void iwl_rfkill_set_hw_state(struct iwl_priv *priv); +void iwl_rfkill_unregister(struct iwl_priv *priv); +int iwl_rfkill_init(struct iwl_priv *priv); +#else +static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {} +static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {} +static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; } +#endif + + + +#endif /* __iwl_rf_kill_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index b576ff24eb4..a40a2174df9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ieee80211 subsystem header files. * diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cbaeaf18649..29a9ecdcbf3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -46,6 +46,7 @@ #include <asm/div64.h> +#include "iwl-3945-core.h" #include "iwl-3945.h" #include "iwl-helpers.h" @@ -91,15 +92,10 @@ int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */ #define VS #endif -#define IWLWIFI_VERSION "1.2.23k" VD VS -#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" +#define IWLWIFI_VERSION "1.2.26k" VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL3945_UCODE_API "-1" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); @@ -116,16 +112,10 @@ static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl3945_get_hw_mode( - struct iwl3945_priv *priv, int mode) +static const struct ieee80211_supported_band *iwl3945_get_band( + struct iwl3945_priv *priv, enum ieee80211_band band) { - int i; - - for (i = 0; i < 3; i++) - if (priv->modes[i].mode == mode) - return &priv->modes[i]; - - return NULL; + return priv->hw->wiphy->bands[band]; } static int iwl3945_is_empty_essid(const char *essid, int essid_len) @@ -168,17 +158,6 @@ static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) return escaped; } -static void iwl3945_print_hex_dump(int level, void *p, u32 len) -{ -#ifdef CONFIG_IWL3945_DEBUG - if (!(iwl3945_debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -#endif -} - /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -204,7 +183,7 @@ static void iwl3945_print_hex_dump(int level, void *p, u32 len) * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused. ***************************************************/ -static int iwl3945_queue_space(const struct iwl3945_queue *q) +int iwl3945_queue_space(const struct iwl3945_queue *q) { int s = q->read_ptr - q->write_ptr; @@ -220,33 +199,14 @@ static int iwl3945_queue_space(const struct iwl3945_queue *q) return s; } -/** - * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning - * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) - */ -static inline int iwl3945_queue_inc_wrap(int index, int n_bd) -{ - return ++index & (n_bd - 1); -} - -/** - * iwl3945_queue_dec_wrap - increment queue index, wrap back to end - * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) - */ -static inline int iwl3945_queue_dec_wrap(int index, int n_bd) -{ - return --index & (n_bd - 1); -} - -static inline int x2_queue_used(const struct iwl3945_queue *q, int i) +int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i) { return q->write_ptr > q->read_ptr ? (i >= q->read_ptr && i < q->write_ptr) : !(i < q->read_ptr && i >= q->write_ptr); } + static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge) { /* This is for scan command, the big buffer at end of command array */ @@ -267,8 +227,8 @@ static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q q->n_window = slots_num; q->id = id; - /* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap - * and iwl3945_queue_dec_wrap are broken. */ + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ BUG_ON(!is_power_of_2(count)); /* slots_num must be power-of-two size, otherwise @@ -368,7 +328,7 @@ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, txq->need_update = 0; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */ + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); /* Initialize queue high/low-water, head/tail indexes */ @@ -399,7 +359,7 @@ void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *t /* first, empty all BD's */ for (; q->write_ptr != q->read_ptr; - q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) iwl3945_hw_txq_free_tfd(priv, txq); len = sizeof(struct iwl3945_cmd) * q->n_window; @@ -547,7 +507,7 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 station->sta.sta.sta_id = index; station->sta.station_flags = 0; - if (priv->phymode == MODE_IEEE80211A) + if (priv->band == IEEE80211_BAND_5GHZ) rate = IWL_RATE_6M_PLCP; else rate = IWL_RATE_1M_PLCP; @@ -738,7 +698,7 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c txq->need_update = 1; /* Increment and update queue's write index */ - q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); ret = iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); @@ -773,17 +733,17 @@ static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_ { int cmd_idx; int ret; - static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ BUG_ON(cmd->meta.flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ BUG_ON(cmd->meta.u.callback != NULL); - if (atomic_xchg(&entry, 1)) { + if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { IWL_ERROR("Error sending %s: Already sending a host command\n", get_cmd_string(cmd->id)); - return -EBUSY; + ret = -EBUSY; + goto out; } set_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -853,7 +813,7 @@ fail: cmd->meta.u.skb = NULL; } out: - atomic_set(&entry, 0); + clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); return ret; } @@ -894,35 +854,37 @@ int iwl3945_send_statistics_request(struct iwl3945_priv *priv) /** * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON - * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz - * @channel: Any channel valid for the requested phymode + * @band: 2.4 or 5 GHz band + * @channel: Any channel valid for the requested band - * In addition to setting the staging RXON, priv->phymode is also set. + * In addition to setting the staging RXON, priv->band is also set. * * NOTE: Does not commit to the hardware; it sets appropriate bit fields - * in the staging RXON flag structure based on the phymode + * in the staging RXON flag structure based on the band */ -static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel) +static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, + enum ieee80211_band band, + u16 channel) { - if (!iwl3945_get_channel_info(priv, phymode, channel)) { + if (!iwl3945_get_channel_info(priv, band, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", - channel, phymode); + channel, band); return -EINVAL; } if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && - (priv->phymode == phymode)) + (priv->band == band)) return 0; priv->staging_rxon.channel = cpu_to_le16(channel); - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; else priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - priv->phymode = phymode; + priv->band = band; - IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); return 0; } @@ -1210,8 +1172,7 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) return -EIO; } - /* Init the hardware's rate fallback order based on the - * phymode */ + /* Init the hardware's rate fallback order based on the band */ rc = iwl3945_init_hw_rate_table(priv); if (rc) { IWL_ERROR("Error setting HW rate table: %02X\n", rc); @@ -1635,151 +1596,6 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) return 0; } -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ -#ifdef CONFIG_IWL3945_DEBUG - -/** - * iwl3945_report_frame - dump frame to syslog during debug sessions - * - * You may hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - */ -void iwl3945_report_frame(struct iwl3945_priv *priv, - struct iwl3945_rx_packet *pkt, - struct ieee80211_hdr *header, int group100) -{ - u32 to_us; - u32 print_summary = 0; - u32 print_dump = 0; /* set to 1 to dump all frames' contents */ - u32 hundred = 0; - u32 dataframe = 0; - u16 fc; - u16 seq_ctl; - u16 channel; - u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; - u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); - - /* MAC header */ - fc = le16_to_cpu(header->frame_control); - seq_ctl = le16_to_cpu(header->seq_ctrl); - - /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); - - /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); - - to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - - /* if data frame is to us and all is good, - * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { - dataframe = 1; - if (!group100) - print_summary = 1; /* print each frame */ - else if (priv->framecnt_to_us < 100) { - priv->framecnt_to_us++; - print_summary = 0; - } else { - priv->framecnt_to_us = 0; - print_summary = 1; - hundred = 1; - } - } else { - /* print summary for all other frames */ - print_summary = 1; - } - - if (print_summary) { - char *title; - u32 rate; - - if (hundred) - title = "100Frames"; - else if (fc & IEEE80211_FCTL_RETRY) - title = "Retry"; - else if (ieee80211_is_assoc_response(fc)) - title = "AscRsp"; - else if (ieee80211_is_reassoc_response(fc)) - title = "RasRsp"; - else if (ieee80211_is_probe_response(fc)) { - title = "PrbRsp"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_beacon(fc)) { - title = "Beacon"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_atim(fc)) - title = "ATIM"; - else if (ieee80211_is_auth(fc)) - title = "Auth"; - else if (ieee80211_is_deauth(fc)) - title = "DeAuth"; - else if (ieee80211_is_disassoc(fc)) - title = "DisAssoc"; - else - title = "Frame"; - - rate = iwl3945_rate_index_from_plcp(rate_sym); - if (rate == -1) - rate = 0; - else - rate = iwl3945_rates[rate].ieee / 2; - - /* print frame summary. - * MAC addresses show just the last byte (for brevity), - * but you can hack it to show more, if you'd like to. */ - if (dataframe) - IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " - "len=%u, rssi=%d, chnl=%d, rate=%u, \n", - title, fc, header->addr1[5], - length, rssi, channel, rate); - else { - /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " - "phy=0x%02x, chnl=%d\n", - title, fc, header->addr1[5], - header->addr3[5], rssi, - tsf_low - priv->scan_start_tsf, - phy_flags, channel); - } - } - if (print_dump) - iwl3945_print_hex_dump(IWL_DL_RX, data, length); -} -#endif - static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv) { if (priv->hw_setting.shared_virt) @@ -1915,7 +1731,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, /* * QoS support */ -#ifdef CONFIG_IWL3945_QOS static int iwl3945_send_qos_params_command(struct iwl3945_priv *priv, struct iwl3945_qosparam_cmd *qos) { @@ -2044,7 +1859,6 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) } } -#endif /* CONFIG_IWL3945_QOS */ /* * Power management (not Tx power!) functions */ @@ -2244,39 +2058,13 @@ int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *h return !compare_ether_addr(header->addr2, priv->bssid); /* packets to our adapter go through */ return !compare_ether_addr(header->addr1, priv->mac_addr); + default: + return 1; } return 1; } -#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x - -static const char *iwl3945_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_ENTRY(SHORT_LIMIT); - TX_STATUS_ENTRY(LONG_LIMIT); - TX_STATUS_ENTRY(FIFO_UNDERRUN); - TX_STATUS_ENTRY(MGMNT_ABORT); - TX_STATUS_ENTRY(NEXT_FRAG); - TX_STATUS_ENTRY(LIFE_EXPIRE); - TX_STATUS_ENTRY(DEST_PS); - TX_STATUS_ENTRY(ABORTED); - TX_STATUS_ENTRY(BT_RETRY); - TX_STATUS_ENTRY(STA_INVALID); - TX_STATUS_ENTRY(FRAG_DROPPED); - TX_STATUS_ENTRY(TID_DISABLE); - TX_STATUS_ENTRY(FRAME_FLUSHED); - TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); - TX_STATUS_ENTRY(TX_LOCKED); - TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); - } - - return "UNKNOWN"; -} - /** * iwl3945_scan_cancel - Cancel any currently executing HW scan * @@ -2461,9 +2249,10 @@ static int iwl3945_set_rxon_hwcrypto(struct iwl3945_priv *priv, int hw_decrypt) return 0; } -static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode) +static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) { + if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_CCK_MSK); @@ -2515,6 +2304,9 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; + default: + IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + break; } #if 0 @@ -2526,7 +2318,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl3945_get_channel_info(priv, priv->phymode, + ch_info = iwl3945_get_channel_info(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2542,11 +2334,11 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); if (is_channel_a_band(ch_info)) - priv->phymode = MODE_IEEE80211A; + priv->band = IEEE80211_BAND_5GHZ; else - priv->phymode = MODE_IEEE80211G; + priv->band = IEEE80211_BAND_2GHZ; - iwl3945_set_flags_for_phymode(priv, priv->phymode); + iwl3945_set_flags_for_phymode(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2560,7 +2352,7 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) const struct iwl3945_channel_info *ch_info; ch_info = iwl3945_get_channel_info(priv, - priv->phymode, + priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info || !is_channel_ibss(ch_info)) { @@ -2694,8 +2486,12 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else + } else { cmd->cmd.tx.timeout.pm_frame_timeout = 0; +#ifdef CONFIG_IWL3945_LEDS + priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len); +#endif + } cmd->cmd.tx.driver_txop = 0; cmd->cmd.tx.tx_flags = tx_flags; @@ -2792,7 +2588,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2963,7 +2759,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, ieee80211_get_hdrlen(fc)); /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); rc = iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); @@ -2992,12 +2788,12 @@ drop: static void iwl3945_set_rate(struct iwl3945_priv *priv) { - const struct ieee80211_hw_mode *hw = NULL; + const struct ieee80211_supported_band *sband = NULL; struct ieee80211_rate *rate; int i; - hw = iwl3945_get_hw_mode(priv, priv->phymode); - if (!hw) { + sband = iwl3945_get_band(priv, priv->band); + if (!sband) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; } @@ -3005,24 +2801,17 @@ static void iwl3945_set_rate(struct iwl3945_priv *priv) priv->active_rate = 0; priv->active_rate_basic = 0; - IWL_DEBUG_RATE("Setting rates for 802.11%c\n", - hw->mode == MODE_IEEE80211A ? - 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); - - for (i = 0; i < hw->num_rates; i++) { - rate = &(hw->rates[i]); - if ((rate->val < IWL_RATE_COUNT) && - (rate->flags & IEEE80211_RATE_SUPPORTED)) { - IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl3945_rates[rate->val].plcp, - (rate->flags & IEEE80211_RATE_BASIC) ? - "*" : ""); - priv->active_rate |= (1 << rate->val); - if (rate->flags & IEEE80211_RATE_BASIC) - priv->active_rate_basic |= (1 << rate->val); - } else - IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl3945_rates[rate->val].plcp); + IWL_DEBUG_RATE("Setting rates for %s GHz\n", + sband->band == IEEE80211_BAND_2GHZ ? "2.4" : "5"); + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + if ((rate->hw_value < IWL_RATE_COUNT) && + !(rate->flags & IEEE80211_CHAN_DISABLED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)\n", + rate->hw_value, iwl3945_rates[rate->hw_value].plcp); + priv->active_rate |= (1 << rate->hw_value); + } } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -3330,127 +3119,6 @@ static int iwl3945_get_measurement(struct iwl3945_priv *priv, } #endif -static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv, - struct iwl3945_tx_info *tx_sta) -{ - - tx_sta->status.ack_signal = 0; - tx_sta->status.excessive_retries = 0; - tx_sta->status.queue_length = 0; - tx_sta->status.queue_number = 0; - - if (in_interrupt()) - ieee80211_tx_status_irqsafe(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - else - ieee80211_tx_status(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - - tx_sta->skb[0] = NULL; -} - -/** - * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd - * - * When FW advances 'R' index, all entries between old and new 'R' index - * need to be reclaimed. As result, some free space forms. If there is - * enough free space (> low mark), wake the stack that feeds us. - */ -static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index) -{ - struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct iwl3945_queue *q = &txq->q; - int nfreed = 0; - - if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " - "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); - return 0; - } - - for (index = iwl3945_queue_inc_wrap(index, q->n_bd); - q->read_ptr != index; - q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (txq_id != IWL_CMD_QUEUE_NUM) { - iwl3945_txstatus_to_ieee(priv, - &(txq->txb[txq->q.read_ptr])); - iwl3945_hw_txq_free_tfd(priv, txq); - } else if (nfreed > 1) { - IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, - q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); - } - nfreed++; - } - - if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && - (txq_id != IWL_CMD_QUEUE_NUM) && - priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); - - - return nfreed; -} - -static int iwl3945_is_tx_success(u32 status) -{ - return (status & 0xFF) == 0x1; -} - -/****************************************************************************** - * - * Generic RX handler implementations - * - ******************************************************************************/ -/** - * iwl3945_rx_reply_tx - Handle Tx response - */ -static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, - struct iwl3945_rx_mem_buffer *rxb) -{ - struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; - struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->status); - - if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - - tx_status = &(txq->txb[txq->q.read_ptr].status); - - tx_status->retry_count = tx_resp->failure_frame; - tx_status->queue_number = status; - tx_status->queue_length = tx_resp->bt_kill_count; - tx_status->queue_length |= tx_resp->failure_rts; - - tx_status->flags = - iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - - tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate); - - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", - txq_id, iwl3945_get_tx_fail_reason(status), status, - tx_resp->rate, tx_resp->failure_frame); - - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) - iwl3945_tx_queue_reclaim(priv, txq_id, index); - - if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) - IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); -} - - static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) { @@ -3797,13 +3465,44 @@ static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv) priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = iwl3945_rx_scan_complete_notif; priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; - priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; /* Set up hardware specific Rx handlers */ iwl3945_hw_rx_handler_setup(priv); } /** + * iwl3945_cmd_queue_reclaim - Reclaim CMD queue entries + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. + */ +static void iwl3945_cmd_queue_reclaim(struct iwl3945_priv *priv, + int txq_id, int index) +{ + struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; + struct iwl3945_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (iwl3945_x2_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->write_ptr, q->read_ptr); + return; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->write_ptr, q->read_ptr); + queue_work(priv->workqueue, &priv->restart); + break; + } + nfreed++; + } +} + + +/** * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim * @@ -3822,12 +3521,6 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, int cmd_index; struct iwl3945_cmd *cmd; - /* If a Tx command is being handled and it isn't in the actual - * command queue then there a command routing bug has been introduced - * in the queue management code. */ - if (txq_id != IWL_CMD_QUEUE_NUM) - IWL_ERROR("Error wrong command queue %d command id 0x%X\n", - txq_id, pkt->hdr.cmd); BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); @@ -3841,7 +3534,7 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl3945_tx_queue_reclaim(priv, txq_id, index); + iwl3945_cmd_queue_reclaim(priv, txq_id, index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -4460,6 +4153,16 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv) iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); } + +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl3945_priv *priv) +{ + /* wait to make sure we flush pedding tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + + static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv) { clear_bit(STATUS_INT_ENABLED, &priv->status); @@ -4521,8 +4224,7 @@ static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv) if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERROR("Start IWL Error Log Dump:\n"); - IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", - priv->status, priv->config, count); + IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); } IWL_ERROR("Desc Time asrtPC blink2 " @@ -4742,9 +4444,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after * reading CSR_INT. */ - if (inta_fh & CSR_FH_INT_RX_MASK) + if (inta_fh & CSR39_FH_INT_RX_MASK) inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR_FH_INT_TX_MASK) + if (inta_fh & CSR39_FH_INT_TX_MASK) inta |= CSR_INT_BIT_FH_TX; /* Now service all interrupt bits discovered above. */ @@ -4792,7 +4494,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) /* Queue restart only if RF_KILL switch was set to "kill" * when we loaded driver, and is now set to "enable". * After we're Alive, RF_KILL gets handled by - * iwl_rx_card_state_notif() */ + * iwl3945_rx_card_state_notif() */ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { clear_bit(STATUS_RF_KILL_HW, &priv->status); queue_work(priv->workqueue, &priv->restart); @@ -4860,7 +4562,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) } /* Re-enable all interrupts */ - iwl3945_enable_interrupts(priv); + /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl3945_enable_interrupts(priv); #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_ISR)) { @@ -4924,7 +4628,9 @@ unplugged: none: /* re-enable interrupts here since we don't have anything to service. */ - iwl3945_enable_interrupts(priv); + /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl3945_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } @@ -5026,24 +4732,24 @@ static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int ban * Based on band and channel number. */ const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv, - int phymode, u16 channel) + enum ieee80211_band band, u16 channel) { int i; - switch (phymode) { - case MODE_IEEE80211A: + switch (band) { + case IEEE80211_BAND_5GHZ: for (i = 14; i < priv->channel_count; i++) { if (priv->channel_info[i].channel == channel) return &priv->channel_info[i]; } break; - case MODE_IEEE80211B: - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: if (channel >= 1 && channel <= 14) return &priv->channel_info[channel - 1]; break; - + case IEEE80211_NUM_BANDS: + WARN_ON(1); } return NULL; @@ -5106,8 +4812,8 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { ch_info->channel = eeprom_ch_index[ch]; - ch_info->phymode = (band == 1) ? MODE_IEEE80211B : - MODE_IEEE80211A; + ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ; /* permanently store EEPROM's channel regulatory flags * and max power in channel info database. */ @@ -5134,11 +4840,12 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x" " %ddBm): Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? "5.2" : "2.4", + CHECK_AND_PRINT(VALID), CHECK_AND_PRINT(IBSS), CHECK_AND_PRINT(ACTIVE), CHECK_AND_PRINT(RADAR), @@ -5203,18 +4910,20 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode) +static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52; else return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode) +static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, + enum ieee80211_band band) { - u16 active = iwl3945_get_active_dwell_time(priv, phymode); - u16 passive = (phymode != MODE_IEEE80211A) ? + u16 active = iwl3945_get_active_dwell_time(priv, band); + u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; @@ -5234,28 +4943,32 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode return passive; } -static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, +static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, + enum ieee80211_band band, u8 is_active, u8 direct_mask, struct iwl3945_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode; + const struct ieee80211_supported_band *sband; const struct iwl3945_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl3945_get_hw_mode(priv, phymode); - if (!hw_mode) + sband = iwl3945_get_band(priv, band); + if (!sband) return 0; - channels = hw_mode->channels; + channels = sband->channels; - active_dwell = iwl3945_get_active_dwell_time(priv, phymode); - passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode); + active_dwell = iwl3945_get_active_dwell_time(priv, band); + passive_dwell = iwl3945_get_passive_dwell_time(priv, band); + + for (i = 0, added = 0; i < sband->n_channels; i++) { + if (channels[i].flags & IEEE80211_CHAN_DISABLED) + continue; - for (i = 0, added = 0; i < hw_mode->num_channels; i++) { - if (channels[i].chan == + if (channels[i].hw_value == le16_to_cpu(priv->active_rxon.channel)) { if (iwl3945_is_associated(priv)) { IWL_DEBUG_SCAN @@ -5266,9 +4979,9 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, } else if (priv->only_active_channel) continue; - scan_ch->channel = channels[i].chan; + scan_ch->channel = channels[i].hw_value; - ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel); + ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", scan_ch->channel); @@ -5276,7 +4989,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, } if (!is_active || is_channel_passive(ch_info) || - !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = 0; /* passive */ else scan_ch->type = 1; /* active */ @@ -5295,7 +5008,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, /* scan_pwr_info->tpc.dsp_atten; */ /*scan_pwr_info->tpc.tx_gain; */ - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); @@ -5319,41 +5032,23 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, return added; } -static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv) -{ - int i, j; - for (i = 0; i < 3; i++) { - struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; - for (j = 0; j < hw_mode->num_channels; j++) - hw_mode->channels[j].flag = hw_mode->channels[j].val; - } -} - static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl3945_rates[i].ieee * 5; - rates[i].val = i; /* Rate scaling will work on indexes */ - rates[i].val2 = i; - rates[i].flags = IEEE80211_RATE_SUPPORTED; - /* Only OFDM have the bits-per-symbol set */ - if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) - rates[i].flags |= IEEE80211_RATE_OFDM; - else { + rates[i].bitrate = iwl3945_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { /* - * If CCK 1M then set rate flag to CCK else CCK_2 - * which is CCK | PREAMBLE2 + * If CCK != 1M then set short preamble rate flag. */ rates[i].flags |= (iwl3945_rates[i].plcp == 10) ? - IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + 0 : IEEE80211_RATE_SHORT_PREAMBLE; } - - /* Set up which ones are basic rates... */ - if (IWL_BASIC_RATES_MASK & (1 << i)) - rates[i].flags |= IEEE80211_RATE_BASIC; } } @@ -5363,143 +5058,117 @@ static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, static int iwl3945_init_geos(struct iwl3945_priv *priv) { struct iwl3945_channel_info *ch; - struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band *sband; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; - enum { - A = 0, - B = 1, - G = 2, - }; - int mode_count = 3; - if (priv->modes) { + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO("Geography modes already initialized.\n"); set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; } - modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, - GFP_KERNEL); - if (!modes) - return -ENOMEM; - channels = kzalloc(sizeof(struct ieee80211_channel) * priv->channel_count, GFP_KERNEL); - if (!channels) { - kfree(modes); + if (!channels) return -ENOMEM; - } - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), GFP_KERNEL); if (!rates) { - kfree(modes); kfree(channels); return -ENOMEM; } - /* 0 = 802.11a - * 1 = 802.11b - * 2 = 802.11g - */ - /* 5.2GHz channels start after the 2.4GHz channels */ - modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; - modes[A].rates = &rates[4]; - modes[A].num_rates = 8; /* just OFDM */ - modes[A].num_channels = 0; - - modes[B].mode = MODE_IEEE80211B; - modes[B].channels = channels; - modes[B].rates = rates; - modes[B].num_rates = 4; /* just CCK */ - modes[B].num_channels = 0; - - modes[G].mode = MODE_IEEE80211G; - modes[G].channels = channels; - modes[G].rates = rates; - modes[G].num_rates = 12; /* OFDM & CCK */ - modes[G].num_channels = 0; + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + sband->channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; + /* just OFDM */ + sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; + sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband->channels = channels; + /* OFDM & CCK */ + sband->bitrates = rates; + sband->n_bitrates = IWL_RATE_COUNT; priv->ieee_channels = channels; priv->ieee_rates = rates; iwl3945_init_hw_rates(priv, rates); - for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + for (i = 0; i < priv->channel_count; i++) { ch = &priv->channel_info[i]; - if (!is_channel_valid(ch)) { - IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " - "skipping.\n", - ch->channel, is_channel_a_band(ch) ? - "5.2" : "2.4"); + /* FIXME: might be removed if scan is OK*/ + if (!is_channel_valid(ch)) continue; - } if (is_channel_a_band(ch)) - geo_ch = &modes[A].channels[modes[A].num_channels++]; - else { - geo_ch = &modes[B].channels[modes[B].num_channels++]; - modes[G].num_channels++; - } + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + else + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + + geo_ch = &sband->channels[sband->n_channels++]; - geo_ch->freq = ieee80211chan2mhz(ch->channel); - geo_ch->chan = ch->channel; - geo_ch->power_level = ch->max_power_avg; - geo_ch->antenna_max = 0xff; + geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; + geo_ch->hw_value = ch->channel; if (is_channel_valid(ch)) { - geo_ch->flag = IEEE80211_CHAN_W_SCAN; - if (ch->flags & EEPROM_CHANNEL_IBSS) - geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - if (ch->flags & EEPROM_CHANNEL_ACTIVE) - geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + geo_ch->flags |= IEEE80211_CHAN_RADAR; if (ch->max_power_avg > priv->max_channel_txpower_limit) priv->max_channel_txpower_limit = ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - geo_ch->val = geo_ch->flag; + /* Save flags for reg domain usage */ + geo_ch->orig_flags = geo_ch->flags; + + IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", + ch->channel, geo_ch->center_freq, + is_channel_a_band(ch) ? "5.2" : "2.4", + geo_ch->flags & IEEE80211_CHAN_DISABLED ? + "restricted" : "valid", + geo_ch->flags); } - if ((modes[A].num_channels == 0) && priv->is_abg) { + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->cfg->sku & IWL_SKU_A) { printk(KERN_INFO DRV_NAME ": Incorrectly detected BG card as ABG. Please send " "your PCI ID 0x%04X:0x%04X to maintainer.\n", priv->pci_dev->device, priv->pci_dev->subsystem_device); - priv->is_abg = 0; + priv->cfg->sku &= ~IWL_SKU_A; } printk(KERN_INFO DRV_NAME ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - modes[G].num_channels, modes[A].num_channels); - - /* - * NOTE: We register these in preference of order -- the - * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick - * a phymode based on rates or AP capabilities but seems to - * configure it purely on if the channel being configured - * is supported by a mode -- and the first match is taken - */ + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); - if (modes[G].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[G]); - if (modes[B].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[B]); - if (modes[A].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[A]); + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; - priv->modes = modes; set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; @@ -5510,7 +5179,6 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) */ static void iwl3945_free_geos(struct iwl3945_priv *priv) { - kfree(priv->modes); kfree(priv->ieee_channels); kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); @@ -5837,7 +5505,7 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) int ret = 0; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ - const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode"; + const char *name = priv->cfg->fw_name; u8 *src; size_t len; u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; @@ -6209,6 +5877,8 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) iwl3945_reg_txpower_periodic(priv); + iwl3945_led_register(priv); + IWL_DEBUG_INFO("ALIVE processing complete.\n"); set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); @@ -6216,6 +5886,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (priv->error_recovering) iwl3945_error_recovery(priv); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); return; restart: @@ -6237,6 +5908,7 @@ static void __iwl3945_down(struct iwl3945_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); + iwl3945_led_unregister(priv); iwl3945_clear_stations_table(priv); /* Unblock any waiting calls */ @@ -6251,7 +5923,10 @@ static void __iwl3945_down(struct iwl3945_priv *priv) iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); @@ -6519,7 +6194,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u8 direct_mask; - int phymode; + enum ieee80211_band band; conf = ieee80211_get_hw_conf(priv->hw); @@ -6651,13 +6326,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; scan->tx_cmd.rate = IWL_RATE_1M_PLCP; scan->good_CRC_th = 0; - phymode = MODE_IEEE80211G; + band = IEEE80211_BAND_2GHZ; break; case 1: scan->tx_cmd.rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; - phymode = MODE_IEEE80211A; + band = IEEE80211_BAND_5GHZ; break; default: @@ -6671,18 +6346,23 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; - if (direct_mask) + if (direct_mask) { IWL_DEBUG_SCAN ("Initiating direct scan for %s.\n", iwl3945_escape_essid(priv->essid, priv->essid_len)); - else + scan->channel_count = + iwl3945_get_channels_for_scan( + priv, band, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + } else { IWL_DEBUG_SCAN("Initiating indirect scan.\n"); - - scan->channel_count = - iwl3945_get_channels_for_scan( - priv, phymode, 1, /* active */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + scan->channel_count = + iwl3945_get_channels_for_scan( + priv, band, 0, /* passive */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + } cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl3945_scan_channel); @@ -6825,7 +6505,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, - (priv->phymode == MODE_IEEE80211A)? + (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, CMD_ASYNC); iwl3945_rate_scale_init(priv->hw, IWL_STA_ID); @@ -6841,9 +6521,8 @@ static void iwl3945_bg_post_associate(struct work_struct *data) iwl3945_sequence_reset(priv); -#ifdef CONFIG_IWL3945_QOS iwl3945_activate_qos(priv, 0); -#endif /* CONFIG_IWL3945_QOS */ + /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; mutex_unlock(&priv->mutex); @@ -7020,7 +6699,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate); + ctl->tx_rate->bitrate); if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); @@ -7079,7 +6758,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co int ret = 0; mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); @@ -7099,19 +6778,20 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl3945_get_channel_info(priv, conf->channel->band, + conf->channel->hw_value); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", - conf->channel, conf->phymode); + conf->channel->hw_value, conf->channel->band); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); ret = -EINVAL; goto out; } - iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel); + iwl3945_set_rxon_channel(priv, conf->channel->band, conf->channel->hw_value); - iwl3945_set_flags_for_phymode(priv, conf->phymode); + iwl3945_set_flags_for_phymode(priv, conf->channel->band); /* The list of supported rates and rate mask can be different * for each phymode; since the phymode may have changed, reset @@ -7225,6 +6905,12 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (conf == NULL) return -EIO; + if (priv->vif != vif) { + IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); + mutex_unlock(&priv->mutex); + return 0; + } + /* XXX: this MUST use conf->mac_addr */ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && @@ -7249,17 +6935,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { - IWL_DEBUG_MAC80211("leave - scanning\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); - mutex_unlock(&priv->mutex); - return 0; - } if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { if (!conf->bssid) { @@ -7487,10 +7162,8 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { struct iwl3945_priv *priv = hw->priv; -#ifdef CONFIG_IWL3945_QOS unsigned long flags; int q; -#endif /* CONFIG_IWL3945_QOS */ IWL_DEBUG_MAC80211("enter\n"); @@ -7504,7 +7177,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, return 0; } -#ifdef CONFIG_IWL3945_QOS if (!priv->qos_data.qos_enable) { priv->qos_data.qos_active = 0; IWL_DEBUG_MAC80211("leave - qos not enabled\n"); @@ -7518,7 +7190,7 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->burst_time * 100)); + cpu_to_le16((params->txop * 32)); priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; @@ -7533,8 +7205,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, mutex_unlock(&priv->mutex); -#endif /*CONFIG_IWL3945_QOS */ - IWL_DEBUG_MAC80211("leave\n"); return 0; } @@ -7599,9 +7269,8 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); -#ifdef CONFIG_IWL3945_QOS iwl3945_reset_qos(priv); -#endif + cancel_delayed_work(&priv->post_associate); spin_lock_irqsave(&priv->lock, flags); @@ -7689,9 +7358,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWL3945_QOS iwl3945_reset_qos(priv); -#endif queue_work(priv->workqueue, &priv->post_associate.work); @@ -7892,65 +7559,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t show_tune(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", - (priv->phymode << 8) | - le16_to_cpu(priv->active_rxon.channel)); -} - -static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode); - -static ssize_t store_tune(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - char *p = (char *)buf; - u16 tune = simple_strtoul(p, &p, 0); - u8 phymode = (tune >> 8) & 0xff; - u16 channel = tune & 0xff; - - IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); - - mutex_lock(&priv->mutex); - if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || - (priv->phymode != phymode)) { - const struct iwl3945_channel_info *ch_info; - - ch_info = iwl3945_get_channel_info(priv, phymode, channel); - if (!ch_info) { - IWL_WARNING("Requested invalid phymode/channel " - "combination: %d %d\n", phymode, channel); - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - /* Cancel any currently running scans... */ - if (iwl3945_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing phymode and " - "rxon.channel = %d %d\n", - phymode, channel); - - iwl3945_set_rxon_channel(priv, phymode, channel); - iwl3945_set_flags_for_phymode(priv, phymode); - - iwl3945_set_rate(priv); - iwl3945_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); - #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT static ssize_t show_measurement(struct device *d, @@ -8024,31 +7632,6 @@ static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); #endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ -static ssize_t show_rate(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl3945_priv *priv = dev_get_drvdata(d); - unsigned long flags; - int i; - - spin_lock_irqsave(&priv->sta_lock, flags); - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) - i = priv->stations[IWL_AP_ID].current_rate.s.rate; - else - i = priv->stations[IWL_STA_ID].current_rate.s.rate; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - i = iwl3945_rate_index_from_plcp(i); - if (i == -1) - return sprintf(buf, "0\n"); - - return sprintf(buf, "%d%s\n", - (iwl3945_rates[i].ieee >> 1), - (iwl3945_rates[i].ieee & 0x1) ? ".5" : ""); -} - -static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL); - static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -8165,73 +7748,8 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl3945_priv *priv = dev_get_drvdata(d); - int len = 0, i; - struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode = NULL; - int count = 0; - - if (!iwl3945_is_ready(priv)) - return -EAGAIN; - - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G); - if (!hw_mode) - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } - - len += - sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } else { - channels = NULL; - count = 0; - } - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - return len; + /* all this shit doesn't belong into sysfs anyway */ + return 0; } static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); @@ -8404,14 +7922,12 @@ static struct attribute *iwl3945_sysfs_entries[] = { &dev_attr_measurement.attr, #endif &dev_attr_power_level.attr, - &dev_attr_rate.attr, &dev_attr_retry_rate.attr, &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, - &dev_attr_tune.attr, &dev_attr_tx_power.attr, NULL @@ -8444,10 +7960,11 @@ static struct ieee80211_ops iwl3945_hw_ops = { static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; - u32 pci_id; struct iwl3945_priv *priv; struct ieee80211_hw *hw; + struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); int i; + unsigned long flags; DECLARE_MAC_BUF(mac); /* Disabling hardware scan means that mac80211 will perform scans @@ -8482,6 +7999,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->hw = hw; priv->pci_dev = pdev; + priv->cfg = cfg; /* Select antenna (may be helpful if only one antenna is connected) */ priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; @@ -8532,7 +8050,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; - priv->phymode = -1; + priv->band = IEEE80211_BAND_2GHZ; err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) @@ -8571,32 +8089,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->iw_mode = IEEE80211_IF_TYPE_STA; - pci_id = - (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device; - - switch (pci_id) { - case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */ - case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */ - case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */ - case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */ - priv->is_abg = 0; - break; - - /* - * Rest are assumed ABG SKU -- if this is not the - * case then the card will get the wrong 'Detected' - * line in the kernel log however the code that - * initializes the GEO table will detect no A-band - * channels and remove the is_abg mask. - */ - default: - priv->is_abg = 1; - break; - } - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n", - priv->is_abg ? "A" : ""); + ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); /* Device-specific setup */ if (iwl3945_hw_set_hw_setting(priv)) { @@ -8604,7 +8098,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e goto out_iounmap; } -#ifdef CONFIG_IWL3945_QOS if (iwl3945_param_qos_enable) priv->qos_data.qos_enable = 1; @@ -8612,9 +8105,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; -#endif /* CONFIG_IWL3945_QOS */ - iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); iwl3945_setup_deferred_work(priv); iwl3945_setup_rx_handlers(priv); @@ -8623,7 +8115,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + spin_lock_irqsave(&priv->lock, flags); iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); if (err) { @@ -8665,9 +8159,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_ERROR("initializing geos failed: %d\n", err); goto out_free_channel_map; } - iwl3945_reset_channel_flag(priv); - iwl3945_rate_control_register(priv->hw); err = ieee80211_register_hw(priv->hw); if (err) { IWL_ERROR("Failed to register network device (error %d)\n", err); @@ -8711,6 +8203,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) struct iwl3945_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; int i; + unsigned long flags; if (!priv) return; @@ -8721,6 +8214,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_down(priv); + /* make sure we flush any pending irq or + * tasklet for the driver + */ + spin_lock_irqsave(&priv->lock, flags); + iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_synchronize_irq(priv); + /* Free MAC hash list for ADHOC */ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { @@ -8742,7 +8244,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); - iwl3945_rate_control_unregister(priv->hw); } /*netif_stop_queue(dev); */ @@ -8823,21 +8324,35 @@ static int __init iwl3945_init(void) int ret; printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + ret = iwl3945_rate_control_register(); + if (ret) { + IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); + return ret; + } + ret = pci_register_driver(&iwl3945_driver); if (ret) { IWL_ERROR("Unable to initialize PCI module\n"); - return ret; + goto error_register; } #ifdef CONFIG_IWL3945_DEBUG ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level); if (ret) { IWL_ERROR("Unable to create driver sysfs file\n"); - pci_unregister_driver(&iwl3945_driver); - return ret; + goto error_debug; } #endif return ret; + +#ifdef CONFIG_IWL3945_DEBUG +error_debug: + pci_unregister_driver(&iwl3945_driver); +#endif +error_register: + iwl3945_rate_control_unregister(); + return ret; } static void __exit iwl3945_exit(void) @@ -8846,6 +8361,7 @@ static void __exit iwl3945_exit(void) driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level); #endif pci_unregister_driver(&iwl3945_driver); + iwl3945_rate_control_unregister(); } module_param_named(antenna, iwl3945_param_antenna, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 60ec29eab85..06e44dad5f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -45,14 +45,13 @@ #include <asm/div64.h> +#include "iwl-eeprom.h" #include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-io.h" #include "iwl-helpers.h" -#ifdef CONFIG_IWL4965_DEBUG -u32 iwl4965_debug_level; -#endif - -static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, +static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); /****************************************************************************** @@ -61,16 +60,6 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, * ******************************************************************************/ -/* module parameters */ -static int iwl4965_param_disable_hw_scan; /* def: 0 = use 4965's h/w scan */ -static int iwl4965_param_debug; /* def: 0 = minimal debug log messages */ -static int iwl4965_param_disable; /* def: enable radio */ -static int iwl4965_param_antenna; /* def: 0 = both antennas (use diversity) */ -int iwl4965_param_hwcrypto; /* def: using software encryption */ -static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */ -int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */ -int iwl4965_param_amsdu_size_8K; /* def: enable 8K amsdu size */ - /* * module name, copyright, version, etc. * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk @@ -78,7 +67,7 @@ int iwl4965_param_amsdu_size_8K; /* def: enable 8K amsdu size */ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux" -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG #define VD "d" #else #define VD @@ -90,15 +79,8 @@ int iwl4965_param_amsdu_size_8K; /* def: enable 8K amsdu size */ #define VS #endif -#define IWLWIFI_VERSION "1.2.23k" VD VS -#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" -#define DRV_VERSION IWLWIFI_VERSION +#define DRV_VERSION IWLWIFI_VERSION VD VS -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL4965_UCODE_API "-1" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); @@ -115,16 +97,10 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl4965_get_hw_mode( - struct iwl4965_priv *priv, int mode) +static const struct ieee80211_supported_band *iwl4965_get_hw_mode( + struct iwl_priv *priv, enum ieee80211_band band) { - int i; - - for (i = 0; i < 3; i++) - if (priv->modes[i].mode == mode) - return &priv->modes[i]; - - return NULL; + return priv->hw->wiphy->bands[band]; } static int iwl4965_is_empty_essid(const char *essid, int essid_len) @@ -167,17 +143,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) return escaped; } -static void iwl4965_print_hex_dump(int level, void *p, u32 len) -{ -#ifdef CONFIG_IWL4965_DEBUG - if (!(iwl4965_debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -#endif -} - /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -205,7 +170,7 @@ static void iwl4965_print_hex_dump(int level, void *p, u32 len) * See more detailed info in iwl-4965-hw.h. ***************************************************/ -static int iwl4965_queue_space(const struct iwl4965_queue *q) +int iwl4965_queue_space(const struct iwl4965_queue *q) { int s = q->read_ptr - q->write_ptr; @@ -221,25 +186,6 @@ static int iwl4965_queue_space(const struct iwl4965_queue *q) return s; } -/** - * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning - * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) - */ -static inline int iwl4965_queue_inc_wrap(int index, int n_bd) -{ - return ++index & (n_bd - 1); -} - -/** - * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end - * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) - */ -static inline int iwl4965_queue_dec_wrap(int index, int n_bd) -{ - return --index & (n_bd - 1); -} static inline int x2_queue_used(const struct iwl4965_queue *q, int i) { @@ -261,15 +207,15 @@ static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge) /** * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes */ -static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q, +static int iwl4965_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; q->n_window = slots_num; q->id = id; - /* count must be power-of-two size, otherwise iwl4965_queue_inc_wrap - * and iwl4965_queue_dec_wrap are broken. */ + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ BUG_ON(!is_power_of_2(count)); /* slots_num must be power-of-two size, otherwise @@ -292,7 +238,7 @@ static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q /** * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue */ -static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv, +static int iwl4965_tx_queue_alloc(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, u32 id) { struct pci_dev *dev = priv->pci_dev; @@ -337,7 +283,7 @@ static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv, /** * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue */ -int iwl4965_tx_queue_init(struct iwl4965_priv *priv, +int iwl4965_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id) { struct pci_dev *dev = priv->pci_dev; @@ -352,7 +298,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, * For normal Tx queues (all other queues), no super-size command * space is needed. */ - len = sizeof(struct iwl4965_cmd) * slots_num; + len = sizeof(struct iwl_cmd) * slots_num; if (txq_id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); @@ -369,7 +315,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, txq->need_update = 0; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */ + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); /* Initialize queue's high/low-water marks, and head/tail indexes */ @@ -389,7 +335,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv, * Free all buffers. * 0-fill, but do not free "txq" descriptor structure. */ -void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) +void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) { struct iwl4965_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; @@ -400,10 +346,10 @@ void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *t /* first, empty all BD's */ for (; q->write_ptr != q->read_ptr; - q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) iwl4965_hw_txq_free_tfd(priv, txq); - len = sizeof(struct iwl4965_cmd) * q->n_window; + len = sizeof(struct iwl_cmd) * q->n_window; if (q->id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; @@ -440,7 +386,7 @@ const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF * * NOTE: This does not remove station from device's station table. */ -static u8 iwl4965_remove_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) +static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; int i; @@ -478,26 +424,9 @@ out: #endif /** - * iwl4965_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -static void iwl4965_clear_stations_table(struct iwl4965_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->num_stations = 0; - memset(priv->stations, 0, sizeof(priv->stations)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -/** * iwl4965_add_station_flags - Add station to tables in driver and device */ -u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, +u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, void *ht_data) { int i; @@ -567,103 +496,10 @@ u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, } -/*************** DRIVER STATUS FUNCTIONS *****/ - -static inline int iwl4965_is_ready(struct iwl4965_priv *priv) -{ - /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are - * set but EXIT_PENDING is not */ - return test_bit(STATUS_READY, &priv->status) && - test_bit(STATUS_GEO_CONFIGURED, &priv->status) && - !test_bit(STATUS_EXIT_PENDING, &priv->status); -} - -static inline int iwl4965_is_alive(struct iwl4965_priv *priv) -{ - return test_bit(STATUS_ALIVE, &priv->status); -} -static inline int iwl4965_is_init(struct iwl4965_priv *priv) -{ - return test_bit(STATUS_INIT, &priv->status); -} - -static inline int iwl4965_is_rfkill(struct iwl4965_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); -} - -static inline int iwl4965_is_ready_rf(struct iwl4965_priv *priv) -{ - - if (iwl4965_is_rfkill(priv)) - return 0; - - return iwl4965_is_ready(priv); -} /*************** HOST COMMAND QUEUE FUNCTIONS *****/ -#define IWL_CMD(x) case x : return #x - -static const char *get_cmd_string(u8 cmd) -{ - switch (cmd) { - IWL_CMD(REPLY_ALIVE); - IWL_CMD(REPLY_ERROR); - IWL_CMD(REPLY_RXON); - IWL_CMD(REPLY_RXON_ASSOC); - IWL_CMD(REPLY_QOS_PARAM); - IWL_CMD(REPLY_RXON_TIMING); - IWL_CMD(REPLY_ADD_STA); - IWL_CMD(REPLY_REMOVE_STA); - IWL_CMD(REPLY_REMOVE_ALL_STA); - IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); - IWL_CMD(REPLY_LEDS_CMD); - IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); - IWL_CMD(RADAR_NOTIFICATION); - IWL_CMD(REPLY_QUIET_CMD); - IWL_CMD(REPLY_CHANNEL_SWITCH); - IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); - IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); - IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); - IWL_CMD(POWER_TABLE_CMD); - IWL_CMD(PM_SLEEP_NOTIFICATION); - IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); - IWL_CMD(REPLY_SCAN_CMD); - IWL_CMD(REPLY_SCAN_ABORT_CMD); - IWL_CMD(SCAN_START_NOTIFICATION); - IWL_CMD(SCAN_RESULTS_NOTIFICATION); - IWL_CMD(SCAN_COMPLETE_NOTIFICATION); - IWL_CMD(BEACON_NOTIFICATION); - IWL_CMD(REPLY_TX_BEACON); - IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); - IWL_CMD(QUIET_NOTIFICATION); - IWL_CMD(REPLY_TX_PWR_TABLE_CMD); - IWL_CMD(MEASURE_ABORT_NOTIFICATION); - IWL_CMD(REPLY_BT_CONFIG); - IWL_CMD(REPLY_STATISTICS_CMD); - IWL_CMD(STATISTICS_NOTIFICATION); - IWL_CMD(REPLY_CARD_STATE_CMD); - IWL_CMD(CARD_STATE_NOTIFICATION); - IWL_CMD(MISSED_BEACONS_NOTIFICATION); - IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); - IWL_CMD(SENSITIVITY_CMD); - IWL_CMD(REPLY_PHY_CALIBRATION_CMD); - IWL_CMD(REPLY_RX_PHY_CMD); - IWL_CMD(REPLY_RX_MPDU_CMD); - IWL_CMD(REPLY_4965_RX); - IWL_CMD(REPLY_COMPRESSED_BA); - default: - return "UNKNOWN"; - - } -} - -#define HOST_COMPLETE_TIMEOUT (HZ / 2) - /** * iwl4965_enqueue_hcmd - enqueue a uCode command * @priv: device private data point @@ -673,13 +509,13 @@ static const char *get_cmd_string(u8 cmd) * failed. On success, it turns the index (> 0) of command in the * command queue. */ -static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) +int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl4965_queue *q = &txq->q; struct iwl4965_tfd_frame *tfd; u32 *control_flags; - struct iwl4965_cmd *out_cmd; + struct iwl_cmd *out_cmd; u32 idx; u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); dma_addr_t phys_addr; @@ -692,7 +528,7 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); - if (iwl4965_is_rfkill(priv)) { + if (iwl_is_rfkill(priv)) { IWL_DEBUG_INFO("Not sending command - RF KILL"); return -EIO; } @@ -726,7 +562,7 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl4965_cmd, hdr); + offsetof(struct iwl_cmd, hdr); iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " @@ -741,158 +577,29 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); /* Increment and update queue's write index */ - q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd); + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl4965_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); return ret ? ret : idx; } -static int iwl4965_send_cmd_async(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) -{ - int ret; - - BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); - - /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->meta.flags & CMD_WANT_SKB); - - /* An asynchronous command MUST have a callback. */ - BUG_ON(!cmd->meta.u.callback); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return -EBUSY; - - ret = iwl4965_enqueue_hcmd(priv, cmd); - if (ret < 0) { - IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), ret); - return ret; - } - return 0; -} - -static int iwl4965_send_cmd_sync(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) +static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { - int cmd_idx; - int ret; - static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ - - BUG_ON(cmd->meta.flags & CMD_ASYNC); - - /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->meta.u.callback != NULL); - - if (atomic_xchg(&entry, 1)) { - IWL_ERROR("Error sending %s: Already sending a host command\n", - get_cmd_string(cmd->id)); - return -EBUSY; - } - - set_bit(STATUS_HCMD_ACTIVE, &priv->status); - - if (cmd->meta.flags & CMD_WANT_SKB) - cmd->meta.source = &cmd->meta; - - cmd_idx = iwl4965_enqueue_hcmd(priv, cmd); - if (cmd_idx < 0) { - ret = cmd_idx; - IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), ret); - goto out; - } - - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - !test_bit(STATUS_HCMD_ACTIVE, &priv->status), - HOST_COMPLETE_TIMEOUT); - if (!ret) { - if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { - IWL_ERROR("Error sending %s: time out after %dms.\n", - get_cmd_string(cmd->id), - jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - ret = -ETIMEDOUT; - goto cancel; - } - } - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", - get_cmd_string(cmd->id)); - ret = -ECANCELED; - goto fail; - } - if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_DEBUG_INFO("Command %s failed: FW Error\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto fail; - } - if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { - IWL_ERROR("Error: Response NULL in '%s'\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto out; - } - - ret = 0; - goto out; - -cancel: - if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl4965_cmd *qcmd; - - /* Cancel the CMD_WANT_SKB flag for the cmd in the - * TX cmd queue. Otherwise in case the cmd comes - * in later, it will possibly set an invalid - * address (cmd->meta.source). */ - qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; - qcmd->meta.flags &= ~CMD_WANT_SKB; - } -fail: - if (cmd->meta.u.skb) { - dev_kfree_skb_any(cmd->meta.u.skb); - cmd->meta.u.skb = NULL; - } -out: - atomic_set(&entry, 0); - return ret; -} - -int iwl4965_send_cmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) -{ - if (cmd->meta.flags & CMD_ASYNC) - return iwl4965_send_cmd_async(priv, cmd); - - return iwl4965_send_cmd_sync(priv, cmd); -} - -int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len, const void *data) -{ - struct iwl4965_host_cmd cmd = { - .id = id, - .len = len, - .data = data, - }; - - return iwl4965_send_cmd_sync(priv, &cmd); -} + struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; -static int __must_check iwl4965_send_cmd_u32(struct iwl4965_priv *priv, u8 id, u32 val) -{ - struct iwl4965_host_cmd cmd = { - .id = id, - .len = sizeof(val), - .data = &val, - }; + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; - return iwl4965_send_cmd_sync(priv, &cmd); } -int iwl4965_send_statistics_request(struct iwl4965_priv *priv) +int iwl4965_send_statistics_request(struct iwl_priv *priv) { - return iwl4965_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); + u32 flags = 0; + return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, + sizeof(flags), &flags); } /** @@ -901,7 +608,7 @@ int iwl4965_send_statistics_request(struct iwl4965_priv *priv) * there is only one AP station with id= IWL_AP_ID * NOTE: mutex must be held before calling this fnction */ -static int iwl4965_rxon_add_station(struct iwl4965_priv *priv, +static int iwl4965_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { u8 sta_id; @@ -928,42 +635,6 @@ static int iwl4965_rxon_add_station(struct iwl4965_priv *priv, } /** - * iwl4965_set_rxon_channel - Set the phymode and channel values in staging RXON - * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz - * @channel: Any channel valid for the requested phymode - - * In addition to setting the staging RXON, priv->phymode is also set. - * - * NOTE: Does not commit to the hardware; it sets appropriate bit fields - * in the staging RXON flag structure based on the phymode - */ -static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode, - u16 channel) -{ - if (!iwl4965_get_channel_info(priv, phymode, channel)) { - IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", - channel, phymode); - return -EINVAL; - } - - if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && - (priv->phymode == phymode)) - return 0; - - priv->staging_rxon.channel = cpu_to_le16(channel); - if (phymode == MODE_IEEE80211A) - priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; - else - priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - - priv->phymode = phymode; - - IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); - - return 0; -} - -/** * iwl4965_check_rxon_cmd - validate RXON structure is valid * * NOTE: This is really only useful during development and can eventually @@ -1044,7 +715,7 @@ static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon) * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. */ -static int iwl4965_full_rxon_required(struct iwl4965_priv *priv) +static int iwl4965_full_rxon_required(struct iwl_priv *priv) { /* These items are only settable from the full RXON command */ @@ -1084,12 +755,12 @@ static int iwl4965_full_rxon_required(struct iwl4965_priv *priv) return 0; } -static int iwl4965_send_rxon_assoc(struct iwl4965_priv *priv) +static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) { int rc = 0; struct iwl4965_rx_packet *res = NULL; struct iwl4965_rxon_assoc_cmd rxon_assoc; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), .meta.flags = CMD_WANT_SKB, @@ -1122,7 +793,7 @@ static int iwl4965_send_rxon_assoc(struct iwl4965_priv *priv) priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; - rc = iwl4965_send_cmd_sync(priv, &cmd); + rc = iwl_send_cmd_sync(priv, &cmd); if (rc) return rc; @@ -1146,14 +817,14 @@ static int iwl4965_send_rxon_assoc(struct iwl4965_priv *priv) * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl4965_commit_rxon(struct iwl4965_priv *priv) +static int iwl4965_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); int rc = 0; - if (!iwl4965_is_alive(priv)) + if (!iwl_is_alive(priv)) return -1; /* always get timestamp with Rx frame */ @@ -1196,12 +867,12 @@ static int iwl4965_commit_rxon(struct iwl4965_priv *priv) * an RXON_ASSOC and the new config wants the associated mask enabled, * we must clear the associated from the active configuration * before we apply the new config */ - if (iwl4965_is_associated(priv) && + if (iwl_is_associated(priv) && (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON, + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl4965_rxon_cmd), &priv->active_rxon); @@ -1224,15 +895,16 @@ static int iwl4965_commit_rxon(struct iwl4965_priv *priv) le16_to_cpu(priv->staging_rxon.channel), print_mac(mac, priv->staging_rxon.bssid_addr)); + iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto); /* Apply the new configuration */ - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON, + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); return rc; } - iwl4965_clear_stations_table(priv); + iwlcore_clear_stations_table(priv); #ifdef CONFIG_IWL4965_SENSITIVITY if (!priv->error_recovering) @@ -1261,7 +933,7 @@ static int iwl4965_commit_rxon(struct iwl4965_priv *priv) /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ - if (iwl4965_is_associated(priv) && + if (iwl_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) == IWL_INVALID_STATION) { @@ -1274,7 +946,7 @@ static int iwl4965_commit_rxon(struct iwl4965_priv *priv) return 0; } -static int iwl4965_send_bt_config(struct iwl4965_priv *priv) +static int iwl4965_send_bt_config(struct iwl_priv *priv) { struct iwl4965_bt_cmd bt_cmd = { .flags = 3, @@ -1284,15 +956,15 @@ static int iwl4965_send_bt_config(struct iwl4965_priv *priv) .kill_cts_mask = 0, }; - return iwl4965_send_cmd_pdu(priv, REPLY_BT_CONFIG, + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(struct iwl4965_bt_cmd), &bt_cmd); } -static int iwl4965_send_scan_abort(struct iwl4965_priv *priv) +static int iwl4965_send_scan_abort(struct iwl_priv *priv) { int rc = 0; struct iwl4965_rx_packet *res; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, }; @@ -1305,7 +977,7 @@ static int iwl4965_send_scan_abort(struct iwl4965_priv *priv) return 0; } - rc = iwl4965_send_cmd_sync(priv, &cmd); + rc = iwl_send_cmd_sync(priv, &cmd); if (rc) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return rc; @@ -1329,8 +1001,8 @@ static int iwl4965_send_scan_abort(struct iwl4965_priv *priv) return rc; } -static int iwl4965_card_state_sync_callback(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, +static int iwl4965_card_state_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) { return 1; @@ -1346,9 +1018,9 @@ static int iwl4965_card_state_sync_callback(struct iwl4965_priv *priv, * When in the 'halt' state, the card is shut down and must be fully * restarted to come back on. */ -static int iwl4965_send_card_state(struct iwl4965_priv *priv, u32 flags, u8 meta_flag) +static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) { - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, @@ -1358,11 +1030,11 @@ static int iwl4965_send_card_state(struct iwl4965_priv *priv, u32 flags, u8 meta if (meta_flag & CMD_ASYNC) cmd.meta.u.callback = iwl4965_card_state_sync_callback; - return iwl4965_send_cmd(priv, &cmd); + return iwl_send_cmd(priv, &cmd); } -static int iwl4965_add_sta_sync_callback(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb) +static int iwl4965_add_sta_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl4965_rx_packet *res = NULL; @@ -1389,12 +1061,12 @@ static int iwl4965_add_sta_sync_callback(struct iwl4965_priv *priv, return 1; } -int iwl4965_send_add_station(struct iwl4965_priv *priv, +int iwl4965_send_add_station(struct iwl_priv *priv, struct iwl4965_addsta_cmd *sta, u8 flags) { struct iwl4965_rx_packet *res = NULL; int rc = 0; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, .len = sizeof(struct iwl4965_addsta_cmd), .meta.flags = flags, @@ -1406,7 +1078,7 @@ int iwl4965_send_add_station(struct iwl4965_priv *priv, else cmd.meta.flags |= CMD_WANT_SKB; - rc = iwl4965_send_cmd(priv, &cmd); + rc = iwl_send_cmd(priv, &cmd); if (rc || (flags & CMD_ASYNC)) return rc; @@ -1436,33 +1108,36 @@ int iwl4965_send_add_station(struct iwl4965_priv *priv, return rc; } -static int iwl4965_update_sta_key_info(struct iwl4965_priv *priv, +static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) { unsigned long flags; __le16 key_flags = 0; - switch (keyconf->alg) { - case ALG_CCMP: - key_flags |= STA_KEY_FLG_CCMP; - key_flags |= cpu_to_le16( - keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - break; - case ALG_TKIP: - case ALG_WEP: - default: - return -EINVAL; - } + key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + + if (sta_id == priv->hw_setting.bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->hw_key_idx = keyconf->keyidx; + + key_flags &= ~STA_KEY_FLG_INVALID; + spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, keyconf->keylen); memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); + + priv->stations[sta_id].sta.key.key_offset + = (sta_id % STA_KEY_MAX_NUM);/*FIXME*/ priv->stations[sta_id].sta.key.key_flags = key_flags; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; @@ -1470,11 +1145,38 @@ static int iwl4965_update_sta_key_info(struct iwl4965_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); - iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); - return 0; + return iwl4965_send_add_station(priv, + &priv->stations[sta_id].sta, CMD_ASYNC); } -static int iwl4965_clear_sta_key_info(struct iwl4965_priv *priv, u8 sta_id) +static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + int ret = 0; + + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + keyconf->hw_key_idx = keyconf->keyidx; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.conf = keyconf; + priv->stations[sta_id].keyinfo.keylen = 16; + + /* This copy is acutally not needed: we get the key with each TX */ + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return ret; +} + +static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) { unsigned long flags; @@ -1491,7 +1193,47 @@ static int iwl4965_clear_sta_key_info(struct iwl4965_priv *priv, u8 sta_id) return 0; } -static void iwl4965_clear_free_frames(struct iwl4965_priv *priv) +static int iwl4965_set_dynamic_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key, u8 sta_id) +{ + int ret; + + switch (key->alg) { + case ALG_CCMP: + ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id); + break; + case ALG_TKIP: + ret = iwl4965_set_tkip_dynamic_key_info(priv, key, sta_id); + break; + case ALG_WEP: + ret = -EOPNOTSUPP; + break; + default: + IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); + ret = -EINVAL; + } + + return ret; +} + +static int iwl4965_remove_static_key(struct iwl_priv *priv) +{ + int ret = -EOPNOTSUPP; + + return ret; +} + +static int iwl4965_set_static_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key) +{ + if (key->alg == ALG_WEP) + return -EOPNOTSUPP; + + IWL_ERROR("Static key invalid: alg %d\n", key->alg); + return -EINVAL; +} + +static void iwl4965_clear_free_frames(struct iwl_priv *priv) { struct list_head *element; @@ -1512,7 +1254,7 @@ static void iwl4965_clear_free_frames(struct iwl4965_priv *priv) } } -static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl4965_priv *priv) +static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv) { struct iwl4965_frame *frame; struct list_head *element; @@ -1532,18 +1274,18 @@ static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl4965_priv *priv) return list_entry(element, struct iwl4965_frame, list); } -static void iwl4965_free_frame(struct iwl4965_priv *priv, struct iwl4965_frame *frame) +static void iwl4965_free_frame(struct iwl_priv *priv, struct iwl4965_frame *frame) { memset(frame, 0, sizeof(*frame)); list_add(&frame->list, &priv->free_frames); } -unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv, +unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left) { - if (!iwl4965_is_associated(priv) || !priv->ibss_beacon || + if (!iwl_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && (priv->iw_mode != IEEE80211_IF_TYPE_AP))) return 0; @@ -1556,34 +1298,6 @@ unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv, return priv->ibss_beacon->len; } -int iwl4965_rate_index_from_plcp(int plcp) -{ - int i = 0; - - /* 4965 HT rate format */ - if (plcp & RATE_MCS_HT_MSK) { - i = (plcp & 0xff); - - if (i >= IWL_RATE_MIMO_6M_PLCP) - i = i - IWL_RATE_MIMO_6M_PLCP; - - i += IWL_FIRST_OFDM_RATE; - /* skip 9M not supported in ht*/ - if (i >= IWL_RATE_9M_INDEX) - i += 1; - if ((i >= IWL_FIRST_OFDM_RATE) && - (i <= IWL_LAST_OFDM_RATE)) - return i; - - /* 4965 legacy rate format, search for match in table */ - } else { - for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++) - if (iwl4965_rates[i].plcp == (plcp &0xFF)) - return i; - } - return -1; -} - static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) { u8 i; @@ -1597,7 +1311,7 @@ static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) return IWL_RATE_INVALID; } -static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv) +static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) { struct iwl4965_frame *frame; unsigned int frame_size; @@ -1625,7 +1339,7 @@ static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv) frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); - rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); iwl4965_free_frame(priv, frame); @@ -1635,232 +1349,11 @@ static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv) /****************************************************************************** * - * EEPROM related functions - * - ******************************************************************************/ - -static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac) -{ - memcpy(mac, priv->eeprom.mac_address, 6); -} - -static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv) -{ - iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); -} - -/** - * iwl4965_eeprom_init - read EEPROM contents - * - * Load the EEPROM contents from adapter into priv->eeprom - * - * NOTE: This routine uses the non-debug IO access functions. - */ -int iwl4965_eeprom_init(struct iwl4965_priv *priv) -{ - u16 *e = (u16 *)&priv->eeprom; - u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP); - u32 r; - int sz = sizeof(priv->eeprom); - int rc; - int i; - u16 addr; - - /* The EEPROM structure has several padding buffers within it - * and when adding new EEPROM maps is subject to programmer errors - * which may be very difficult to identify without explicitly - * checking the resulting size of the eeprom map. */ - BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); - - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { - IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); - return -ENOENT; - } - - /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - rc = iwl4965_eeprom_acquire_semaphore(priv); - if (rc < 0) { - IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); - return -ENOENT; - } - - /* eeprom is an array of 16bit values */ - for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); - - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } - - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { - IWL_ERROR("Time out reading EEPROM[%d]", addr); - rc = -ETIMEDOUT; - goto done; - } - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); - } - rc = 0; - -done: - iwl4965_eeprom_release_semaphore(priv); - return rc; -} - -/****************************************************************************** - * * Misc. internal state and helper functions * ******************************************************************************/ -#ifdef CONFIG_IWL4965_DEBUG -/** - * iwl4965_report_frame - dump frame to syslog during debug sessions - * - * You may hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: This was originally written for 3945, need to audit for - * proper operation with 4965. - */ -void iwl4965_report_frame(struct iwl4965_priv *priv, - struct iwl4965_rx_packet *pkt, - struct ieee80211_hdr *header, int group100) -{ - u32 to_us; - u32 print_summary = 0; - u32 print_dump = 0; /* set to 1 to dump all frames' contents */ - u32 hundred = 0; - u32 dataframe = 0; - u16 fc; - u16 seq_ctl; - u16 channel; - u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; - u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); - - /* MAC header */ - fc = le16_to_cpu(header->frame_control); - seq_ctl = le16_to_cpu(header->seq_ctrl); - - /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); - - /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); - - to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - - /* if data frame is to us and all is good, - * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { - dataframe = 1; - if (!group100) - print_summary = 1; /* print each frame */ - else if (priv->framecnt_to_us < 100) { - priv->framecnt_to_us++; - print_summary = 0; - } else { - priv->framecnt_to_us = 0; - print_summary = 1; - hundred = 1; - } - } else { - /* print summary for all other frames */ - print_summary = 1; - } - - if (print_summary) { - char *title; - u32 rate; - - if (hundred) - title = "100Frames"; - else if (fc & IEEE80211_FCTL_RETRY) - title = "Retry"; - else if (ieee80211_is_assoc_response(fc)) - title = "AscRsp"; - else if (ieee80211_is_reassoc_response(fc)) - title = "RasRsp"; - else if (ieee80211_is_probe_response(fc)) { - title = "PrbRsp"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_beacon(fc)) { - title = "Beacon"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_atim(fc)) - title = "ATIM"; - else if (ieee80211_is_auth(fc)) - title = "Auth"; - else if (ieee80211_is_deauth(fc)) - title = "DeAuth"; - else if (ieee80211_is_disassoc(fc)) - title = "DisAssoc"; - else - title = "Frame"; - - rate = iwl4965_rate_index_from_plcp(rate_sym); - if (rate == -1) - rate = 0; - else - rate = iwl4965_rates[rate].ieee / 2; - - /* print frame summary. - * MAC addresses show just the last byte (for brevity), - * but you can hack it to show more, if you'd like to. */ - if (dataframe) - IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " - "len=%u, rssi=%d, chnl=%d, rate=%u, \n", - title, fc, header->addr1[5], - length, rssi, channel, rate); - else { - /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " - "phy=0x%02x, chnl=%d\n", - title, fc, header->addr1[5], - header->addr3[5], rssi, - tsf_low - priv->scan_start_tsf, - phy_flags, channel); - } - } - if (print_dump) - iwl4965_print_hex_dump(IWL_DL_RX, data, length); -} -#endif - -static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv) +static void iwl4965_unset_hw_setting(struct iwl_priv *priv) { if (priv->hw_setting.shared_virt) pci_free_consistent(priv->pci_dev, @@ -1898,24 +1391,20 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate, return ret_rates; } -#ifdef CONFIG_IWL4965_HT -void static iwl4965_set_ht_capab(struct ieee80211_hw *hw, - struct ieee80211_ht_cap *ht_cap, - u8 use_current_config); -#endif - /** * iwl4965_fill_probe_req - fill in all required fields and IE for probe request */ -static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv, - struct ieee80211_mgmt *frame, - int left, int is_direct) +static u16 iwl4965_fill_probe_req(struct iwl_priv *priv, + enum ieee80211_band band, + struct ieee80211_mgmt *frame, + int left, int is_direct) { int len = 0; u8 *pos = NULL; u16 active_rates, ret_rates, cck_rates, active_rate_basic; #ifdef CONFIG_IWL4965_HT - struct ieee80211_hw_mode *mode; + const struct ieee80211_supported_band *sband = + iwl4965_get_hw_mode(priv, band); #endif /* CONFIG_IWL4965_HT */ /* Make sure there is enough space for the probe request, @@ -2000,13 +1489,18 @@ static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv, len += 2 + *pos; #ifdef CONFIG_IWL4965_HT - mode = priv->hw->conf.mode; - if (mode->ht_info.ht_supported) { + if (sband && sband->ht_info.ht_supported) { + struct ieee80211_ht_cap *ht_cap; pos += (*pos) + 1; *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); - iwl4965_set_ht_capab(priv->hw, - (struct ieee80211_ht_cap *)pos, 0); + ht_cap = (struct ieee80211_ht_cap *)pos; + ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); + memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); + ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor & + IEEE80211_HT_CAP_AMPDU_FACTOR) | + ((sband->ht_info.ampdu_density << 2) & + IEEE80211_HT_CAP_AMPDU_DENSITY); len += 2 + sizeof(struct ieee80211_ht_cap); } #endif /*CONFIG_IWL4965_HT */ @@ -2018,103 +1512,15 @@ static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv, /* * QoS support */ -#ifdef CONFIG_IWL4965_QOS -static int iwl4965_send_qos_params_command(struct iwl4965_priv *priv, +static int iwl4965_send_qos_params_command(struct iwl_priv *priv, struct iwl4965_qosparam_cmd *qos) { - return iwl4965_send_cmd_pdu(priv, REPLY_QOS_PARAM, + return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, sizeof(struct iwl4965_qosparam_cmd), qos); } -static void iwl4965_reset_qos(struct iwl4965_priv *priv) -{ - u16 cw_min = 15; - u16 cw_max = 1023; - u8 aifs = 2; - u8 is_legacy = 0; - unsigned long flags; - int i; - - spin_lock_irqsave(&priv->lock, flags); - priv->qos_data.qos_active = 0; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { - cw_min = 31; - is_legacy = 1; - } - - if (priv->qos_data.qos_active) - aifs = 3; - - priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); - priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; - priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; - priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; - - if (priv->qos_data.qos_active) { - i = 1; - priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); - priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[i].aifsn = 7; - priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - - i = 2; - priv->qos_data.def_qos_parm.ac[i].cw_min = - cpu_to_le16((cw_min + 1) / 2 - 1); - priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[i].aifsn = 2; - if (is_legacy) - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(6016); - else - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(3008); - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - - i = 3; - priv->qos_data.def_qos_parm.ac[i].cw_min = - cpu_to_le16((cw_min + 1) / 4 - 1); - priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16((cw_max + 1) / 2 - 1); - priv->qos_data.def_qos_parm.ac[i].aifsn = 2; - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - if (is_legacy) - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(3264); - else - priv->qos_data.def_qos_parm.ac[i].edca_txop = - cpu_to_le16(1504); - } else { - for (i = 1; i < 4; i++) { - priv->qos_data.def_qos_parm.ac[i].cw_min = - cpu_to_le16(cw_min); - priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16(cw_max); - priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; - priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; - priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; - } - } - IWL_DEBUG_QOS("set QoS to default \n"); - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force) +static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force) { unsigned long flags; @@ -2142,7 +1548,7 @@ static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force) spin_unlock_irqrestore(&priv->lock, flags); - if (force || iwl4965_is_associated(priv)) { + if (force || iwl_is_associated(priv)) { IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", priv->qos_data.qos_active, priv->qos_data.def_qos_parm.qos_flags); @@ -2152,7 +1558,6 @@ static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force) } } -#endif /* CONFIG_IWL4965_QOS */ /* * Power management (not Tx power!) functions */ @@ -2193,7 +1598,7 @@ static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = { SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; -int iwl4965_power_init_handle(struct iwl4965_priv *priv) +int iwl4965_power_init_handle(struct iwl_priv *priv) { int rc = 0, i; struct iwl4965_power_mgr *pow_data; @@ -2232,7 +1637,7 @@ int iwl4965_power_init_handle(struct iwl4965_priv *priv) return rc; } -static int iwl4965_update_power_cmd(struct iwl4965_priv *priv, +static int iwl4965_update_power_cmd(struct iwl_priv *priv, struct iwl4965_powertable_cmd *cmd, u32 mode) { int rc = 0, i; @@ -2296,7 +1701,7 @@ static int iwl4965_update_power_cmd(struct iwl4965_priv *priv, return rc; } -static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode) +static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode) { u32 uninitialized_var(final_mode); int rc; @@ -2321,7 +1726,7 @@ static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode) iwl4965_update_power_cmd(priv, &cmd, final_mode); - rc = iwl4965_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); @@ -2331,7 +1736,7 @@ static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode) return rc; } -int iwl4965_is_network_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header) +int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) { /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ @@ -2354,6 +1759,8 @@ int iwl4965_is_network_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *h return !compare_ether_addr(header->addr2, priv->bssid); /* packets to our adapter go through */ return !compare_ether_addr(header->addr1, priv->mac_addr); + default: + break; } return 1; @@ -2392,7 +1799,7 @@ static const char *iwl4965_get_tx_fail_reason(u32 status) * * NOTE: priv->mutex is not required before calling this function */ -static int iwl4965_scan_cancel(struct iwl4965_priv *priv) +static int iwl4965_scan_cancel(struct iwl_priv *priv) { if (!test_bit(STATUS_SCAN_HW, &priv->status)) { clear_bit(STATUS_SCANNING, &priv->status); @@ -2420,7 +1827,7 @@ static int iwl4965_scan_cancel(struct iwl4965_priv *priv) * * NOTE: priv->mutex must be held before calling this function */ -static int iwl4965_scan_cancel_timeout(struct iwl4965_priv *priv, unsigned long ms) +static int iwl4965_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) { unsigned long now = jiffies; int ret; @@ -2439,7 +1846,7 @@ static int iwl4965_scan_cancel_timeout(struct iwl4965_priv *priv, unsigned long return ret; } -static void iwl4965_sequence_reset(struct iwl4965_priv *priv) +static void iwl4965_sequence_reset(struct iwl_priv *priv) { /* Reset ieee stats */ @@ -2469,7 +1876,7 @@ static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) return cpu_to_le16(new_val); } -static void iwl4965_setup_rxon_timing(struct iwl4965_priv *priv) +static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) { u64 interval_tm_unit; u64 tsf, result; @@ -2480,13 +1887,13 @@ static void iwl4965_setup_rxon_timing(struct iwl4965_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1); - priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0); + priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32); + priv->rxon_timing.timestamp.dw[0] = + cpu_to_le32(priv->timestamp & 0xFFFFFFFF); priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; - tsf = priv->timestamp1; - tsf = ((tsf << 32) | priv->timestamp0); + tsf = priv->timestamp; beacon_int = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); @@ -2525,14 +1932,14 @@ static void iwl4965_setup_rxon_timing(struct iwl4965_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl4965_scan_initiate(struct iwl4965_priv *priv) +static int iwl4965_scan_initiate(struct iwl_priv *priv) { if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("APs don't scan.\n"); return 0; } - if (!iwl4965_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; } @@ -2559,21 +1966,11 @@ static int iwl4965_scan_initiate(struct iwl4965_priv *priv) return 0; } -static int iwl4965_set_rxon_hwcrypto(struct iwl4965_priv *priv, int hw_decrypt) -{ - struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; - if (hw_decrypt) - rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; - else - rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; - - return 0; -} - -static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode) +static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) { + if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_CCK_MSK); @@ -2597,9 +1994,9 @@ static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode) /* * initialize rxon structure with default values from eeprom */ -static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) +static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) { - const struct iwl4965_channel_info *ch_info; + const struct iwl_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); @@ -2625,6 +2022,9 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; + default: + IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + break; } #if 0 @@ -2636,7 +2036,7 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl4965_get_channel_info(priv, priv->phymode, + ch_info = iwl_get_channel_info(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2651,12 +2051,9 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) ch_info = &priv->channel_info[0]; priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); - if (is_channel_a_band(ch_info)) - priv->phymode = MODE_IEEE80211A; - else - priv->phymode = MODE_IEEE80211G; + priv->band = ch_info->band; - iwl4965_set_flags_for_phymode(priv, priv->phymode); + iwl4965_set_flags_for_phymode(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2672,13 +2069,13 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) iwl4965_set_rxon_chain(priv); } -static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode) +static int iwl4965_set_mode(struct iwl_priv *priv, int mode) { if (mode == IEEE80211_IF_TYPE_IBSS) { - const struct iwl4965_channel_info *ch_info; + const struct iwl_channel_info *ch_info; - ch_info = iwl4965_get_channel_info(priv, - priv->phymode, + ch_info = iwl_get_channel_info(priv, + priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info || !is_channel_ibss(ch_info)) { @@ -2693,10 +2090,10 @@ static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode) iwl4965_connection_init_rx_config(priv); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - iwl4965_clear_stations_table(priv); + iwlcore_clear_stations_table(priv); /* dont commit rxon if rf-kill is on*/ - if (!iwl4965_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv)) return -EAGAIN; cancel_delayed_work(&priv->scan_check); @@ -2711,31 +2108,28 @@ static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode) return 0; } -static void iwl4965_build_tx_cmd_hwcrypto(struct iwl4965_priv *priv, +static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_control *ctl, - struct iwl4965_cmd *cmd, + struct iwl_cmd *cmd, struct sk_buff *skb_frag, - int last_frag) + int sta_id) { - struct iwl4965_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); + if (ctl->flags & IEEE80211_TXCTL_AMPDU) + cmd->cmd.tx.tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); break; case ALG_TKIP: -#if 0 cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; - - if (last_frag) - memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8, - 8); - else - memset(cmd->cmd.tx.tkip_mic.byte, 0, 8); -#endif + ieee80211_get_tkip_key(keyinfo->conf, skb_frag, + IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key); + IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); break; case ALG_WEP: @@ -2760,8 +2154,8 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl4965_priv *priv, /* * handle build REPLY_TX command notification. */ -static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv, - struct iwl4965_cmd *cmd, +static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) @@ -2816,20 +2210,27 @@ static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv, cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else + } else { cmd->cmd.tx.timeout.pm_frame_timeout = 0; + } cmd->cmd.tx.driver_txop = 0; cmd->cmd.tx.tx_flags = tx_flags; cmd->cmd.tx.next_frame_len = 0; } - +static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->tx_stats[idx].cnt++; + priv->tx_stats[idx].bytes += len; +} /** * iwl4965_get_sta_id - Find station's index within station table * * If new IBSS station, create new entry in station table */ -static int iwl4965_get_sta_id(struct iwl4965_priv *priv, +static int iwl4965_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; @@ -2872,7 +2273,7 @@ static int iwl4965_get_sta_id(struct iwl4965_priv *priv, IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", print_mac(mac, hdr->addr1)); - iwl4965_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; default: @@ -2884,7 +2285,7 @@ static int iwl4965_get_sta_id(struct iwl4965_priv *priv, /* * start REPLY_TX command process */ -static int iwl4965_tx_skb(struct iwl4965_priv *priv, +static int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -2896,7 +2297,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - struct iwl4965_cmd *out_cmd = NULL; + struct iwl_cmd *out_cmd = NULL; u16 len, idx, len_org; u8 id, hdr_len, unicast; u8 sta_id; @@ -2908,7 +2309,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, int rc; spin_lock_irqsave(&priv->lock, flags); - if (iwl4965_is_rfkill(priv)) { + if (iwl_is_rfkill(priv)) { IWL_DEBUG_DROP("Dropping - RF KILL\n"); goto drop_unlock; } @@ -2918,7 +2319,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2928,7 +2329,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, fc = le16_to_cpu(hdr->frame_control); -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX("Sending AUTH frame\n"); else if (ieee80211_is_assoc_request(fc)) @@ -2939,10 +2340,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, /* drop all data frame if we are not associated */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (!iwl4965_is_associated(priv) || + (!iwl_is_associated(priv) || ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || !priv->assoc_station_added)) { - IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n"); + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); goto drop_unlock; } @@ -2972,11 +2373,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); seq_number += 0x10; #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG /* aggregation is on for this <sta,tid> */ - if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG) + if (ctl->flags & IEEE80211_TXCTL_AMPDU) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; -#endif /* CONFIG_IWL4965_HT_AGG */ + priv->stations[sta_id].tid[tid].tfds_in_queue++; #endif /* CONFIG_IWL4965_HT */ } @@ -3026,7 +2426,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, * We'll tell device about this padding later. */ len = priv->hw_setting.tx_cmd_len + - sizeof(struct iwl4965_cmd_header) + hdr_len; + sizeof(struct iwl_cmd_header) + hdr_len; len_org = len; len = (len + 3) & ~3; @@ -3038,15 +2438,15 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl4965_cmd) * idx + - offsetof(struct iwl4965_cmd, hdr); + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id); /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ @@ -3071,19 +2471,13 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, /* set is_hcca to 0; it probably will never be implemented */ iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); - scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) + + iwl_update_tx_stats(priv, fc, len); + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl4965_tx_cmd, scratch); out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); -#ifdef CONFIG_IWL4965_HT_AGG -#ifdef CONFIG_IWL4965_HT - /* TODO: move this functionality to rate scaling */ - iwl4965_tl_get_stats(priv, hdr); -#endif /* CONFIG_IWL4965_HT_AGG */ -#endif /*CONFIG_IWL4965_HT */ - - if (!ieee80211_get_morefrag(hdr)) { txq->need_update = 1; if (qc) { @@ -3095,17 +2489,17 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, txq->need_update = 0; } - iwl4965_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, sizeof(out_cmd->cmd.tx)); - iwl4965_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, ieee80211_get_hdrlen(fc)); /* Set up entry for this TFD in Tx byte-count array */ iwl4965_tx_queue_update_wr_ptr(priv, txq, len); /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd); + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); rc = iwl4965_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); @@ -3132,13 +2526,13 @@ drop: return -1; } -static void iwl4965_set_rate(struct iwl4965_priv *priv) +static void iwl4965_set_rate(struct iwl_priv *priv) { - const struct ieee80211_hw_mode *hw = NULL; + const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; int i; - hw = iwl4965_get_hw_mode(priv, priv->phymode); + hw = iwl4965_get_hw_mode(priv, priv->band); if (!hw) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; @@ -3147,24 +2541,10 @@ static void iwl4965_set_rate(struct iwl4965_priv *priv) priv->active_rate = 0; priv->active_rate_basic = 0; - IWL_DEBUG_RATE("Setting rates for 802.11%c\n", - hw->mode == MODE_IEEE80211A ? - 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); - - for (i = 0; i < hw->num_rates; i++) { - rate = &(hw->rates[i]); - if ((rate->val < IWL_RATE_COUNT) && - (rate->flags & IEEE80211_RATE_SUPPORTED)) { - IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl4965_rates[rate->val].plcp, - (rate->flags & IEEE80211_RATE_BASIC) ? - "*" : ""); - priv->active_rate |= (1 << rate->val); - if (rate->flags & IEEE80211_RATE_BASIC) - priv->active_rate_basic |= (1 << rate->val); - } else - IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl4965_rates[rate->val].plcp); + for (i = 0; i < hw->n_bitrates; i++) { + rate = &(hw->bitrates[i]); + if (rate->hw_value < IWL_RATE_COUNT) + priv->active_rate |= (1 << rate->hw_value); } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -3193,7 +2573,7 @@ static void iwl4965_set_rate(struct iwl4965_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio) +void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) { unsigned long flags; @@ -3208,17 +2588,25 @@ static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio) /* FIXME: This is a workaround for AP */ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { spin_lock_irqsave(&priv->lock, flags); - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); spin_unlock_irqrestore(&priv->lock, flags); - iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + /* call the host command only if no hw rf-kill set */ + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + iwl4965_send_card_state(priv, + CARD_STATE_CMD_DISABLE, + 0); set_bit(STATUS_RF_KILL_SW, &priv->status); + + /* make sure mac80211 stop sending Tx frame */ + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); } return; } spin_lock_irqsave(&priv->lock, flags); - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); clear_bit(STATUS_RF_KILL_SW, &priv->status); spin_unlock_irqrestore(&priv->lock, flags); @@ -3227,9 +2615,9 @@ static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio) msleep(10); spin_lock_irqsave(&priv->lock, flags); - iwl4965_read32(priv, CSR_UCODE_DRV_GP1); - if (!iwl4965_grab_nic_access(priv)) - iwl4965_release_nic_access(priv); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_nic_access(priv)) + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { @@ -3242,7 +2630,7 @@ static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio) return; } -void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb, +void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, u32 decrypt_res, struct ieee80211_rx_status *stats) { u16 fc = @@ -3257,6 +2645,12 @@ void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb, IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { case RX_RES_STATUS_SEC_TYPE_TKIP: + /* The uCode has got a bad phase 1 Key, pushes the packet. + * Decryption will be done in SW. */ + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_KEY_TTAK) + break; + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_BAD_ICV_MIC) stats->flag |= RX_FLAG_MMIC_ERROR; @@ -3277,7 +2671,7 @@ void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb, #define IWL_PACKET_RETRY_TIME HZ -int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header) +int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) { u16 sc = le16_to_cpu(header->seq_ctrl); u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; @@ -3394,13 +2788,13 @@ static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) return cpu_to_le32(res); } -static int iwl4965_get_measurement(struct iwl4965_priv *priv, +static int iwl4965_get_measurement(struct iwl_priv *priv, struct ieee80211_measurement_params *params, u8 type) { struct iwl4965_spectrum_cmd spectrum; struct iwl4965_rx_packet *res; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, .meta.flags = CMD_WANT_SKB, @@ -3410,7 +2804,7 @@ static int iwl4965_get_measurement(struct iwl4965_priv *priv, int spectrum_resp_status; int duration = le16_to_cpu(params->duration); - if (iwl4965_is_associated(priv)) + if (iwl_is_associated(priv)) add_time = iwl4965_usecs_to_beacons( le64_to_cpu(params->start_time) - priv->last_tsf, @@ -3425,7 +2819,7 @@ static int iwl4965_get_measurement(struct iwl4965_priv *priv, cmd.len = sizeof(spectrum); spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - if (iwl4965_is_associated(priv)) + if (iwl_is_associated(priv)) spectrum.start_time = iwl4965_add_beacon_time(priv->last_beacon_time, add_time, @@ -3440,7 +2834,7 @@ static int iwl4965_get_measurement(struct iwl4965_priv *priv, spectrum.flags |= RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - rc = iwl4965_send_cmd_sync(priv, &cmd); + rc = iwl_send_cmd_sync(priv, &cmd); if (rc) return rc; @@ -3474,7 +2868,7 @@ static int iwl4965_get_measurement(struct iwl4965_priv *priv, } #endif -static void iwl4965_txstatus_to_ieee(struct iwl4965_priv *priv, +static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv, struct iwl4965_tx_info *tx_sta) { @@ -3500,7 +2894,7 @@ static void iwl4965_txstatus_to_ieee(struct iwl4965_priv *priv, * need to be reclaimed. As result, some free space forms. If there is * enough free space (> low mark), wake the stack that feeds us. */ -int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index) +int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; struct iwl4965_queue *q = &txq->q; @@ -3513,9 +2907,9 @@ int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index) return 0; } - for (index = iwl4965_queue_inc_wrap(index, q->n_bd); + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; - q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) { + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { if (txq_id != IWL_CMD_QUEUE_NUM) { iwl4965_txstatus_to_ieee(priv, &(txq->txb[txq->q.read_ptr])); @@ -3528,10 +2922,10 @@ int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index) nfreed++; } - if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && +/* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && (txq_id != IWL_CMD_QUEUE_NUM) && priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); + ieee80211_wake_queue(priv->hw, txq_id); */ return nfreed; @@ -3550,9 +2944,8 @@ static int iwl4965_is_tx_success(u32 status) * ******************************************************************************/ #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG -static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv, +static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { if (priv->iw_mode == IEEE80211_IF_TYPE_STA) @@ -3564,7 +2957,7 @@ static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv, } static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr( - struct iwl4965_priv *priv, int txq_id, int idx) + struct iwl_priv *priv, int txq_id, int idx) { if (priv->txq[txq_id].txb[idx].skb[0]) return (struct ieee80211_hdr *)priv->txq[txq_id]. @@ -3583,13 +2976,13 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) /** * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue */ -static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, +static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, struct iwl4965_ht_agg *agg, - struct iwl4965_tx_resp *tx_resp, + struct iwl4965_tx_resp_agg *tx_resp, u16 start_idx) { - u32 status; - __le32 *frame_status = &tx_resp->status; + u16 status; + struct agg_tx_status *frame_status = &tx_resp->status; struct ieee80211_tx_status *tx_status = NULL; struct ieee80211_hdr *hdr = NULL; int i, sh; @@ -3602,30 +2995,30 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, agg->frame_count = tx_resp->frame_count; agg->start_idx = start_idx; agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - agg->bitmap0 = agg->bitmap1 = 0; + agg->bitmap = 0; /* # frames attempted by Tx command */ if (agg->frame_count == 1) { /* Only one frame was attempted; no block-ack will arrive */ - struct iwl4965_tx_queue *txq ; - status = le32_to_cpu(frame_status[0]); + status = le16_to_cpu(frame_status[0].status); + seq = le16_to_cpu(frame_status[0].sequence); + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); - txq_id = agg->txq_id; - txq = &priv->txq[txq_id]; /* FIXME: code repetition */ - IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n", - agg->frame_count, agg->start_idx); + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", + agg->frame_count, agg->start_idx, idx); - tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status); + tx_status = &(priv->txq[txq_id].txb[idx].status); tx_status->retry_count = tx_resp->failure_frame; tx_status->queue_number = status & 0xff; - tx_status->queue_length = tx_resp->bt_kill_count; - tx_status->queue_length |= tx_resp->failure_rts; - + tx_status->queue_length = tx_resp->failure_rts; + tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; tx_status->flags = iwl4965_is_tx_success(status)? IEEE80211_TX_STATUS_ACK : 0; - tx_status->control.tx_rate = - iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags); + iwl4965_hwrate_to_tx_control(priv, + le32_to_cpu(tx_resp->rate_n_flags), + &tx_status->control); /* FIXME: code repetition end */ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", @@ -3642,8 +3035,8 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, /* Construct bit-map of pending frames within Tx window */ for (i = 0; i < agg->frame_count; i++) { u16 sc; - status = le32_to_cpu(frame_status[i]); - seq = status >> 16; + status = le16_to_cpu(frame_status[i].status); + seq = le16_to_cpu(frame_status[i].sequence); idx = SEQ_TO_INDEX(seq); txq_id = SEQ_TO_QUEUE(seq); @@ -3687,13 +3080,12 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, start, (u32)(bitmap & 0xFFFFFFFF)); } - agg->bitmap0 = bitmap & 0xFFFFFFFF; - agg->bitmap1 = bitmap >> 32; + agg->bitmap = bitmap; agg->start_idx = start; agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n", + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", agg->frame_count, agg->start_idx, - agg->bitmap0); + (unsigned long long)agg->bitmap); if (bitmap) agg->wait_for_ba = 1; @@ -3701,12 +3093,11 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, return 0; } #endif -#endif /** * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response */ -static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_tx(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3718,9 +3109,9 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG - int tid, sta_id; -#endif + int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; + struct ieee80211_hdr *hdr; + __le16 *qc; #endif if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { @@ -3732,44 +3123,51 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, } #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG + hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); + qc = ieee80211_get_qos_ctrl(hdr); + + if (qc) + tid = le16_to_cpu(*qc) & 0xf; + + sta_id = iwl4965_get_ra_sta_id(priv, hdr); + if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known\n"); + return; + } + if (txq->sched_retry) { const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); - struct ieee80211_hdr *hdr = - iwl4965_tx_queue_get_hdr(priv, txq_id, index); struct iwl4965_ht_agg *agg = NULL; - __le16 *qc = ieee80211_get_qos_ctrl(hdr); - - if (qc == NULL) { - IWL_ERROR("BUG_ON qc is null!!!!\n"); - return; - } - - tid = le16_to_cpu(*qc) & 0xf; - sta_id = iwl4965_get_ra_sta_id(priv, hdr); - if (unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERROR("Station not known for\n"); + if (!qc) return; - } agg = &priv->stations[sta_id].tid[tid].agg; - iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index); + iwl4965_tx_status_reply_tx(priv, agg, + (struct iwl4965_tx_resp_agg *)tx_resp, index); if ((tx_resp->frame_count == 1) && !iwl4965_is_tx_success(status)) { /* TODO: send BAR */ } - if ((txq->q.read_ptr != (scd_ssn & 0xff))) { - index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + if (txq->q.read_ptr != (scd_ssn & 0xff)) { + int freed; + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); - iwl4965_tx_queue_reclaim(priv, txq_id, index); + freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + txq_id >= 0 && priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) + ieee80211_wake_queue(priv->hw, txq_id); + + iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); } } else { -#endif /* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ tx_status = &(txq->txb[txq->q.read_ptr].status); @@ -3777,12 +3175,10 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, tx_status->queue_number = status; tx_status->queue_length = tx_resp->bt_kill_count; tx_status->queue_length |= tx_resp->failure_rts; - tx_status->flags = iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - - tx_status->control.tx_rate = - iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags); + iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), + &tx_status->control); IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), @@ -3790,12 +3186,21 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, tx_resp->failure_frame); IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) - iwl4965_tx_queue_reclaim(priv, txq_id, index); + if (index != -1) { + int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); +#ifdef CONFIG_IWL4965_HT + if (tid != MAX_TID_COUNT) + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && + (txq_id >= 0) && + priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + if (tid != MAX_TID_COUNT) + iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); +#endif + } #ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG } -#endif /* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) @@ -3803,7 +3208,7 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, } -static void iwl4965_rx_reply_alive(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_alive(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3839,7 +3244,7 @@ static void iwl4965_rx_reply_alive(struct iwl4965_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl4965_rx_reply_add_sta(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3848,7 +3253,7 @@ static void iwl4965_rx_reply_add_sta(struct iwl4965_priv *priv, return; } -static void iwl4965_rx_reply_error(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_error(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3864,7 +3269,7 @@ static void iwl4965_rx_reply_error(struct iwl4965_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl4965_rx_csa(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb) +static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon; @@ -3875,7 +3280,7 @@ static void iwl4965_rx_csa(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buff priv->staging_rxon.channel = csa->channel; } -static void iwl4965_rx_spectrum_measure_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT @@ -3893,10 +3298,10 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl4965_priv *priv, #endif } -static void iwl4965_rx_pm_sleep_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX("sleep mode: %d, src: %d\n", @@ -3904,20 +3309,20 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl4965_priv *priv, #endif } -static void iwl4965_rx_pm_debug_statistics_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl4965_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } static void iwl4965_bg_beacon_update(struct work_struct *work) { - struct iwl4965_priv *priv = - container_of(work, struct iwl4965_priv, beacon_update); + struct iwl_priv *priv = + container_of(work, struct iwl_priv, beacon_update); struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ @@ -3939,10 +3344,10 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) iwl4965_send_beacon_cmd(priv); } -static void iwl4965_rx_beacon_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); @@ -3962,10 +3367,10 @@ static void iwl4965_rx_beacon_notif(struct iwl4965_priv *priv, } /* Service response to REPLY_SCAN_CMD (0x80) */ -static void iwl4965_rx_reply_scan(struct iwl4965_priv *priv, +static void iwl4965_rx_reply_scan(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl4965_scanreq_notification *notif = (struct iwl4965_scanreq_notification *)pkt->u.raw; @@ -3975,7 +3380,7 @@ static void iwl4965_rx_reply_scan(struct iwl4965_priv *priv, } /* Service SCAN_START_NOTIFICATION (0x82) */ -static void iwl4965_rx_scan_start_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -3992,7 +3397,7 @@ static void iwl4965_rx_scan_start_notif(struct iwl4965_priv *priv, } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static void iwl4965_rx_scan_results_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -4017,7 +3422,7 @@ static void iwl4965_rx_scan_results_notif(struct iwl4965_priv *priv, } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static void iwl4965_rx_scan_complete_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -4075,7 +3480,7 @@ reschedule: /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl4965_rx_card_state_notif(struct iwl4965_priv *priv, +static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; @@ -4089,35 +3494,35 @@ static void iwl4965_rx_card_state_notif(struct iwl4965_priv *priv, if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | RF_CARD_DISABLED)) { - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl4965_grab_nic_access(priv)) { - iwl4965_write_direct32( + if (!iwl_grab_nic_access(priv)) { + iwl_write_direct32( priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); } if (!(flags & RXON_CARD_DISABLED)) { - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl4965_grab_nic_access(priv)) { - iwl4965_write_direct32( + if (!iwl_grab_nic_access(priv)) { + iwl_write_direct32( priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); } } if (flags & RF_CARD_DISABLED) { - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - iwl4965_read32(priv, CSR_UCODE_DRV_GP1); - if (!iwl4965_grab_nic_access(priv)) - iwl4965_release_nic_access(priv); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_nic_access(priv)) + iwl_release_nic_access(priv); } } @@ -4153,7 +3558,7 @@ static void iwl4965_rx_card_state_notif(struct iwl4965_priv *priv, * This function chains into the hardware specific files for them to setup * any hardware specific handlers as well. */ -static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv) +static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) { priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive; priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta; @@ -4195,7 +3600,7 @@ static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv) * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ -static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv, +static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; @@ -4204,7 +3609,7 @@ static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv, int index = SEQ_TO_INDEX(sequence); int huge = sequence & SEQ_HUGE_FRAME; int cmd_index; - struct iwl4965_cmd *cmd; + struct iwl_cmd *cmd; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -4318,7 +3723,7 @@ static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q) /** * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue */ -int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_rx_queue *q) +int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q) { u32 reg = 0; int rc = 0; @@ -4331,27 +3736,27 @@ int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_ /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - iwl4965_set_bit(priv, CSR_GP_CNTRL, + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; } - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) goto exit_unlock; /* Device expects a multiple of 8 */ - iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, + iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); /* Else device is assumed to be awake */ } else /* Device expects a multiple of 8 */ - iwl4965_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); q->need_update = 0; @@ -4364,7 +3769,7 @@ int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_ /** * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr */ -static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv, +static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl_priv *priv, dma_addr_t dma_addr) { return cpu_to_le32((u32)(dma_addr >> 8)); @@ -4382,7 +3787,7 @@ static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv, * also updates the memory address in the firmware to reference the new * target buffer. */ -static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv) +static int iwl4965_rx_queue_restock(struct iwl_priv *priv) { struct iwl4965_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -4434,7 +3839,7 @@ static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv) * Also restock the Rx queue via iwl4965_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -static void iwl4965_rx_allocate(struct iwl4965_priv *priv) +static void iwl4965_rx_allocate(struct iwl_priv *priv) { struct iwl4965_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -4476,7 +3881,7 @@ static void iwl4965_rx_allocate(struct iwl4965_priv *priv) */ static void __iwl4965_rx_replenish(void *data) { - struct iwl4965_priv *priv = data; + struct iwl_priv *priv = data; iwl4965_rx_allocate(priv); iwl4965_rx_queue_restock(priv); @@ -4485,7 +3890,7 @@ static void __iwl4965_rx_replenish(void *data) void iwl4965_rx_replenish(void *data) { - struct iwl4965_priv *priv = data; + struct iwl_priv *priv = data; unsigned long flags; iwl4965_rx_allocate(priv); @@ -4500,7 +3905,7 @@ void iwl4965_rx_replenish(void *data) * This free routine walks the list of POOL entries and if SKB is set to * non NULL it is unmapped and freed */ -static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq) +static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { @@ -4518,7 +3923,7 @@ static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_q rxq->bd = NULL; } -int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv) +int iwl4965_rx_queue_alloc(struct iwl_priv *priv) { struct iwl4965_rx_queue *rxq = &priv->rxq; struct pci_dev *dev = priv->pci_dev; @@ -4545,7 +3950,7 @@ int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv) return 0; } -void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq) +void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) { unsigned long flags; int i; @@ -4660,7 +4065,7 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) * the appropriate handlers, including command responses, * frame-received notifications, and other notifications. */ -static void iwl4965_rx_handle(struct iwl4965_priv *priv) +static void iwl4965_rx_handle(struct iwl_priv *priv) { struct iwl4965_rx_mem_buffer *rxb; struct iwl4965_rx_packet *pkt; @@ -4706,7 +4111,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv) * but apparently a few don't get set; catch them here. */ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && - (pkt->hdr.cmd != REPLY_4965_RX) && + (pkt->hdr.cmd != REPLY_RX) && (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); @@ -4729,7 +4134,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv) if (reclaim) { /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl4965_send_cmd() + * fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) iwl4965_tx_cmd_complete(priv, rxb); @@ -4773,7 +4178,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv) /** * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware */ -static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, +static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) { u32 reg = 0; @@ -4788,27 +4193,27 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, /* wake up nic if it's powered down ... * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ - reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); - iwl4965_set_bit(priv, CSR_GP_CNTRL, + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return rc; } /* restore this queue's parameters in nic hardware. */ - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) return rc; - iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, + iwl_write_direct32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); /* else not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ } else - iwl4965_write32(priv, HBUS_TARG_WRPTR, + iwl_write32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); txq->need_update = 0; @@ -4816,13 +4221,13 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, return rc; } -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon) { DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); - iwl4965_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", @@ -4839,24 +4244,32 @@ static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon) } #endif -static void iwl4965_enable_interrupts(struct iwl4965_priv *priv) +static void iwl4965_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR("Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &priv->status); - iwl4965_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); } -static inline void iwl4965_disable_interrupts(struct iwl4965_priv *priv) +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl_priv *priv) +{ + /* wait to make sure we flush pedding tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + +static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) { clear_bit(STATUS_INT_ENABLED, &priv->status); /* disable interrupts from uCode/NIC to host */ - iwl4965_write32(priv, CSR_INT_MASK, 0x00000000); + iwl_write32(priv, CSR_INT_MASK, 0x00000000); /* acknowledge/clear/reset any interrupts still pending * from uCode or flow handler (Rx/Tx DMA) */ - iwl4965_write32(priv, CSR_INT, 0xffffffff); - iwl4965_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); IWL_DEBUG_ISR("Disabled interrupts\n"); } @@ -4883,7 +4296,7 @@ static const char *desc_lookup(int i) #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) -static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv) +static void iwl4965_dump_nic_error_log(struct iwl_priv *priv) { u32 data2, line; u32 desc, time, count, base, data1; @@ -4897,29 +4310,28 @@ static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv) return; } - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } - count = iwl4965_read_targ_mem(priv, base); + count = iwl_read_targ_mem(priv, base); if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERROR("Start IWL Error Log Dump:\n"); - IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", - priv->status, priv->config, count); + IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); } - desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32)); - blink1 = iwl4965_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl4965_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl4965_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl4965_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl4965_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl4965_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl4965_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl4965_read_targ_mem(priv, base + 11 * sizeof(u32)); + desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); IWL_ERROR("Desc Time " "data1 data2 line\n"); @@ -4929,7 +4341,7 @@ static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv) IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, ilink1, ilink2); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); } #define EVENT_START_OFFSET (4 * sizeof(u32)) @@ -4937,9 +4349,9 @@ static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv) /** * iwl4965_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! + * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ -static void iwl4965_print_event_log(struct iwl4965_priv *priv, u32 start_idx, +static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) { u32 i; @@ -4963,21 +4375,21 @@ static void iwl4965_print_event_log(struct iwl4965_priv *priv, u32 start_idx, /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl4965_read_targ_mem(priv, ptr); + ev = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); - time = iwl4965_read_targ_mem(priv, ptr); + time = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); if (mode == 0) IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ else { - data = iwl4965_read_targ_mem(priv, ptr); + data = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); } } } -static void iwl4965_dump_nic_event_log(struct iwl4965_priv *priv) +static void iwl4965_dump_nic_event_log(struct iwl_priv *priv) { int rc; u32 base; /* SRAM byte address of event log header */ @@ -4993,24 +4405,24 @@ static void iwl4965_dump_nic_event_log(struct iwl4965_priv *priv) return; } - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } /* event log header */ - capacity = iwl4965_read_targ_mem(priv, base); - mode = iwl4965_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl4965_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl4965_read_targ_mem(priv, base + (3 * sizeof(u32))); + capacity = iwl_read_targ_mem(priv, base); + mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ if (size == 0) { IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); return; } @@ -5026,13 +4438,13 @@ static void iwl4965_dump_nic_event_log(struct iwl4965_priv *priv) /* (then/else) start at top of log */ iwl4965_print_event_log(priv, 0, next_entry, mode); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); } /** * iwl4965_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl4965_irq_handle_error(struct iwl4965_priv *priv) +static void iwl4965_irq_handle_error(struct iwl_priv *priv) { /* Set the FW error flag -- cleared on iwl4965_down */ set_bit(STATUS_FW_ERROR, &priv->status); @@ -5040,8 +4452,8 @@ static void iwl4965_irq_handle_error(struct iwl4965_priv *priv) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); -#ifdef CONFIG_IWL4965_DEBUG - if (iwl4965_debug_level & IWL_DL_FW_ERRORS) { +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_FW_ERRORS) { iwl4965_dump_nic_error_log(priv); iwl4965_dump_nic_event_log(priv); iwl4965_print_rx_config_cmd(&priv->staging_rxon); @@ -5058,7 +4470,7 @@ static void iwl4965_irq_handle_error(struct iwl4965_priv *priv) IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); - if (iwl4965_is_associated(priv)) { + if (iwl_is_associated(priv)) { memcpy(&priv->recovery_rxon, &priv->active_rxon, sizeof(priv->recovery_rxon)); priv->error_recovering = 1; @@ -5067,7 +4479,7 @@ static void iwl4965_irq_handle_error(struct iwl4965_priv *priv) } } -static void iwl4965_error_recovery(struct iwl4965_priv *priv) +static void iwl4965_error_recovery(struct iwl_priv *priv) { unsigned long flags; @@ -5084,12 +4496,12 @@ static void iwl4965_error_recovery(struct iwl4965_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) +static void iwl4965_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; u32 inta_fh; unsigned long flags; -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG u32 inta_mask; #endif @@ -5098,19 +4510,19 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) /* Ack/clear/reset pending uCode interrupts. * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl4965_read32(priv, CSR_INT); - iwl4965_write32(priv, CSR_INT, inta); + inta = iwl_read32(priv, CSR_INT); + iwl_write32(priv, CSR_INT, inta); /* Ack/clear/reset pending flow-handler (DMA) interrupts. * Any new interrupts that happen after this, either while we're * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS); - iwl4965_write32(priv, CSR_FH_INT_STATUS, inta_fh); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); -#ifdef CONFIG_IWL4965_DEBUG - if (iwl4965_debug_level & IWL_DL_ISR) { +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ - inta_mask = iwl4965_read32(priv, CSR_INT_MASK); + inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); } @@ -5120,9 +4532,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after * reading CSR_INT. */ - if (inta_fh & CSR_FH_INT_RX_MASK) + if (inta_fh & CSR49_FH_INT_RX_MASK) inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR_FH_INT_TX_MASK) + if (inta_fh & CSR49_FH_INT_TX_MASK) inta |= CSR_INT_BIT_FH_TX; /* Now service all interrupt bits discovered above. */ @@ -5141,8 +4553,8 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) return; } -#ifdef CONFIG_IWL4965_DEBUG - if (iwl4965_debug_level & (IWL_DL_ISR)) { +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) IWL_DEBUG_ISR("Scheduler finished to transmit " @@ -5159,7 +4571,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) /* HW RF KILL switch toggled */ if (inta & CSR_INT_BIT_RF_KILL) { int hw_rf_kill = 0; - if (!(iwl4965_read32(priv, CSR_GP_CNTRL) & + if (!(iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; @@ -5170,7 +4582,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) /* Queue restart only if RF_KILL switch was set to "kill" * when we loaded driver, and is now set to "enable". * After we're Alive, RF_KILL gets handled by - * iwl_rx_card_state_notif() */ + * iwl4965_rx_card_state_notif() */ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { clear_bit(STATUS_RF_KILL_HW, &priv->status); queue_work(priv->workqueue, &priv->restart); @@ -5230,13 +4642,15 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) } /* Re-enable all interrupts */ - iwl4965_enable_interrupts(priv); - -#ifdef CONFIG_IWL4965_DEBUG - if (iwl4965_debug_level & (IWL_DL_ISR)) { - inta = iwl4965_read32(priv, CSR_INT); - inta_mask = iwl4965_read32(priv, CSR_INT_MASK); - inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS); + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl4965_enable_interrupts(priv); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + inta = iwl_read32(priv, CSR_INT); + inta_mask = iwl_read32(priv, CSR_INT_MASK); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); } @@ -5246,7 +4660,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) static irqreturn_t iwl4965_isr(int irq, void *data) { - struct iwl4965_priv *priv = data; + struct iwl_priv *priv = data; u32 inta, inta_mask; u32 inta_fh; if (!priv) @@ -5258,12 +4672,12 @@ static irqreturn_t iwl4965_isr(int irq, void *data) * back-to-back ISRs and sporadic interrupts from our NIC. * If we have something to service, the tasklet will re-enable ints. * If we *don't* have something, we'll re-enable before leaving here. */ - inta_mask = iwl4965_read32(priv, CSR_INT_MASK); /* just for debug */ - iwl4965_write32(priv, CSR_INT_MASK, 0x00000000); + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); /* Discover which interrupts are active/pending */ - inta = iwl4965_read32(priv, CSR_INT); - inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS); + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); /* Ignore interrupt if there's nothing in NIC to service. * This may be due to IRQ shared with another device, @@ -5295,313 +4709,13 @@ static irqreturn_t iwl4965_isr(int irq, void *data) none: /* re-enable interrupts here since we don't have anything to service. */ - iwl4965_enable_interrupts(priv); + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl4965_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } -/************************** EEPROM BANDS **************************** - * - * The iwl4965_eeprom_band definitions below provide the mapping from the - * EEPROM contents to the specific channel number supported for each - * band. - * - * For example, iwl4965_priv->eeprom.band_3_channels[4] from the band_3 - * definition below maps to physical channel 42 in the 5.2GHz spectrum. - * The specific geography and calibration information for that channel - * is contained in the eeprom map itself. - * - * During init, we copy the eeprom information and channel map - * information into priv->channel_info_24/52 and priv->channel_map_24/52 - * - * channel_map_24/52 provides the index in the channel_info array for a - * given channel. We have to have two separate maps as there is channel - * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and - * band_2 - * - * A value of 0xff stored in the channel_map indicates that the channel - * is not supported by the hardware at all. - * - * A value of 0xfe in the channel_map indicates that the channel is not - * valid for Tx with the current hardware. This means that - * while the system can tune and receive on a given channel, it may not - * be able to associate or transmit any frames on that - * channel. There is no corresponding channel information for that - * entry. - * - *********************************************************************/ - -/* 2.4 GHz */ -static const u8 iwl4965_eeprom_band_1[14] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 -}; - -/* 5.2 GHz bands */ -static const u8 iwl4965_eeprom_band_2[] = { /* 4915-5080MHz */ - 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 -}; - -static const u8 iwl4965_eeprom_band_3[] = { /* 5170-5320MHz */ - 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 -}; - -static const u8 iwl4965_eeprom_band_4[] = { /* 5500-5700MHz */ - 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 -}; - -static const u8 iwl4965_eeprom_band_5[] = { /* 5725-5825MHz */ - 145, 149, 153, 157, 161, 165 -}; - -static u8 iwl4965_eeprom_band_6[] = { /* 2.4 FAT channel */ - 1, 2, 3, 4, 5, 6, 7 -}; - -static u8 iwl4965_eeprom_band_7[] = { /* 5.2 FAT channel */ - 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 -}; - -static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, - int band, - int *eeprom_ch_count, - const struct iwl4965_eeprom_channel - **eeprom_ch_info, - const u8 **eeprom_ch_index) -{ - switch (band) { - case 1: /* 2.4GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_1); - *eeprom_ch_info = priv->eeprom.band_1_channels; - *eeprom_ch_index = iwl4965_eeprom_band_1; - break; - case 2: /* 4.9GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_2); - *eeprom_ch_info = priv->eeprom.band_2_channels; - *eeprom_ch_index = iwl4965_eeprom_band_2; - break; - case 3: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_3); - *eeprom_ch_info = priv->eeprom.band_3_channels; - *eeprom_ch_index = iwl4965_eeprom_band_3; - break; - case 4: /* 5.5GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_4); - *eeprom_ch_info = priv->eeprom.band_4_channels; - *eeprom_ch_index = iwl4965_eeprom_band_4; - break; - case 5: /* 5.7GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_5); - *eeprom_ch_info = priv->eeprom.band_5_channels; - *eeprom_ch_index = iwl4965_eeprom_band_5; - break; - case 6: /* 2.4GHz FAT channels */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_6); - *eeprom_ch_info = priv->eeprom.band_24_channels; - *eeprom_ch_index = iwl4965_eeprom_band_6; - break; - case 7: /* 5 GHz FAT channels */ - *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_7); - *eeprom_ch_info = priv->eeprom.band_52_channels; - *eeprom_ch_index = iwl4965_eeprom_band_7; - break; - default: - BUG(); - return; - } -} - -/** - * iwl4965_get_channel_info - Find driver's private channel info - * - * Based on band and channel number. - */ -const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv, - int phymode, u16 channel) -{ - int i; - - switch (phymode) { - case MODE_IEEE80211A: - for (i = 14; i < priv->channel_count; i++) { - if (priv->channel_info[i].channel == channel) - return &priv->channel_info[i]; - } - break; - - case MODE_IEEE80211B: - case MODE_IEEE80211G: - if (channel >= 1 && channel <= 14) - return &priv->channel_info[channel - 1]; - break; - - } - - return NULL; -} - -#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ - ? # x " " : "") - -/** - * iwl4965_init_channel_map - Set up driver's info for all possible channels - */ -static int iwl4965_init_channel_map(struct iwl4965_priv *priv) -{ - int eeprom_ch_count = 0; - const u8 *eeprom_ch_index = NULL; - const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL; - int band, ch; - struct iwl4965_channel_info *ch_info; - - if (priv->channel_count) { - IWL_DEBUG_INFO("Channel map already initialized.\n"); - return 0; - } - - if (priv->eeprom.version < 0x2f) { - IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", - priv->eeprom.version); - return -EINVAL; - } - - IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); - - priv->channel_count = - ARRAY_SIZE(iwl4965_eeprom_band_1) + - ARRAY_SIZE(iwl4965_eeprom_band_2) + - ARRAY_SIZE(iwl4965_eeprom_band_3) + - ARRAY_SIZE(iwl4965_eeprom_band_4) + - ARRAY_SIZE(iwl4965_eeprom_band_5); - - IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); - - priv->channel_info = kzalloc(sizeof(struct iwl4965_channel_info) * - priv->channel_count, GFP_KERNEL); - if (!priv->channel_info) { - IWL_ERROR("Could not allocate channel_info\n"); - priv->channel_count = 0; - return -ENOMEM; - } - - ch_info = priv->channel_info; - - /* Loop through the 5 EEPROM bands adding them in order to the - * channel map we maintain (that contains additional information than - * what just in the EEPROM) */ - for (band = 1; band <= 5; band++) { - - iwl4965_init_band_reference(priv, band, &eeprom_ch_count, - &eeprom_ch_info, &eeprom_ch_index); - - /* Loop through each band adding each of the channels */ - for (ch = 0; ch < eeprom_ch_count; ch++) { - ch_info->channel = eeprom_ch_index[ch]; - ch_info->phymode = (band == 1) ? MODE_IEEE80211B : - MODE_IEEE80211A; - - /* permanently store EEPROM's channel regulatory flags - * and max power in channel info database. */ - ch_info->eeprom = eeprom_ch_info[ch]; - - /* Copy the run-time flags so they are there even on - * invalid channels */ - ch_info->flags = eeprom_ch_info[ch].flags; - - if (!(is_channel_valid(ch_info))) { - IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " - "No traffic\n", - ch_info->channel, - ch_info->flags, - is_channel_a_band(ch_info) ? - "5.2" : "2.4"); - ch_info++; - continue; - } - - /* Initialize regulatory-based run-time data */ - ch_info->max_power_avg = ch_info->curr_txpow = - eeprom_ch_info[ch].max_power_avg; - ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; - ch_info->min_power = 0; - - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" - " %ddBm): Ad-Hoc %ssupported\n", - ch_info->channel, - is_channel_a_band(ch_info) ? - "5.2" : "2.4", - CHECK_AND_PRINT(IBSS), - CHECK_AND_PRINT(ACTIVE), - CHECK_AND_PRINT(RADAR), - CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(NARROW), - CHECK_AND_PRINT(DFS), - eeprom_ch_info[ch].flags, - eeprom_ch_info[ch].max_power_avg, - ((eeprom_ch_info[ch]. - flags & EEPROM_CHANNEL_IBSS) - && !(eeprom_ch_info[ch]. - flags & EEPROM_CHANNEL_RADAR)) - ? "" : "not "); - - /* Set the user_txpower_limit to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->user_txpower_limit) - priv->user_txpower_limit = - eeprom_ch_info[ch].max_power_avg; - - ch_info++; - } - } - - /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ - for (band = 6; band <= 7; band++) { - int phymode; - u8 fat_extension_chan; - - iwl4965_init_band_reference(priv, band, &eeprom_ch_count, - &eeprom_ch_info, &eeprom_ch_index); - - /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ - phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A; - - /* Loop through each band adding each of the channels */ - for (ch = 0; ch < eeprom_ch_count; ch++) { - - if ((band == 6) && - ((eeprom_ch_index[ch] == 5) || - (eeprom_ch_index[ch] == 6) || - (eeprom_ch_index[ch] == 7))) - fat_extension_chan = HT_IE_EXT_CHANNEL_MAX; - else - fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; - - /* Set up driver's info for lower half */ - iwl4965_set_fat_chan_info(priv, phymode, - eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - fat_extension_chan); - - /* Set up driver's info for upper half */ - iwl4965_set_fat_chan_info(priv, phymode, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - HT_IE_EXT_CHANNEL_BELOW); - } - } - - return 0; -} - -/* - * iwl4965_free_channel_map - undo allocations in iwl4965_init_channel_map - */ -static void iwl4965_free_channel_map(struct iwl4965_priv *priv) -{ - kfree(priv->channel_info); - priv->channel_count = 0; -} - /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses * from more than one AP. */ @@ -5625,22 +4739,24 @@ static void iwl4965_free_channel_map(struct iwl4965_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, int phymode) +static inline u16 iwl4965_get_active_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52; else return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode) +static u16 iwl4965_get_passive_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band) { - u16 active = iwl4965_get_active_dwell_time(priv, phymode); - u16 passive = (phymode != MODE_IEEE80211A) ? + u16 active = iwl4965_get_active_dwell_time(priv, band); + u16 passive = (band != IEEE80211_BAND_5GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; - if (iwl4965_is_associated(priv)) { + if (iwl_is_associated(priv)) { /* If we're associated, we clamp the maximum passive * dwell time to be 98% of the beacon interval (minus * 2 * channel tune time) */ @@ -5656,30 +4772,34 @@ static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode return passive; } -static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, +static int iwl4965_get_channels_for_scan(struct iwl_priv *priv, + enum ieee80211_band band, u8 is_active, u8 direct_mask, struct iwl4965_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode; - const struct iwl4965_channel_info *ch_info; + const struct ieee80211_supported_band *sband; + const struct iwl_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl4965_get_hw_mode(priv, phymode); - if (!hw_mode) + sband = iwl4965_get_hw_mode(priv, band); + if (!sband) return 0; - channels = hw_mode->channels; + channels = sband->channels; - active_dwell = iwl4965_get_active_dwell_time(priv, phymode); - passive_dwell = iwl4965_get_passive_dwell_time(priv, phymode); + active_dwell = iwl4965_get_active_dwell_time(priv, band); + passive_dwell = iwl4965_get_passive_dwell_time(priv, band); + + for (i = 0, added = 0; i < sband->n_channels; i++) { + if (channels[i].flags & IEEE80211_CHAN_DISABLED) + continue; - for (i = 0, added = 0; i < hw_mode->num_channels; i++) { - if (channels[i].chan == + if (ieee80211_frequency_to_channel(channels[i].center_freq) == le16_to_cpu(priv->active_rxon.channel)) { - if (iwl4965_is_associated(priv)) { + if (iwl_is_associated(priv)) { IWL_DEBUG_SCAN ("Skipping current channel %d\n", le16_to_cpu(priv->active_rxon.channel)); @@ -5688,9 +4808,9 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, } else if (priv->only_active_channel) continue; - scan_ch->channel = channels[i].chan; + scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq); - ch_info = iwl4965_get_channel_info(priv, phymode, + ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", @@ -5699,7 +4819,7 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, } if (!is_active || is_channel_passive(ch_info) || - !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = 0; /* passive */ else scan_ch->type = 1; /* active */ @@ -5718,7 +4838,7 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, /* scan_pwr_info->tpc.dsp_atten; */ /*scan_pwr_info->tpc.tx_gain; */ - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); @@ -5742,194 +4862,148 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, return added; } -static void iwl4965_reset_channel_flag(struct iwl4965_priv *priv) -{ - int i, j; - for (i = 0; i < 3; i++) { - struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; - for (j = 0; j < hw_mode->num_channels; j++) - hw_mode->channels[j].flag = hw_mode->channels[j].val; - } -} - -static void iwl4965_init_hw_rates(struct iwl4965_priv *priv, +static void iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl4965_rates[i].ieee * 5; - rates[i].val = i; /* Rate scaling will work on indexes */ - rates[i].val2 = i; - rates[i].flags = IEEE80211_RATE_SUPPORTED; - /* Only OFDM have the bits-per-symbol set */ - if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) - rates[i].flags |= IEEE80211_RATE_OFDM; - else { + rates[i].bitrate = iwl4965_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { /* - * If CCK 1M then set rate flag to CCK else CCK_2 - * which is CCK | PREAMBLE2 + * If CCK != 1M then set short preamble rate flag. */ - rates[i].flags |= (iwl4965_rates[i].plcp == 10) ? - IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + rates[i].flags |= + (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? + 0 : IEEE80211_RATE_SHORT_PREAMBLE; } - - /* Set up which ones are basic rates... */ - if (IWL_BASIC_RATES_MASK & (1 << i)) - rates[i].flags |= IEEE80211_RATE_BASIC; } } /** * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom */ -static int iwl4965_init_geos(struct iwl4965_priv *priv) +int iwl4965_init_geos(struct iwl_priv *priv) { - struct iwl4965_channel_info *ch; - struct ieee80211_hw_mode *modes; + struct iwl_channel_info *ch; + struct ieee80211_supported_band *sband; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; - enum { - A = 0, - B = 1, - G = 2, - }; - int mode_count = 3; - if (priv->modes) { + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO("Geography modes already initialized.\n"); set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; } - modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, - GFP_KERNEL); - if (!modes) - return -ENOMEM; - channels = kzalloc(sizeof(struct ieee80211_channel) * priv->channel_count, GFP_KERNEL); - if (!channels) { - kfree(modes); + if (!channels) return -ENOMEM; - } - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), GFP_KERNEL); if (!rates) { - kfree(modes); kfree(channels); return -ENOMEM; } - /* 0 = 802.11a - * 1 = 802.11b - * 2 = 802.11g - */ - /* 5.2GHz channels start after the 2.4GHz channels */ - modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)]; - modes[A].rates = rates; - modes[A].num_rates = 8; /* just OFDM */ - modes[A].rates = &rates[4]; - modes[A].num_channels = 0; -#ifdef CONFIG_IWL4965_HT - iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A); -#endif + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + /* just OFDM */ + sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; + sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; - modes[B].mode = MODE_IEEE80211B; - modes[B].channels = channels; - modes[B].rates = rates; - modes[B].num_rates = 4; /* just CCK */ - modes[B].num_channels = 0; - - modes[G].mode = MODE_IEEE80211G; - modes[G].channels = channels; - modes[G].rates = rates; - modes[G].num_rates = 12; /* OFDM & CCK */ - modes[G].num_channels = 0; -#ifdef CONFIG_IWL4965_HT - iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G); -#endif + iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ); + + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband->channels = channels; + /* OFDM & CCK */ + sband->bitrates = rates; + sband->n_bitrates = IWL_RATE_COUNT; + + iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; priv->ieee_rates = rates; iwl4965_init_hw_rates(priv, rates); - for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + for (i = 0; i < priv->channel_count; i++) { ch = &priv->channel_info[i]; - if (!is_channel_valid(ch)) { - IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " - "skipping.\n", - ch->channel, is_channel_a_band(ch) ? - "5.2" : "2.4"); + /* FIXME: might be removed if scan is OK */ + if (!is_channel_valid(ch)) continue; - } - if (is_channel_a_band(ch)) { - geo_ch = &modes[A].channels[modes[A].num_channels++]; - } else { - geo_ch = &modes[B].channels[modes[B].num_channels++]; - modes[G].num_channels++; - } + if (is_channel_a_band(ch)) + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + else + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + + geo_ch = &sband->channels[sband->n_channels++]; - geo_ch->freq = ieee80211chan2mhz(ch->channel); - geo_ch->chan = ch->channel; - geo_ch->power_level = ch->max_power_avg; - geo_ch->antenna_max = 0xff; + geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; + geo_ch->hw_value = ch->channel; if (is_channel_valid(ch)) { - geo_ch->flag = IEEE80211_CHAN_W_SCAN; - if (ch->flags & EEPROM_CHANNEL_IBSS) - geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - if (ch->flags & EEPROM_CHANNEL_ACTIVE) - geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + geo_ch->flags |= IEEE80211_CHAN_RADAR; if (ch->max_power_avg > priv->max_channel_txpower_limit) priv->max_channel_txpower_limit = ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - geo_ch->val = geo_ch->flag; + /* Save flags for reg domain usage */ + geo_ch->orig_flags = geo_ch->flags; + + IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", + ch->channel, geo_ch->center_freq, + is_channel_a_band(ch) ? "5.2" : "2.4", + geo_ch->flags & IEEE80211_CHAN_DISABLED ? + "restricted" : "valid", + geo_ch->flags); } - if ((modes[A].num_channels == 0) && priv->is_abg) { + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->cfg->sku & IWL_SKU_A) { printk(KERN_INFO DRV_NAME ": Incorrectly detected BG card as ABG. Please send " "your PCI ID 0x%04X:0x%04X to maintainer.\n", priv->pci_dev->device, priv->pci_dev->subsystem_device); - priv->is_abg = 0; + priv->cfg->sku &= ~IWL_SKU_A; } printk(KERN_INFO DRV_NAME ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - modes[G].num_channels, modes[A].num_channels); + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); - /* - * NOTE: We register these in preference of order -- the - * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick - * a phymode based on rates or AP capabilities but seems to - * configure it purely on if the channel being configured - * is supported by a mode -- and the first match is taken - */ + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; - if (modes[G].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[G]); - if (modes[B].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[B]); - if (modes[A].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[A]); - - priv->modes = modes; set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; @@ -5938,9 +5012,8 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) /* * iwl4965_free_geos - undo allocations in iwl4965_init_geos */ -static void iwl4965_free_geos(struct iwl4965_priv *priv) +void iwl4965_free_geos(struct iwl_priv *priv) { - kfree(priv->modes); kfree(priv->ieee_channels); kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); @@ -5952,7 +5025,7 @@ static void iwl4965_free_geos(struct iwl4965_priv *priv) * ******************************************************************************/ -static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv) +static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) { iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); @@ -5966,7 +5039,7 @@ static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv) * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host, * looking at all data. */ -static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image, +static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; @@ -5976,18 +5049,18 @@ static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image, IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) return rc; - iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); errcnt = 0; for (; len > 0; len -= sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERROR("uCode INST section is invalid at " "offset 0x%x, is 0x%x, s/b 0x%x\n", @@ -5999,7 +5072,7 @@ static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image, } } - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); if (!errcnt) IWL_DEBUG_INFO @@ -6014,7 +5087,7 @@ static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image, * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, u32 len) +static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; int rc = 0; @@ -6023,7 +5096,7 @@ static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) return rc; @@ -6031,9 +5104,9 @@ static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, + iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + RTC_INST_LOWER_BOUND); - val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { #if 0 /* Enable this if you want to see details */ IWL_ERROR("uCode INST section is invalid at " @@ -6047,7 +5120,7 @@ static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, } } - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); return rc; } @@ -6057,7 +5130,7 @@ static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, * iwl4965_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl4965_verify_ucode(struct iwl4965_priv *priv) +static int iwl4965_verify_ucode(struct iwl_priv *priv) { __le32 *image; u32 len; @@ -6104,7 +5177,7 @@ static int iwl4965_verify_ucode(struct iwl4965_priv *priv) /* check contents of special bootstrap uCode SRAM */ -static int iwl4965_verify_bsm(struct iwl4965_priv *priv) +static int iwl4965_verify_bsm(struct iwl_priv *priv) { __le32 *image = priv->ucode_boot.v_addr; u32 len = priv->ucode_boot.len; @@ -6114,11 +5187,11 @@ static int iwl4965_verify_bsm(struct iwl4965_priv *priv) IWL_DEBUG_INFO("Begin verify bsm\n"); /* verify BSM SRAM contents */ - val = iwl4965_read_prph(priv, BSM_WR_DWCOUNT_REG); + val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG); for (reg = BSM_SRAM_LOWER_BOUND; reg < BSM_SRAM_LOWER_BOUND + len; reg += sizeof(u32), image ++) { - val = iwl4965_read_prph(priv, reg); + val = iwl_read_prph(priv, reg); if (val != le32_to_cpu(*image)) { IWL_ERROR("BSM uCode verification failed at " "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", @@ -6166,7 +5239,7 @@ static int iwl4965_verify_bsm(struct iwl4965_priv *priv) * the runtime uCode instructions and the backup data cache into SRAM, * and re-launches the runtime uCode from where it left off. */ -static int iwl4965_load_bsm(struct iwl4965_priv *priv) +static int iwl4965_load_bsm(struct iwl_priv *priv) { __le32 *image = priv->ucode_boot.v_addr; u32 len = priv->ucode_boot.len; @@ -6195,42 +5268,42 @@ static int iwl4965_load_bsm(struct iwl4965_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) return rc; - iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); - iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); /* Fill BSM memory with bootstrap instructions */ for (reg_offset = BSM_SRAM_LOWER_BOUND; reg_offset < BSM_SRAM_LOWER_BOUND + len; reg_offset += sizeof(u32), image++) - _iwl4965_write_prph(priv, reg_offset, + _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image)); rc = iwl4965_verify_bsm(priv); if (rc) { - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); return rc; } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ - iwl4965_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); - iwl4965_write_prph(priv, BSM_WR_MEM_DST_REG, + iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND); - iwl4965_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); /* Load bootstrap code into instruction SRAM now, * to prepare to load "initialize" uCode */ - iwl4965_write_prph(priv, BSM_WR_CTRL_REG, + iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START); /* Wait for load of bootstrap uCode to finish */ for (i = 0; i < 100; i++) { - done = iwl4965_read_prph(priv, BSM_WR_CTRL_REG); + done = iwl_read_prph(priv, BSM_WR_CTRL_REG); if (!(done & BSM_WR_CTRL_REG_BIT_START)) break; udelay(10); @@ -6244,18 +5317,18 @@ static int iwl4965_load_bsm(struct iwl4965_priv *priv) /* Enable future boot loads whenever power management unit triggers it * (e.g. when powering back up after power-save shutdown) */ - iwl4965_write_prph(priv, BSM_WR_CTRL_REG, + iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); return 0; } -static void iwl4965_nic_start(struct iwl4965_priv *priv) +static void iwl4965_nic_start(struct iwl_priv *priv) { /* Remove all resets to allow NIC to operate */ - iwl4965_write32(priv, CSR_RESET, 0); + iwl_write32(priv, CSR_RESET, 0); } @@ -6264,12 +5337,12 @@ static void iwl4965_nic_start(struct iwl4965_priv *priv) * * Copy into buffers for card to fetch via bus-mastering */ -static int iwl4965_read_ucode(struct iwl4965_priv *priv) +static int iwl4965_read_ucode(struct iwl_priv *priv) { struct iwl4965_ucode *ucode; int ret; const struct firmware *ucode_raw; - const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode"; + const char *name = priv->cfg->fw_name; u8 *src; size_t len; u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; @@ -6465,7 +5538,7 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv) * We need to replace them to load runtime uCode inst and data, * and to save runtime data when powering down. */ -static int iwl4965_set_ucode_ptrs(struct iwl4965_priv *priv) +static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; @@ -6477,24 +5550,24 @@ static int iwl4965_set_ucode_ptrs(struct iwl4965_priv *priv) pdata = priv->ucode_data_backup.p_addr >> 4; spin_lock_irqsave(&priv->lock, flags); - rc = iwl4965_grab_nic_access(priv); + rc = iwl_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } /* Tell bootstrap uCode where to find image to load */ - iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); /* Inst bytecount must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ - iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, + iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -6514,7 +5587,7 @@ static int iwl4965_set_ucode_ptrs(struct iwl4965_priv *priv) * * Tell "initialize" uCode to go ahead and load the runtime uCode. */ -static void iwl4965_init_alive_start(struct iwl4965_priv *priv) +static void iwl4965_init_alive_start(struct iwl_priv *priv) { /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { @@ -6559,7 +5632,7 @@ static void iwl4965_init_alive_start(struct iwl4965_priv *priv) * from protocol/runtime uCode (initialization uCode's * Alive gets handled by iwl4965_init_alive_start()). */ -static void iwl4965_alive_start(struct iwl4965_priv *priv) +static void iwl4965_alive_start(struct iwl_priv *priv) { int rc = 0; @@ -6582,7 +5655,7 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv) goto restart; } - iwl4965_clear_stations_table(priv); + iwlcore_clear_stations_table(priv); rc = iwl4965_alive_notify(priv); if (rc) { @@ -6597,7 +5670,7 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv) /* Clear out the uCode error bit if it is set */ clear_bit(STATUS_FW_ERROR, &priv->status); - if (iwl4965_is_rfkill(priv)) + if (iwl_is_rfkill(priv)) return; ieee80211_start_queues(priv->hw); @@ -6607,7 +5680,7 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv) iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); - if (iwl4965_is_associated(priv)) { + if (iwl_is_associated(priv)) { struct iwl4965_rxon_cmd *active_rxon = (struct iwl4965_rxon_cmd *)(&priv->active_rxon); @@ -6631,6 +5704,8 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv) iwl4965_rf_kill_ct_config(priv); + iwl_leds_register(priv); + IWL_DEBUG_INFO("ALIVE processing complete.\n"); set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); @@ -6638,15 +5713,17 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv) if (priv->error_recovering) iwl4965_error_recovery(priv); + iwlcore_low_level_notify(priv, IWLCORE_START_EVT); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); return; restart: queue_work(priv->workqueue, &priv->restart); } -static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv); +static void iwl4965_cancel_deferred_work(struct iwl_priv *priv); -static void __iwl4965_down(struct iwl4965_priv *priv) +static void __iwl4965_down(struct iwl_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); @@ -6659,7 +5736,11 @@ static void __iwl4965_down(struct iwl4965_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl4965_clear_stations_table(priv); + iwl_leds_unregister(priv); + + iwlcore_low_level_notify(priv, IWLCORE_STOP_EVT); + + iwlcore_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -6670,17 +5751,20 @@ static void __iwl4965_down(struct iwl4965_priv *priv) clear_bit(STATUS_EXIT_PENDING, &priv->status); /* stop and reset the on-board processor */ - iwl4965_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl4965_init() then * clear all bits but the RF Kill and SUSPEND bits and return */ - if (!iwl4965_is_init(priv)) { + if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << @@ -6706,7 +5790,7 @@ static void __iwl4965_down(struct iwl4965_priv *priv) STATUS_FW_ERROR; spin_lock_irqsave(&priv->lock, flags); - iwl4965_clear_bit(priv, CSR_GP_CNTRL, + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock_irqrestore(&priv->lock, flags); @@ -6714,17 +5798,17 @@ static void __iwl4965_down(struct iwl4965_priv *priv) iwl4965_hw_rxq_stop(priv); spin_lock_irqsave(&priv->lock, flags); - if (!iwl4965_grab_nic_access(priv)) { - iwl4965_write_prph(priv, APMG_CLK_DIS_REG, + if (!iwl_grab_nic_access(priv)) { + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - iwl4965_release_nic_access(priv); + iwl_release_nic_access(priv); } spin_unlock_irqrestore(&priv->lock, flags); udelay(5); iwl4965_hw_nic_stop_master(priv); - iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); iwl4965_hw_nic_reset(priv); exit: @@ -6738,7 +5822,7 @@ static void __iwl4965_down(struct iwl4965_priv *priv) iwl4965_clear_free_frames(priv); } -static void iwl4965_down(struct iwl4965_priv *priv) +static void iwl4965_down(struct iwl_priv *priv) { mutex_lock(&priv->mutex); __iwl4965_down(priv); @@ -6749,7 +5833,7 @@ static void iwl4965_down(struct iwl4965_priv *priv) #define MAX_HW_RESTARTS 5 -static int __iwl4965_up(struct iwl4965_priv *priv) +static int __iwl4965_up(struct iwl_priv *priv) { int rc, i; @@ -6761,6 +5845,7 @@ static int __iwl4965_up(struct iwl4965_priv *priv) if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { IWL_WARNING("Radio disabled by SW RF kill (module " "parameter)\n"); + iwl_rfkill_set_hw_state(priv); return -ENODEV; } @@ -6770,18 +5855,20 @@ static int __iwl4965_up(struct iwl4965_priv *priv) } /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl4965_read32(priv, CSR_GP_CNTRL) & + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); else { set_bit(STATUS_RF_KILL_HW, &priv->status); if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { + iwl_rfkill_set_hw_state(priv); IWL_WARNING("Radio disabled by HW RF Kill switch\n"); return -ENODEV; } } - iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_rfkill_set_hw_state(priv); + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); rc = iwl4965_hw_nic_init(priv); if (rc) { @@ -6790,17 +5877,17 @@ static int __iwl4965_up(struct iwl4965_priv *priv) } /* make sure rfkill handshake bits are cleared */ - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable host interrupts */ - iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); iwl4965_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); /* Copy original ucode data image from disk into backup cache. * This will be used to initialize the on-board processor's @@ -6814,7 +5901,7 @@ static int __iwl4965_up(struct iwl4965_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl4965_clear_stations_table(priv); + iwlcore_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -6852,8 +5939,8 @@ static int __iwl4965_up(struct iwl4965_priv *priv) static void iwl4965_bg_init_alive_start(struct work_struct *data) { - struct iwl4965_priv *priv = - container_of(data, struct iwl4965_priv, init_alive_start.work); + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6865,8 +5952,8 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) static void iwl4965_bg_alive_start(struct work_struct *data) { - struct iwl4965_priv *priv = - container_of(data, struct iwl4965_priv, alive_start.work); + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6878,7 +5965,7 @@ static void iwl4965_bg_alive_start(struct work_struct *data) static void iwl4965_bg_rf_kill(struct work_struct *work) { - struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, rf_kill); + struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); wake_up_interruptible(&priv->wait_command_queue); @@ -6887,13 +5974,16 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) mutex_lock(&priv->mutex); - if (!iwl4965_is_rfkill(priv)) { + if (!iwl_is_rfkill(priv)) { IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, "HW and/or SW RF Kill no longer active, restarting " "device\n"); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) queue_work(priv->workqueue, &priv->restart); } else { + /* make sure mac80211 stop sending Tx frame */ + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) IWL_DEBUG_RF_KILL("Can not turn radio back on - " @@ -6903,6 +5993,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) "Kill switch must be turned off for " "wireless networking to work.\n"); } + iwl_rfkill_set_hw_state(priv); + mutex_unlock(&priv->mutex); } @@ -6910,8 +6002,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) static void iwl4965_bg_scan_check(struct work_struct *data) { - struct iwl4965_priv *priv = - container_of(data, struct iwl4965_priv, scan_check.work); + struct iwl_priv *priv = + container_of(data, struct iwl_priv, scan_check.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6931,24 +6023,25 @@ static void iwl4965_bg_scan_check(struct work_struct *data) static void iwl4965_bg_request_scan(struct work_struct *data) { - struct iwl4965_priv *priv = - container_of(data, struct iwl4965_priv, request_scan); - struct iwl4965_host_cmd cmd = { + struct iwl_priv *priv = + container_of(data, struct iwl_priv, request_scan); + struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl4965_scan_cmd), .meta.flags = CMD_SIZE_HUGE, }; - int rc = 0; struct iwl4965_scan_cmd *scan; struct ieee80211_conf *conf = NULL; + u16 cmd_len; + enum ieee80211_band band; u8 direct_mask; - int phymode; + int ret = 0; conf = ieee80211_get_hw_conf(priv->hw); mutex_lock(&priv->mutex); - if (!iwl4965_is_ready(priv)) { + if (!iwl_is_ready(priv)) { IWL_WARNING("request scan called when driver not ready.\n"); goto done; } @@ -6963,7 +6056,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) if (test_bit(STATUS_SCAN_HW, &priv->status)) { IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " "Ignoring second request.\n"); - rc = -EIO; + ret = -EIO; goto done; } @@ -6977,7 +6070,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) goto done; } - if (iwl4965_is_rfkill(priv)) { + if (iwl_is_rfkill(priv)) { IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); goto done; } @@ -6996,7 +6089,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) priv->scan = kmalloc(sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE, GFP_KERNEL); if (!priv->scan) { - rc = -ENOMEM; + ret = -ENOMEM; goto done; } } @@ -7006,7 +6099,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - if (iwl4965_is_associated(priv)) { + if (iwl_is_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; @@ -7043,26 +6136,19 @@ static void iwl4965_bg_request_scan(struct work_struct *data) memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); direct_mask = 1; - } else if (!iwl4965_is_associated(priv) && priv->essid_len) { + } else if (!iwl_is_associated(priv) && priv->essid_len) { scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); direct_mask = 1; - } else + } else { direct_mask = 0; + } - /* We don't build a direct scan probe request; the uCode will do - * that based on the direct_mask added to each channel entry */ - scan->tx_cmd.len = cpu_to_le16( - iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan), 0)); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - /* flags + rate selection */ - - scan->tx_cmd.tx_flags |= cpu_to_le32(0x200); switch (priv->scan_bands) { case 2: @@ -7072,7 +6158,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK); scan->good_CRC_th = 0; - phymode = MODE_IEEE80211G; + band = IEEE80211_BAND_2GHZ; break; case 1: @@ -7080,7 +6166,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, RATE_MCS_ANT_B_MSK); scan->good_CRC_th = IWL_GOOD_CRC_TH; - phymode = MODE_IEEE80211A; + band = IEEE80211_BAND_5GHZ; break; default: @@ -7088,6 +6174,13 @@ static void iwl4965_bg_request_scan(struct work_struct *data) goto done; } + /* We don't build a direct scan probe request; the uCode will do + * that based on the direct_mask added to each channel entry */ + cmd_len = iwl4965_fill_probe_req(priv, band, + (struct ieee80211_mgmt *)scan->data, + IWL_MAX_SCAN_SIZE - sizeof(*scan), 0); + + scan->tx_cmd.len = cpu_to_le16(cmd_len); /* select Rx chains */ /* Force use of chains B and C (0x6) for scan Rx. @@ -7101,18 +6194,23 @@ static void iwl4965_bg_request_scan(struct work_struct *data) if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; - if (direct_mask) + if (direct_mask) { IWL_DEBUG_SCAN ("Initiating direct scan for %s.\n", iwl4965_escape_essid(priv->essid, priv->essid_len)); - else + scan->channel_count = + iwl4965_get_channels_for_scan( + priv, band, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + } else { IWL_DEBUG_SCAN("Initiating indirect scan.\n"); - - scan->channel_count = - iwl4965_get_channels_for_scan( - priv, phymode, 1, /* active */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + scan->channel_count = + iwl4965_get_channels_for_scan( + priv, band, 0, /* passive */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + } cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl4965_scan_channel); @@ -7120,8 +6218,8 @@ static void iwl4965_bg_request_scan(struct work_struct *data) scan->len = cpu_to_le16(cmd.len); set_bit(STATUS_SCAN_HW, &priv->status); - rc = iwl4965_send_cmd_sync(priv, &cmd); - if (rc) + ret = iwl_send_cmd_sync(priv, &cmd); + if (ret) goto done; queue_delayed_work(priv->workqueue, &priv->scan_check, @@ -7138,7 +6236,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) static void iwl4965_bg_up(struct work_struct *data) { - struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, up); + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -7150,7 +6248,7 @@ static void iwl4965_bg_up(struct work_struct *data) static void iwl4965_bg_restart(struct work_struct *data) { - struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, restart); + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -7161,8 +6259,8 @@ static void iwl4965_bg_restart(struct work_struct *data) static void iwl4965_bg_rx_replenish(struct work_struct *data) { - struct iwl4965_priv *priv = - container_of(data, struct iwl4965_priv, rx_replenish); + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -7176,11 +6274,10 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data) static void iwl4965_bg_post_associate(struct work_struct *data) { - struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, + struct iwl_priv *priv = container_of(data, struct iwl_priv, post_associate.work); - - int rc = 0; struct ieee80211_conf *conf = NULL; + int ret = 0; DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { @@ -7211,9 +6308,9 @@ static void iwl4965_bg_post_associate(struct work_struct *data) memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); iwl4965_setup_rxon_timing(priv); - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING, + ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); - if (rc) + if (ret) IWL_WARNING("REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); @@ -7255,7 +6352,7 @@ static void iwl4965_bg_post_associate(struct work_struct *data) case IEEE80211_IF_TYPE_IBSS: /* clear out the station table */ - iwl4965_clear_stations_table(priv); + iwlcore_clear_stations_table(priv); iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); iwl4965_rxon_add_station(priv, priv->bssid, 0); @@ -7281,9 +6378,8 @@ static void iwl4965_bg_post_associate(struct work_struct *data) if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) priv->assoc_station_added = 1; -#ifdef CONFIG_IWL4965_QOS iwl4965_activate_qos(priv, 0); -#endif /* CONFIG_IWL4965_QOS */ + /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; mutex_unlock(&priv->mutex); @@ -7291,9 +6387,9 @@ static void iwl4965_bg_post_associate(struct work_struct *data) static void iwl4965_bg_abort_scan(struct work_struct *work) { - struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, abort_scan); + struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); - if (!iwl4965_is_ready(priv)) + if (!iwl_is_ready(priv)) return; mutex_lock(&priv->mutex); @@ -7308,8 +6404,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co static void iwl4965_bg_scan_completed(struct work_struct *work) { - struct iwl4965_priv *priv = - container_of(work, struct iwl4965_priv, scan_completed); + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); @@ -7338,7 +6434,7 @@ static void iwl4965_bg_scan_completed(struct work_struct *work) static int iwl4965_mac_start(struct ieee80211_hw *hw) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; int ret; IWL_DEBUG_MAC80211("enter\n"); @@ -7415,7 +6511,7 @@ out_disable_msi: static void iwl4965_mac_stop(struct ieee80211_hw *hw) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); @@ -7426,7 +6522,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; - if (iwl4965_is_ready_rf(priv)) { + if (iwl_is_ready_rf(priv)) { /* stop mac, cancel any scan request and clear * RXON_FILTER_ASSOC_MSK BIT */ @@ -7450,7 +6546,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); @@ -7460,7 +6556,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate); + ctl->tx_rate->bitrate); if (iwl4965_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); @@ -7472,7 +6568,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; unsigned long flags; DECLARE_MAC_BUF(mac); @@ -7495,7 +6591,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl4965_is_ready(priv)) + if (iwl_is_ready(priv)) iwl4965_set_mode(priv, conf->type); mutex_unlock(&priv->mutex); @@ -7513,23 +6609,23 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, */ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { - struct iwl4965_priv *priv = hw->priv; - const struct iwl4965_channel_info *ch_info; + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; unsigned long flags; int ret = 0; mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); - if (!iwl4965_is_ready(priv)) { + if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); ret = -EIO; goto out; } - if (unlikely(!iwl4965_param_disable_hw_scan && + if (unlikely(!priv->cfg->mod_params->disable_hw_scan && test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); set_bit(STATUS_CONF_PENDING, &priv->status); @@ -7539,10 +6635,9 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl4965_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl_get_channel_info(priv, conf->channel->band, + ieee80211_frequency_to_channel(conf->channel->center_freq)); if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", - conf->channel, conf->phymode); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); ret = -EINVAL; @@ -7550,10 +6645,10 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co } #ifdef CONFIG_IWL4965_HT - /* if we are switching fron ht to 2.4 clear flags + /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not * support ht */ - if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel) + if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel->hw_value) #ifdef IEEE80211_CONF_CHANNEL_SWITCH && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) #endif @@ -7561,12 +6656,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co priv->staging_rxon.flags = 0; #endif /* CONFIG_IWL4965_HT */ - iwl4965_set_rxon_channel(priv, conf->phymode, conf->channel); + iwlcore_set_rxon_channel(priv, conf->channel->band, + ieee80211_frequency_to_channel(conf->channel->center_freq)); - iwl4965_set_flags_for_phymode(priv, conf->phymode); + iwl4965_set_flags_for_phymode(priv, conf->channel->band); /* The list of supported rates and rate mask can be different - * for each phymode; since the phymode may have changed, reset + * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists */ iwl4965_set_rate(priv); @@ -7579,14 +6675,15 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co } #endif - iwl4965_radio_kill_sw(priv, !conf->radio_enabled); + if (priv->cfg->ops->lib->radio_kill_sw) + priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled); if (!conf->radio_enabled) { IWL_DEBUG_MAC80211("leave - radio disabled\n"); goto out; } - if (iwl4965_is_rfkill(priv)) { + if (iwl_is_rfkill(priv)) { IWL_DEBUG_MAC80211("leave - RF kill\n"); ret = -EIO; goto out; @@ -7608,9 +6705,9 @@ out: return ret; } -static void iwl4965_config_ap(struct iwl4965_priv *priv) +static void iwl4965_config_ap(struct iwl_priv *priv) { - int rc = 0; + int ret = 0; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -7625,9 +6722,9 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv) /* RXON Timing */ memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); iwl4965_setup_rxon_timing(priv); - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING, + ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); - if (rc) + if (ret) IWL_WARNING("REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); @@ -7658,9 +6755,7 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); -#ifdef CONFIG_IWL4965_QOS iwl4965_activate_qos(priv, 1); -#endif iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); } iwl4965_send_beacon_cmd(priv); @@ -7674,7 +6769,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7682,6 +6777,12 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, if (conf == NULL) return -EIO; + if (priv->vif != vif) { + IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); + mutex_unlock(&priv->mutex); + return 0; + } + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && (!conf->beacon || !conf->ssid_len)) { IWL_DEBUG_MAC80211 @@ -7689,7 +6790,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return 0; } - if (!iwl4965_is_alive(priv)) + if (!iwl_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); @@ -7704,17 +6805,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { - IWL_DEBUG_MAC80211("leave - scanning\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); - mutex_unlock(&priv->mutex); - return 0; - } if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { if (!conf->bssid) { @@ -7729,7 +6819,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, priv->ibss_beacon = conf->beacon; } - if (iwl4965_is_rfkill(priv)) + if (iwl_is_rfkill(priv)) goto done; if (conf->bssid && !is_zero_ether_addr(conf->bssid) && @@ -7797,13 +6887,13 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); mutex_lock(&priv->mutex); - if (iwl4965_is_ready_rf(priv)) { + if (iwl_is_ready_rf(priv)) { iwl4965_scan_cancel_timeout(priv, 100); cancel_delayed_work(&priv->post_associate); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -7821,14 +6911,77 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, } + +#ifdef CONFIG_IWL4965_HT +static void iwl4965_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; + struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + + IWL_DEBUG_MAC80211("enter: \n"); + + iwl_conf->is_ht = bss_conf->assoc_ht; + + if (!iwl_conf->is_ht) + return; + + priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) + iwl_conf->sgf |= 0x1; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) + iwl_conf->sgf |= 0x2; + + iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); + iwl_conf->max_amsdu_size = + !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); + + iwl_conf->supported_chan_width = + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); + iwl_conf->extension_chan_offset = + ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + /* If no above or below channel supplied disable FAT channel */ + if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE && + iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW) + iwl_conf->supported_chan_width = 0; + + iwl_conf->tx_mimo_ps_mode = + (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); + + iwl_conf->control_channel = ht_bss_conf->primary_channel; + iwl_conf->tx_chan_width = + !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + iwl_conf->ht_protection = + ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + iwl_conf->non_GF_STA_present = + !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); + + IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); + IWL_DEBUG_MAC80211("leave\n"); +} +#else +static inline void iwl4965_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ +} +#endif + +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", + bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; else @@ -7836,35 +6989,52 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A)) + IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; else priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; } + if (changes & BSS_CHANGED_HT) { + IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); + iwl4965_ht_conf(priv, bss_conf); + iwl4965_set_rxon_chain(priv); + } + if (changes & BSS_CHANGED_ASSOC) { - /* - * TODO: - * do stuff instead of sniffing assoc resp - */ + IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); + if (bss_conf->assoc) { + priv->assoc_id = bss_conf->aid; + priv->beacon_int = bss_conf->beacon_int; + priv->timestamp = bss_conf->timestamp; + priv->assoc_capability = bss_conf->assoc_capability; + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + queue_work(priv->workqueue, &priv->post_associate.work); + } else { + priv->assoc_id = 0; + IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); + } + } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { + IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); + iwl4965_send_rxon_assoc(priv); } - if (iwl4965_is_associated(priv)) - iwl4965_send_rxon_assoc(priv); } static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) { int rc = 0; unsigned long flags; - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); mutex_lock(&priv->mutex); spin_lock_irqsave(&priv->lock, flags); - if (!iwl4965_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv)) { rc = -EIO; IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); goto out_unlock; @@ -7910,18 +7080,69 @@ out_unlock: return rc; } +static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) +{ + struct iwl_priv *priv = hw->priv; + u8 sta_id = IWL_INVALID_STATION; + unsigned long flags; + __le16 key_flags = 0; + int i; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_MAC80211("enter\n"); + + sta_id = iwl4965_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); + return; + } + + iwl4965_scan_cancel_timeout(priv, 100); + + key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == priv->hw_setting.bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].sta.key.key_offset = + (sta_id % STA_KEY_MAX_NUM);/* FIXME */ + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) + priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = + cpu_to_le16(phase1key[i]); + + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); +} + static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; DECLARE_MAC_BUF(mac); - int rc = 0; - u8 sta_id; + int ret = 0; + u8 sta_id = IWL_INVALID_STATION; + u8 static_key; IWL_DEBUG_MAC80211("enter\n"); - if (!iwl4965_param_hwcrypto) { + if (!priv->cfg->mod_params->hw_crypto) { IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -7930,58 +7151,57 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* only support pairwise keys */ return -EOPNOTSUPP; - sta_id = iwl4965_hw_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); - return -EINVAL; - } + /* FIXME: need to differenciate between static and dynamic key + * in the level of mac80211 */ + static_key = !iwl_is_associated(priv); - mutex_lock(&priv->mutex); + if (!static_key) { + sta_id = iwl4965_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); + return -EINVAL; + } + } iwl4965_scan_cancel_timeout(priv, 100); switch (cmd) { - case SET_KEY: - rc = iwl4965_update_sta_key_info(priv, key, sta_id); - if (!rc) { - iwl4965_set_rxon_hwcrypto(priv, 1); - iwl4965_commit_rxon(priv); - key->hw_key_idx = sta_id; - IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - } + case SET_KEY: + if (static_key) + ret = iwl4965_set_static_key(priv, key); + else + ret = iwl4965_set_dynamic_key(priv, key, sta_id); + + IWL_DEBUG_MAC80211("enable hwcrypto key\n"); break; case DISABLE_KEY: - rc = iwl4965_clear_sta_key_info(priv, sta_id); - if (!rc) { - iwl4965_set_rxon_hwcrypto(priv, 0); - iwl4965_commit_rxon(priv); - IWL_DEBUG_MAC80211("disable hwcrypto key\n"); - } + if (static_key) + ret = iwl4965_remove_static_key(priv); + else + ret = iwl4965_clear_sta_key_info(priv, sta_id); + + IWL_DEBUG_MAC80211("disable hwcrypto key\n"); break; default: - rc = -EINVAL; + ret = -EINVAL; } IWL_DEBUG_MAC80211("leave\n"); - mutex_unlock(&priv->mutex); - return rc; + return ret; } static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { - struct iwl4965_priv *priv = hw->priv; -#ifdef CONFIG_IWL4965_QOS + struct iwl_priv *priv = hw->priv; unsigned long flags; int q; -#endif /* CONFIG_IWL4965_QOS */ IWL_DEBUG_MAC80211("enter\n"); - if (!iwl4965_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); return -EIO; } @@ -7991,7 +7211,6 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, return 0; } -#ifdef CONFIG_IWL4965_QOS if (!priv->qos_data.qos_enable) { priv->qos_data.qos_active = 0; IWL_DEBUG_MAC80211("leave - qos not enabled\n"); @@ -8005,7 +7224,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->burst_time * 100)); + cpu_to_le16((params->txop * 32)); priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; @@ -8015,13 +7234,11 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, mutex_lock(&priv->mutex); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) iwl4965_activate_qos(priv, 1); - else if (priv->assoc_id && iwl4965_is_associated(priv)) + else if (priv->assoc_id && iwl_is_associated(priv)) iwl4965_activate_qos(priv, 0); mutex_unlock(&priv->mutex); -#endif /*CONFIG_IWL4965_QOS */ - IWL_DEBUG_MAC80211("leave\n"); return 0; } @@ -8029,7 +7246,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; int i, avail; struct iwl4965_tx_queue *txq; struct iwl4965_queue *q; @@ -8037,7 +7254,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("enter\n"); - if (!iwl4965_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); return -EIO; } @@ -8080,7 +7297,7 @@ static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw) static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; unsigned long flags; mutex_lock(&priv->mutex); @@ -8091,30 +7308,15 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) spin_lock_irqsave(&priv->lock, flags); memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWL4965_HT_AGG -/* if (priv->lq_mngr.agg_ctrl.granted_ba) - iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/ - - memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl4965_agg_control)); - priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10; - priv->lq_mngr.agg_ctrl.ba_timeout = 5000; - priv->lq_mngr.agg_ctrl.auto_agg = 1; - - if (priv->lq_mngr.agg_ctrl.auto_agg) - priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED; -#endif /*CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ -#ifdef CONFIG_IWL4965_QOS - iwl4965_reset_qos(priv); -#endif + iwlcore_reset_qos(priv); cancel_delayed_work(&priv->post_associate); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = 0; priv->assoc_capability = 0; - priv->call_post_assoc_from_beacon = 0; priv->assoc_station_added = 0; /* new association get rid of ibss beacon skb */ @@ -8124,14 +7326,13 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) priv->ibss_beacon = NULL; priv->beacon_int = priv->hw->conf.beacon_int; - priv->timestamp1 = 0; - priv->timestamp0 = 0; + priv->timestamp = 0; if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) priv->beacon_int = 0; spin_unlock_irqrestore(&priv->lock, flags); - if (!iwl4965_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); mutex_unlock(&priv->mutex); return; @@ -8166,13 +7367,13 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct iwl4965_priv *priv = hw->priv; + struct iwl_priv *priv = hw->priv; unsigned long flags; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); - if (!iwl4965_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); mutex_unlock(&priv->mutex); return -EIO; @@ -8196,9 +7397,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWL4965_QOS - iwl4965_reset_qos(priv); -#endif + iwlcore_reset_qos(priv); queue_work(priv->workqueue, &priv->post_associate.work); @@ -8207,111 +7406,13 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk return 0; } -#ifdef CONFIG_IWL4965_HT - -static void iwl4965_ht_info_fill(struct ieee80211_conf *conf, - struct iwl4965_priv *priv) -{ - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - struct ieee80211_ht_info *ht_conf = &conf->ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf; - - IWL_DEBUG_MAC80211("enter: \n"); - - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) { - iwl_conf->is_ht = 0; - return; - } - - iwl_conf->is_ht = 1; - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= 0x1; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= 0x2; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); - iwl_conf->tx_mimo_ps_mode = - (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); - - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); - iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; - iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); - - IWL_DEBUG_MAC80211("control channel %d\n", - iwl_conf->control_channel); - IWL_DEBUG_MAC80211("leave\n"); -} - -static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) -{ - struct iwl4965_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("enter: \n"); - - iwl4965_ht_info_fill(conf, priv); - iwl4965_set_rxon_chain(priv); - - if (priv && priv->assoc_id && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (priv->beacon_int) - queue_work(priv->workqueue, &priv->post_associate.work); - else - priv->call_post_assoc_from_beacon = 1; - spin_unlock_irqrestore(&priv->lock, flags); - } - - IWL_DEBUG_MAC80211("leave:\n"); - return 0; -} - -static void iwl4965_set_ht_capab(struct ieee80211_hw *hw, - struct ieee80211_ht_cap *ht_cap, - u8 use_current_config) -{ - struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_hw_mode *mode = conf->mode; - - if (use_current_config) { - ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap); - memcpy(ht_cap->supp_mcs_set, - conf->ht_conf.supp_mcs_set, 16); - } else { - ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap); - memcpy(ht_cap->supp_mcs_set, - mode->ht_info.supp_mcs_set, 16); - } - ht_cap->ampdu_params_info = - (mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | - ((mode->ht_info.ampdu_density << 2) & - IEEE80211_HT_CAP_AMPDU_DENSITY); -} - -#endif /*CONFIG_IWL4965_HT*/ - /***************************************************************************** * * sysfs attributes * *****************************************************************************/ -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG /* * The following adds a new attribute to the sysfs representation @@ -8323,7 +7424,7 @@ static void iwl4965_set_ht_capab(struct ieee80211_hw *hw, static ssize_t show_debug_level(struct device_driver *d, char *buf) { - return sprintf(buf, "0x%08X\n", iwl4965_debug_level); + return sprintf(buf, "0x%08X\n", iwl_debug_level); } static ssize_t store_debug_level(struct device_driver *d, const char *buf, size_t count) @@ -8336,7 +7437,7 @@ static ssize_t store_debug_level(struct device_driver *d, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - iwl4965_debug_level = val; + iwl_debug_level = val; return strnlen(buf, count); } @@ -8344,45 +7445,15 @@ static ssize_t store_debug_level(struct device_driver *d, static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, store_debug_level); -#endif /* CONFIG_IWL4965_DEBUG */ +#endif /* CONFIG_IWLWIFI_DEBUG */ -static ssize_t show_rf_kill(struct device *d, - struct device_attribute *attr, char *buf) -{ - /* - * 0 - RF kill not enabled - * 1 - SW based RF kill active (sysfs) - * 2 - HW based RF kill active - * 3 - Both HW and SW based RF kill active - */ - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | - (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); - - return sprintf(buf, "%i\n", val); -} - -static ssize_t store_rf_kill(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - - mutex_lock(&priv->mutex); - iwl4965_radio_kill_sw(priv, buf[0] == '1'); - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - if (!iwl4965_is_alive(priv)) + if (!iwl_is_alive(priv)) return -EAGAIN; return sprintf(buf, "%d\n", iwl4965_hw_get_temperature(priv)); @@ -8394,7 +7465,7 @@ static ssize_t show_rs_window(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = d->driver_data; + struct iwl_priv *priv = d->driver_data; return iwl4965_fill_rs_info(priv->hw, buf, IWL_AP_ID); } static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); @@ -8402,7 +7473,7 @@ static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; return sprintf(buf, "%d\n", priv->user_txpower_limit); } @@ -8410,7 +7481,7 @@ static ssize_t store_tx_power(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; char *p = (char *)buf; u32 val; @@ -8429,7 +7500,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); static ssize_t show_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -8438,7 +7509,7 @@ static ssize_t store_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; u32 flags = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); @@ -8463,7 +7534,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); static ssize_t show_filter_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -8473,7 +7544,7 @@ static ssize_t store_filter_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; u32 filter_flags = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); @@ -8497,71 +7568,12 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t show_tune(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", - (priv->phymode << 8) | - le16_to_cpu(priv->active_rxon.channel)); -} - -static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode); - -static ssize_t store_tune(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - char *p = (char *)buf; - u16 tune = simple_strtoul(p, &p, 0); - u8 phymode = (tune >> 8) & 0xff; - u16 channel = tune & 0xff; - - IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); - - mutex_lock(&priv->mutex); - if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || - (priv->phymode != phymode)) { - const struct iwl4965_channel_info *ch_info; - - ch_info = iwl4965_get_channel_info(priv, phymode, channel); - if (!ch_info) { - IWL_WARNING("Requested invalid phymode/channel " - "combination: %d %d\n", phymode, channel); - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - /* Cancel any currently running scans... */ - if (iwl4965_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing phymode and " - "rxon.channel = %d %d\n", - phymode, channel); - - iwl4965_set_rxon_channel(priv, phymode, channel); - iwl4965_set_flags_for_phymode(priv, phymode); - - iwl4965_set_rate(priv); - iwl4965_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); - #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT static ssize_t show_measurement(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); struct iwl4965_spectrum_notification measure_report; u32 size = sizeof(measure_report), len = 0, ofs = 0; u8 *data = (u8 *) & measure_report; @@ -8594,7 +7606,7 @@ static ssize_t store_measurement(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); struct ieee80211_measurement_params params = { .channel = le16_to_cpu(priv->active_rxon.channel), .start_time = cpu_to_le64(priv->last_tsf), @@ -8633,7 +7645,7 @@ static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); priv->retry_rate = simple_strtoul(buf, NULL, 0); if (priv->retry_rate <= 0) @@ -8645,7 +7657,7 @@ static ssize_t store_retry_rate(struct device *d, static ssize_t show_retry_rate(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%d", priv->retry_rate); } @@ -8656,14 +7668,14 @@ static ssize_t store_power_level(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); int rc; int mode; mode = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); - if (!iwl4965_is_ready(priv)) { + if (!iwl_is_ready(priv)) { rc = -EAGAIN; goto out; } @@ -8710,7 +7722,7 @@ static const s32 period_duration[] = { static ssize_t show_power_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); int level = IWL_POWER_LEVEL(priv->power_mode); char *p = buf; @@ -8745,73 +7757,8 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); - int len = 0, i; - struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode = NULL; - int count = 0; - - if (!iwl4965_is_ready(priv)) - return -EAGAIN; - - hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211G); - if (!hw_mode) - hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211B); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } - - len += - sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211A); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } else { - channels = NULL; - count = 0; - } - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - return len; + /* all this shit doesn't belong into sysfs anyway */ + return 0; } static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); @@ -8819,13 +7766,13 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); u32 size = sizeof(struct iwl4965_notif_statistics); u32 len = 0, ofs = 0; u8 *data = (u8 *) & priv->statistics; int rc = 0; - if (!iwl4965_is_alive(priv)) + if (!iwl_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); @@ -8857,9 +7804,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); static ssize_t show_antenna(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); - if (!iwl4965_is_alive(priv)) + if (!iwl_is_alive(priv)) return -EAGAIN; return sprintf(buf, "%d\n", priv->antenna); @@ -8870,7 +7817,7 @@ static ssize_t store_antenna(struct device *d, const char *buf, size_t count) { int ant; - struct iwl4965_priv *priv = dev_get_drvdata(d); + struct iwl_priv *priv = dev_get_drvdata(d); if (count == 0) return 0; @@ -8895,8 +7842,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - if (!iwl4965_is_alive(priv)) + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + if (!iwl_is_alive(priv)) return -EAGAIN; return sprintf(buf, "0x%08x\n", (int)priv->status); } @@ -8910,7 +7857,7 @@ static ssize_t dump_error_log(struct device *d, char *p = (char *)buf; if (p[0] == '1') - iwl4965_dump_nic_error_log((struct iwl4965_priv *)d->driver_data); + iwl4965_dump_nic_error_log((struct iwl_priv *)d->driver_data); return strnlen(buf, count); } @@ -8924,7 +7871,7 @@ static ssize_t dump_event_log(struct device *d, char *p = (char *)buf; if (p[0] == '1') - iwl4965_dump_nic_event_log((struct iwl4965_priv *)d->driver_data); + iwl4965_dump_nic_event_log((struct iwl_priv *)d->driver_data); return strnlen(buf, count); } @@ -8937,7 +7884,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); * *****************************************************************************/ -static void iwl4965_setup_deferred_work(struct iwl4965_priv *priv) +static void iwl4965_setup_deferred_work(struct iwl_priv *priv) { priv->workqueue = create_workqueue(DRV_NAME); @@ -8962,7 +7909,7 @@ static void iwl4965_setup_deferred_work(struct iwl4965_priv *priv) iwl4965_irq_tasklet, (unsigned long)priv); } -static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv) +static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) { iwl4965_hw_cancel_deferred_work(priv); @@ -8985,12 +7932,10 @@ static struct attribute *iwl4965_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, - &dev_attr_tune.attr, &dev_attr_tx_power.attr, NULL @@ -9011,6 +7956,7 @@ static struct ieee80211_ops iwl4965_hw_ops = { .config_interface = iwl4965_mac_config_interface, .configure_filter = iwl4965_configure_filter, .set_key = iwl4965_mac_set_key, + .update_tkip_key = iwl4965_mac_update_tkip_key, .get_stats = iwl4965_mac_get_stats, .get_tx_stats = iwl4965_mac_get_tx_stats, .conf_tx = iwl4965_mac_conf_tx, @@ -9019,12 +7965,7 @@ static struct ieee80211_ops iwl4965_hw_ops = { .beacon_update = iwl4965_mac_beacon_update, .bss_info_changed = iwl4965_bss_info_changed, #ifdef CONFIG_IWL4965_HT - .conf_ht = iwl4965_mac_conf_ht, .ampdu_action = iwl4965_mac_ampdu_action, -#ifdef CONFIG_IWL4965_HT_AGG - .ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start, - .ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop, -#endif /* CONFIG_IWL4965_HT_AGG */ #endif /* CONFIG_IWL4965_HT */ .hw_scan = iwl4965_mac_hw_scan }; @@ -9032,85 +7973,45 @@ static struct ieee80211_ops iwl4965_hw_ops = { static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; - struct iwl4965_priv *priv; + struct iwl_priv *priv; struct ieee80211_hw *hw; - int i; + struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); + unsigned long flags; DECLARE_MAC_BUF(mac); + /************************ + * 1. Allocating HW data + ************************/ + /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ - if (iwl4965_param_disable_hw_scan) { + if (cfg->mod_params->disable_hw_scan) { IWL_DEBUG_INFO("Disabling hw_scan\n"); iwl4965_hw_ops.hw_scan = NULL; } - if ((iwl4965_param_queues_num > IWL_MAX_NUM_QUEUES) || - (iwl4965_param_queues_num < IWL_MIN_NUM_QUEUES)) { - IWL_ERROR("invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); - err = -EINVAL; - goto out; - } - - /* mac80211 allocates memory for this device instance, including - * space for this driver's private structure */ - hw = ieee80211_alloc_hw(sizeof(struct iwl4965_priv), &iwl4965_hw_ops); - if (hw == NULL) { - IWL_ERROR("Can not allocate network device\n"); + hw = iwl_alloc_all(cfg, &iwl4965_hw_ops); + if (!hw) { err = -ENOMEM; goto out; } - SET_IEEE80211_DEV(hw, &pdev->dev); + priv = hw->priv; + /* At this point both hw and priv are allocated. */ - hw->rate_control_algorithm = "iwl-4965-rs"; + SET_IEEE80211_DEV(hw, &pdev->dev); IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); - priv = hw->priv; - priv->hw = hw; - + priv->cfg = cfg; priv->pci_dev = pdev; - priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna; -#ifdef CONFIG_IWL4965_DEBUG - iwl4965_debug_level = iwl4965_param_debug; + +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_debug_level = priv->cfg->mod_params->debug; atomic_set(&priv->restrict_refcnt, 0); #endif - priv->retry_rate = 1; - - priv->ibss_beacon = NULL; - - /* Tell mac80211 and its clients (e.g. Wireless Extensions) - * the range of signal quality values that we'll provide. - * Negative values for level/noise indicate that we'll provide dBm. - * For WE, at least, non-0 values here *enable* display of values - * in app (iwconfig). */ - hw->max_rssi = -20; /* signal level, negative indicates dBm */ - hw->max_noise = -20; /* noise level, negative indicates dBm */ - hw->max_signal = 100; /* link quality indication (%) */ - - /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; - - /* Default value; 4 EDCA QOS priorities */ - hw->queues = 4; -#ifdef CONFIG_IWL4965_HT -#ifdef CONFIG_IWL4965_HT_AGG - /* Enhanced value; more queues, to support 11n aggregation */ - hw->queues = 16; -#endif /* CONFIG_IWL4965_HT_AGG */ -#endif /* CONFIG_IWL4965_HT */ - - spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - spin_lock_init(&priv->lq_mngr.lock); - - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); + /************************** + * 2. Initializing PCI bus + **************************/ if (pci_enable_device(pdev)) { err = -ENODEV; goto out_ieee80211_free_hw; @@ -9118,31 +8019,28 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - /* Clear the driver's (not device's) station table */ - iwl4965_clear_stations_table(priv); - - priv->data_retry_limit = -1; - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->phymode = -1; - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (err) { - printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); - goto out_pci_disable_device; + if (err) { + printk(KERN_WARNING DRV_NAME + ": No suitable DMA available.\n"); + goto out_pci_disable_device; } - pci_set_drvdata(pdev, priv); err = pci_request_regions(pdev, DRV_NAME); if (err) goto out_pci_disable_device; + pci_set_drvdata(pdev, priv); + /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, 0x41, 0x00); + /*********************** + * 3. Read REV register + ***********************/ priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -9150,132 +8048,112 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e } IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", - (unsigned long long) pci_resource_len(pdev, 0)); + (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); - /* Initialize module parameter values here */ + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (iwl4965_param_disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO("Radio disabled.\n"); + /***************** + * 4. Read EEPROM + *****************/ + /* nic init */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out_iounmap; } + /* Read the EEPROM */ + err = iwl_eeprom_init(priv); + if (err) { + IWL_ERROR("Unable to init EEPROM\n"); + goto out_iounmap; + } + /* MAC Address location in EEPROM same for 3945/4965 */ + iwl_eeprom_get_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - priv->iw_mode = IEEE80211_IF_TYPE_STA; - - priv->ps_mode = 0; - priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->valid_antenna = 0x7; /* assume all 3 connected */ - priv->ps_mode = IWL_MIMO_PS_NONE; - - /* Choose which receivers/antennas to use */ - iwl4965_set_rxon_chain(priv); - - printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link 4965AGN\n"); - + /************************ + * 5. Setup HW constants + ************************/ /* Device-specific setup */ if (iwl4965_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); goto out_iounmap; } -#ifdef CONFIG_IWL4965_QOS - if (iwl4965_param_qos_enable) - priv->qos_data.qos_enable = 1; + /******************* + * 6. Setup hw/priv + *******************/ - iwl4965_reset_qos(priv); + err = iwl_setup(priv); + if (err) + goto out_unset_hw_settings; + /* At this point both hw and priv are initialized. */ - priv->qos_data.qos_active = 0; - priv->qos_data.qos_cap.val = 0; -#endif /* CONFIG_IWL4965_QOS */ + /********************************** + * 7. Initialize module parameters + **********************************/ - iwl4965_set_rxon_channel(priv, MODE_IEEE80211G, 6); - iwl4965_setup_deferred_work(priv); - iwl4965_setup_rx_handlers(priv); + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (priv->cfg->mod_params->disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); + } - priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to AC mode */ - priv->power_mode = IWL_POWER_AC; - priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + if (priv->cfg->mod_params->enable_qos) + priv->qos_data.qos_enable = 1; + /******************** + * 8. Setup services + ********************/ + spin_lock_irqsave(&priv->lock, flags); iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - goto out_release_irq; - } - - /* nic init */ - iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl4965_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); - goto out_remove_sysfs; - } - /* Read the EEPROM */ - err = iwl4965_eeprom_init(priv); - if (err) { - IWL_ERROR("Unable to init EEPROM\n"); - goto out_remove_sysfs; + goto out_unset_hw_settings; } - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); - SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - err = iwl4965_init_channel_map(priv); + err = iwl_dbgfs_register(priv, DRV_NAME); if (err) { - IWL_ERROR("initializing regulatory failed: %d\n", err); + IWL_ERROR("failed to create debugfs files\n"); goto out_remove_sysfs; } - err = iwl4965_init_geos(priv); - if (err) { - IWL_ERROR("initializing geos failed: %d\n", err); - goto out_free_channel_map; - } - iwl4965_reset_channel_flag(priv); - - iwl4965_rate_control_register(priv->hw); - err = ieee80211_register_hw(priv->hw); - if (err) { - IWL_ERROR("Failed to register network device (error %d)\n", err); - goto out_free_geos; - } + iwl4965_setup_deferred_work(priv); + iwl4965_setup_rx_handlers(priv); - priv->hw->conf.beacon_int = 100; - priv->mac80211_registered = 1; + /******************** + * 9. Conclude + ********************/ pci_save_state(pdev); pci_disable_device(pdev); + /* notify iwlcore to init */ + iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT); return 0; - out_free_geos: - iwl4965_free_geos(priv); - out_free_channel_map: - iwl4965_free_channel_map(priv); out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - - out_release_irq: - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; + out_unset_hw_settings: iwl4965_unset_hw_setting(priv); - out_iounmap: pci_iounmap(pdev, priv->hw_base); out_pci_release_regions: pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); out_pci_disable_device: pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); out: @@ -9284,19 +8162,34 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) { - struct iwl4965_priv *priv = pci_get_drvdata(pdev); + struct iwl_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; int i; + unsigned long flags; if (!priv) return; IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + priv->mac80211_registered = 0; + } + set_bit(STATUS_EXIT_PENDING, &priv->status); iwl4965_down(priv); + /* make sure we flush any pending irq or + * tasklet for the driver + */ + spin_lock_irqsave(&priv->lock, flags); + iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_synchronize_irq(priv); + /* Free MAC hash list for ADHOC */ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { @@ -9305,6 +8198,8 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) } } + iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT); + iwl_dbgfs_unregister(priv); sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); iwl4965_dealloc_ucode_pci(priv); @@ -9314,12 +8209,8 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl4965_hw_txq_ctx_free(priv); iwl4965_unset_hw_setting(priv); - iwl4965_clear_stations_table(priv); + iwlcore_clear_stations_table(priv); - if (priv->mac80211_registered) { - ieee80211_unregister_hw(priv->hw); - iwl4965_rate_control_unregister(priv->hw); - } /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); @@ -9335,7 +8226,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - iwl4965_free_channel_map(priv); + iwl_free_channel_map(priv); iwl4965_free_geos(priv); if (priv->ibss_beacon) @@ -9348,7 +8239,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct iwl4965_priv *priv = pci_get_drvdata(pdev); + struct iwl_priv *priv = pci_get_drvdata(pdev); if (priv->is_open) { set_bit(STATUS_IN_SUSPEND, &priv->status); @@ -9363,7 +8254,7 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int iwl4965_pci_resume(struct pci_dev *pdev) { - struct iwl4965_priv *priv = pci_get_drvdata(pdev); + struct iwl_priv *priv = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); @@ -9399,51 +8290,45 @@ static int __init iwl4965_init(void) int ret; printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + ret = iwl4965_rate_control_register(); + if (ret) { + IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); + return ret; + } + ret = pci_register_driver(&iwl4965_driver); if (ret) { IWL_ERROR("Unable to initialize PCI module\n"); - return ret; + goto error_register; } -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level); if (ret) { IWL_ERROR("Unable to create driver sysfs file\n"); - pci_unregister_driver(&iwl4965_driver); - return ret; + goto error_debug; } #endif return ret; + +#ifdef CONFIG_IWLWIFI_DEBUG +error_debug: + pci_unregister_driver(&iwl4965_driver); +#endif +error_register: + iwl4965_rate_control_unregister(); + return ret; } static void __exit iwl4965_exit(void) { -#ifdef CONFIG_IWL4965_DEBUG +#ifdef CONFIG_IWLWIFI_DEBUG driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level); #endif pci_unregister_driver(&iwl4965_driver); + iwl4965_rate_control_unregister(); } -module_param_named(antenna, iwl4965_param_antenna, int, 0444); -MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl4965_param_disable, int, 0444); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); -module_param_named(hwcrypto, iwl4965_param_hwcrypto, int, 0444); -MODULE_PARM_DESC(hwcrypto, - "using hardware crypto engine (default 0 [software])\n"); -module_param_named(debug, iwl4965_param_debug, int, 0444); -MODULE_PARM_DESC(debug, "debug output mask"); -module_param_named(disable_hw_scan, iwl4965_param_disable_hw_scan, int, 0444); -MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); - -module_param_named(queues_num, iwl4965_param_queues_num, int, 0444); -MODULE_PARM_DESC(queues_num, "number of hw queues."); - -/* QoS */ -module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); -module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444); -MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); - module_exit(iwl4965_exit); module_init(iwl4965_init); diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 5e10ce0d351..4bc46a60ae2 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -79,7 +79,7 @@ static u8 *lbs_code_2_region(u8 code) * @param nrchan number of channels * @return the nrchan-th chan number */ -static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan) +static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan) /*find the nrchan-th chan after the firstchan*/ { u8 i; @@ -134,7 +134,7 @@ static u8 lbs_channel_known_11d(u8 chan, return 0; } -u32 lbs_chan_2_freq(u8 chan, u8 band) +u32 lbs_chan_2_freq(u8 chan) { struct chan_freq_power *cf; u16 i; @@ -264,7 +264,7 @@ static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_ch * @param chan chan * @return TRUE;FALSE */ -static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan) +static u8 lbs_region_chan_supported_11d(u8 region, u8 chan) { struct chan_freq_power *cfp; int cfp_no; @@ -273,7 +273,7 @@ static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan) lbs_deb_enter(LBS_DEB_11D); - cfp = lbs_get_region_cfp_table(region, band, &cfp_no); + cfp = lbs_get_region_cfp_table(region, &cfp_no); if (cfp == NULL) return 0; @@ -367,7 +367,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { /*step4: channel is supported? */ - if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) { + if (!lbs_get_chan_11d(firstchan, i, &curchan)) { /* Chan is not found in UN table */ lbs_deb_11d("chan is not supported: %d \n", i); break; @@ -375,8 +375,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* lastchan = curchan; - if (lbs_region_chan_supported_11d - (region, band, curchan)) { + if (lbs_region_chan_supported_11d(region, curchan)) { /*step5: Check if curchan is supported by mrvl in region */ parsed_region_chan->chanpwr[idx].chan = curchan; parsed_region_chan->chanpwr[idx].pwr = @@ -554,8 +553,7 @@ done: * @param resp pointer to command response buffer * @return 0; -1 */ -int lbs_ret_802_11d_domain_info(struct lbs_private *priv, - struct cmd_ds_command *resp) +int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) { struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; struct mrvlietypes_domainparamset *domain = &domaininfo->domain; diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 811eea2cfba..4f4f47f0f87 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -83,7 +83,7 @@ struct lbs_private; u8 lbs_get_scan_type_11d(u8 chan, struct parsed_region_chan_11d *parsed_region_chan); -u32 lbs_chan_2_freq(u8 chan, u8 band); +u32 lbs_chan_2_freq(u8 chan); void lbs_init_11d(struct lbs_private *priv); @@ -93,8 +93,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmdno, u16 cmdOption); -int lbs_ret_802_11d_domain_info(struct lbs_private *priv, - struct cmd_ds_command *resp); +int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp); struct bss_descriptor; int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 0e2787691f9..f0724e31adf 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,7 +1,7 @@ libertas-objs := main.o wext.o \ rx.o tx.o cmd.o \ cmdresp.o scan.o \ - join.o 11d.o \ + 11d.o \ debugfs.o \ ethtool.o assoc.o diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 6a24ed6067e..c9c3640ce9f 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1,14 +1,11 @@ /* Copyright (C) 2006, Red Hat, Inc. */ -#include <linux/bitops.h> -#include <net/ieee80211.h> #include <linux/etherdevice.h> #include "assoc.h" -#include "join.h" #include "decl.h" -#include "hostcmd.h" #include "host.h" +#include "scan.h" #include "cmd.h" @@ -17,6 +14,428 @@ static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* The firmware needs certain bits masked out of the beacon-derviced capability + * field when associating/joining to BSSs. + */ +#define CAPINFO_MASK (~(0xda00)) + + + +/** + * @brief Associate to a specific BSS discovered in a scan + * + * @param priv A pointer to struct lbs_private structure + * @param pbssdesc Pointer to the BSS descriptor to associate with. + * + * @return 0-success, otherwise fail + */ +static int lbs_associate(struct lbs_private *priv, + struct assoc_request *assoc_req) +{ + int ret; + + lbs_deb_enter(LBS_DEB_ASSOC); + + ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, + 0, CMD_OPTION_WAITFORRSP, + 0, assoc_req->bss.bssid); + + if (ret) + goto done; + + /* set preamble to firmware */ + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + else + priv->preamble = CMD_TYPE_LONG_PREAMBLE; + + lbs_set_radio_control(priv); + + ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + +/** + * @brief Join an adhoc network found in a previous scan + * + * @param priv A pointer to struct lbs_private structure + * @param pbssdesc Pointer to a BSS descriptor found in a previous scan + * to attempt to join + * + * @return 0--success, -1--fail + */ +static int lbs_join_adhoc_network(struct lbs_private *priv, + struct assoc_request *assoc_req) +{ + struct bss_descriptor *bss = &assoc_req->bss; + int ret = 0; + + lbs_deb_join("current SSID '%s', ssid length %u\n", + escape_essid(priv->curbssparams.ssid, + priv->curbssparams.ssid_len), + priv->curbssparams.ssid_len); + lbs_deb_join("requested ssid '%s', ssid length %u\n", + escape_essid(bss->ssid, bss->ssid_len), + bss->ssid_len); + + /* check if the requested SSID is already joined */ + if (priv->curbssparams.ssid_len && + !lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, + bss->ssid, bss->ssid_len) && + (priv->mode == IW_MODE_ADHOC) && + (priv->connect_status == LBS_CONNECTED)) { + union iwreq_data wrqu; + + lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " + "current, not attempting to re-join"); + + /* Send the re-association event though, because the association + * request really was successful, even if just a null-op. + */ + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, + ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + goto out; + } + + /* Use shortpreamble only when both creator and card supports + short preamble */ + if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || + !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { + lbs_deb_join("AdhocJoin: Long preamble\n"); + priv->preamble = CMD_TYPE_LONG_PREAMBLE; + } else { + lbs_deb_join("AdhocJoin: Short preamble\n"); + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + } + + lbs_set_radio_control(priv); + + lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); + lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); + + priv->adhoccreate = 0; + + ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, + 0, CMD_OPTION_WAITFORRSP, + OID_802_11_SSID, assoc_req); + +out: + return ret; +} + +/** + * @brief Start an Adhoc Network + * + * @param priv A pointer to struct lbs_private structure + * @param adhocssid The ssid of the Adhoc Network + * @return 0--success, -1--fail + */ +static int lbs_start_adhoc_network(struct lbs_private *priv, + struct assoc_request *assoc_req) +{ + int ret = 0; + + priv->adhoccreate = 1; + + if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { + lbs_deb_join("AdhocStart: Short preamble\n"); + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + } else { + lbs_deb_join("AdhocStart: Long preamble\n"); + priv->preamble = CMD_TYPE_LONG_PREAMBLE; + } + + lbs_set_radio_control(priv); + + lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); + lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); + + ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + + return ret; +} + +int lbs_stop_adhoc_network(struct lbs_private *priv) +{ + return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); +} + +static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, + struct bss_descriptor *match_bss) +{ + if (!secinfo->wep_enabled && !secinfo->WPAenabled + && !secinfo->WPA2enabled + && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC + && match_bss->rsn_ie[0] != MFIE_TYPE_RSN + && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + return 1; + else + return 0; +} + +static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, + struct bss_descriptor *match_bss) +{ + if (secinfo->wep_enabled && !secinfo->WPAenabled + && !secinfo->WPA2enabled + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + return 1; + else + return 0; +} + +static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, + struct bss_descriptor *match_bss) +{ + if (!secinfo->wep_enabled && secinfo->WPAenabled + && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) + /* privacy bit may NOT be set in some APs like LinkSys WRT54G + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ + ) + return 1; + else + return 0; +} + +static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, + struct bss_descriptor *match_bss) +{ + if (!secinfo->wep_enabled && secinfo->WPA2enabled && + (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) + /* privacy bit may NOT be set in some APs like LinkSys WRT54G + (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ + ) + return 1; + else + return 0; +} + +static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, + struct bss_descriptor *match_bss) +{ + if (!secinfo->wep_enabled && !secinfo->WPAenabled + && !secinfo->WPA2enabled + && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) + && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + return 1; + else + return 0; +} + +/** + * @brief Check if a scanned network compatible with the driver settings + * + * WEP WPA WPA2 ad-hoc encrypt Network + * enabled enabled enabled AES mode privacy WPA WPA2 Compatible + * 0 0 0 0 NONE 0 0 0 yes No security + * 1 0 0 0 NONE 1 0 0 yes Static WEP + * 0 1 0 0 x 1x 1 x yes WPA + * 0 0 1 0 x 1x x 1 yes WPA2 + * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES + * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * + * @param priv A pointer to struct lbs_private + * @param index Index in scantable to check against current driver settings + * @param mode Network mode: Infrastructure or IBSS + * + * @return Index in scantable, or error code if negative + */ +static int is_network_compatible(struct lbs_private *priv, + struct bss_descriptor *bss, uint8_t mode) +{ + int matched = 0; + + lbs_deb_enter(LBS_DEB_SCAN); + + if (bss->mode != mode) + goto done; + + matched = match_bss_no_security(&priv->secinfo, bss); + if (matched) + goto done; + matched = match_bss_static_wep(&priv->secinfo, bss); + if (matched) + goto done; + matched = match_bss_wpa(&priv->secinfo, bss); + if (matched) { + lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x " + "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " + "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", + (bss->capability & WLAN_CAPABILITY_PRIVACY)); + goto done; + } + matched = match_bss_wpa2(&priv->secinfo, bss); + if (matched) { + lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x " + "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " + "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", + (bss->capability & WLAN_CAPABILITY_PRIVACY)); + goto done; + } + matched = match_bss_dynamic_wep(&priv->secinfo, bss); + if (matched) { + lbs_deb_scan("is_network_compatible() dynamic WEP: " + "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", + bss->wpa_ie[0], bss->rsn_ie[0], + (bss->capability & WLAN_CAPABILITY_PRIVACY)); + goto done; + } + + /* bss security settings don't match those configured on card */ + lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x " + "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", + bss->wpa_ie[0], bss->rsn_ie[0], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", + (bss->capability & WLAN_CAPABILITY_PRIVACY)); + +done: + lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); + return matched; +} + +/** + * @brief This function finds a specific compatible BSSID in the scan list + * + * Used in association code + * + * @param priv A pointer to struct lbs_private + * @param bssid BSSID to find in the scan list + * @param mode Network mode: Infrastructure or IBSS + * + * @return index in BSSID list, or error return code (< 0) + */ +static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, + uint8_t *bssid, uint8_t mode) +{ + struct bss_descriptor *iter_bss; + struct bss_descriptor *found_bss = NULL; + + lbs_deb_enter(LBS_DEB_SCAN); + + if (!bssid) + goto out; + + lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); + + /* Look through the scan table for a compatible match. The loop will + * continue past a matched bssid that is not compatible in case there + * is an AP with multiple SSIDs assigned to the same BSSID + */ + mutex_lock(&priv->lock); + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (compare_ether_addr(iter_bss->bssid, bssid)) + continue; /* bssid doesn't match */ + switch (mode) { + case IW_MODE_INFRA: + case IW_MODE_ADHOC: + if (!is_network_compatible(priv, iter_bss, mode)) + break; + found_bss = iter_bss; + break; + default: + found_bss = iter_bss; + break; + } + } + mutex_unlock(&priv->lock); + +out: + lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); + return found_bss; +} + +/** + * @brief This function finds ssid in ssid list. + * + * Used in association code + * + * @param priv A pointer to struct lbs_private + * @param ssid SSID to find in the list + * @param bssid BSSID to qualify the SSID selection (if provided) + * @param mode Network mode: Infrastructure or IBSS + * + * @return index in BSSID list + */ +static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, + uint8_t *ssid, uint8_t ssid_len, + uint8_t *bssid, uint8_t mode, + int channel) +{ + u32 bestrssi = 0; + struct bss_descriptor *iter_bss = NULL; + struct bss_descriptor *found_bss = NULL; + struct bss_descriptor *tmp_oldest = NULL; + + lbs_deb_enter(LBS_DEB_SCAN); + + mutex_lock(&priv->lock); + + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (!tmp_oldest || + (iter_bss->last_scanned < tmp_oldest->last_scanned)) + tmp_oldest = iter_bss; + + if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, + ssid, ssid_len) != 0) + continue; /* ssid doesn't match */ + if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) + continue; /* bssid doesn't match */ + if ((channel > 0) && (iter_bss->channel != channel)) + continue; /* channel doesn't match */ + + switch (mode) { + case IW_MODE_INFRA: + case IW_MODE_ADHOC: + if (!is_network_compatible(priv, iter_bss, mode)) + break; + + if (bssid) { + /* Found requested BSSID */ + found_bss = iter_bss; + goto out; + } + + if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { + bestrssi = SCAN_RSSI(iter_bss->rssi); + found_bss = iter_bss; + } + break; + case IW_MODE_AUTO: + default: + if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { + bestrssi = SCAN_RSSI(iter_bss->rssi); + found_bss = iter_bss; + } + break; + } + } + +out: + mutex_unlock(&priv->lock); + lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); + return found_bss; +} static int assoc_helper_essid(struct lbs_private *priv, struct assoc_request * assoc_req) @@ -38,7 +457,7 @@ static int assoc_helper_essid(struct lbs_private *priv, escape_essid(assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { lbs_send_specific_ssid_scan(priv, assoc_req->ssid, - assoc_req->ssid_len, 0); + assoc_req->ssid_len); bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); @@ -53,7 +472,7 @@ static int assoc_helper_essid(struct lbs_private *priv, * scan data will cause us to join a non-existant adhoc network */ lbs_send_specific_ssid_scan(priv, assoc_req->ssid, - assoc_req->ssid_len, 1); + assoc_req->ssid_len); /* Search for the requested SSID in the scan table */ bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, @@ -164,34 +583,6 @@ done: return ret; } - -int lbs_update_channel(struct lbs_private *priv) -{ - int ret; - - /* the channel in f/w could be out of sync; get the current channel */ - lbs_deb_enter(LBS_DEB_ASSOC); - - ret = lbs_get_channel(priv); - if (ret > 0) { - priv->curbssparams.channel = ret; - ret = 0; - } - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -void lbs_sync_channel(struct work_struct *work) -{ - struct lbs_private *priv = container_of(work, struct lbs_private, - sync_channel); - - lbs_deb_enter(LBS_DEB_ASSOC); - if (lbs_update_channel(priv)) - lbs_pr_info("Channel synchronization failed."); - lbs_deb_leave(LBS_DEB_ASSOC); -} - static int assoc_helper_channel(struct lbs_private *priv, struct assoc_request * assoc_req) { @@ -279,13 +670,11 @@ static int assoc_helper_wep_keys(struct lbs_private *priv, /* enable/disable the MAC's WEP packet filter */ if (assoc_req->secinfo.wep_enabled) - priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE; + priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE; else - priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE; + priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE; - ret = lbs_set_mac_packet_filter(priv); - if (ret) - goto out; + lbs_set_mac_control(priv); mutex_lock(&priv->lock); @@ -315,9 +704,7 @@ static int assoc_helper_secinfo(struct lbs_private *priv, memcpy(&priv->secinfo, &assoc_req->secinfo, sizeof(struct lbs_802_11_security)); - ret = lbs_set_mac_packet_filter(priv); - if (ret) - goto out; + lbs_set_mac_control(priv); /* If RSN is already enabled, don't try to enable it again, since * ENABLE_RSN resets internal state machines and will clobber the @@ -360,11 +747,7 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv, if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_KEY_MATERIAL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - 0, assoc_req); + ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); assoc_req->flags = flags; } @@ -374,11 +757,7 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv, if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_KEY_MATERIAL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - 0, assoc_req); + ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); assoc_req->flags = flags; } @@ -413,11 +792,10 @@ static int should_deauth_infrastructure(struct lbs_private *priv, { int ret = 0; - lbs_deb_enter(LBS_DEB_ASSOC); - if (priv->connect_status != LBS_CONNECTED) return 0; + lbs_deb_enter(LBS_DEB_ASSOC); if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { lbs_deb_assoc("Deauthenticating due to new SSID\n"); ret = 1; @@ -456,7 +834,7 @@ static int should_deauth_infrastructure(struct lbs_private *priv, out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return 0; + return ret; } @@ -489,6 +867,91 @@ static int should_stop_adhoc(struct lbs_private *priv, } +/** + * @brief This function finds the best SSID in the Scan List + * + * Search the scan table for the best SSID that also matches the current + * adapter network preference (infrastructure or adhoc) + * + * @param priv A pointer to struct lbs_private + * + * @return index in BSSID list + */ +static struct bss_descriptor *lbs_find_best_ssid_in_list( + struct lbs_private *priv, uint8_t mode) +{ + uint8_t bestrssi = 0; + struct bss_descriptor *iter_bss; + struct bss_descriptor *best_bss = NULL; + + lbs_deb_enter(LBS_DEB_SCAN); + + mutex_lock(&priv->lock); + + list_for_each_entry(iter_bss, &priv->network_list, list) { + switch (mode) { + case IW_MODE_INFRA: + case IW_MODE_ADHOC: + if (!is_network_compatible(priv, iter_bss, mode)) + break; + if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) + break; + bestrssi = SCAN_RSSI(iter_bss->rssi); + best_bss = iter_bss; + break; + case IW_MODE_AUTO: + default: + if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) + break; + bestrssi = SCAN_RSSI(iter_bss->rssi); + best_bss = iter_bss; + break; + } + } + + mutex_unlock(&priv->lock); + lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); + return best_bss; +} + +/** + * @brief Find the best AP + * + * Used from association worker. + * + * @param priv A pointer to struct lbs_private structure + * @param pSSID A pointer to AP's ssid + * + * @return 0--success, otherwise--fail + */ +static int lbs_find_best_network_ssid(struct lbs_private *priv, + uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode, + uint8_t *out_mode) +{ + int ret = -1; + struct bss_descriptor *found; + + lbs_deb_enter(LBS_DEB_SCAN); + + priv->scan_ssid_len = 0; + lbs_scan_networks(priv, 1); + if (priv->surpriseremoved) + goto out; + + found = lbs_find_best_ssid_in_list(priv, preferred_mode); + if (found && (found->ssid_len > 0)) { + memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); + *out_ssid_len = found->ssid_len; + *out_mode = found->mode; + ret = 0; + } + +out: + lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); + return ret; +} + + void lbs_association_worker(struct work_struct *work) { struct lbs_private *priv = container_of(work, struct lbs_private, @@ -643,17 +1106,11 @@ void lbs_association_worker(struct work_struct *work) } if (success) { - lbs_deb_assoc("ASSOC: associated to '%s', %s\n", - escape_essid(priv->curbssparams.ssid, - priv->curbssparams.ssid_len), + lbs_deb_assoc("associated to %s\n", print_mac(mac, priv->curbssparams.bssid)); lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); - - lbs_prepare_and_send_command(priv, - CMD_802_11_GET_LOG, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); } else { ret = -1; } @@ -752,3 +1209,705 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) lbs_deb_leave(LBS_DEB_ASSOC); return assoc_req; } + + +/** + * @brief This function finds common rates between rate1 and card rates. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param priv A pointer to struct lbs_private structure + * @param rate1 the buffer which keeps input and output + * @param rate1_size the size of rate1 buffer; new size of buffer on return + * + * @return 0 or -1 + */ +static int get_common_rates(struct lbs_private *priv, + u8 *rates, + u16 *rates_size) +{ + u8 *card_rates = lbs_bg_rates; + size_t num_card_rates = sizeof(lbs_bg_rates); + int ret = 0, i, j; + u8 tmp[30]; + size_t tmp_size = 0; + + /* For each rate in card_rates that exists in rate1, copy to tmp */ + for (i = 0; card_rates[i] && (i < num_card_rates); i++) { + for (j = 0; rates[j] && (j < *rates_size); j++) { + if (rates[j] == card_rates[i]) + tmp[tmp_size++] = card_rates[i]; + } + } + + lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + + if (!priv->auto_rate) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == priv->cur_rate) + goto done; + } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + ret = -1; + goto done; + } + ret = 0; + +done: + memset(rates, 0, *rates_size); + *rates_size = min_t(int, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + return ret; +} + + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void lbs_set_basic_rate_flags(u8 *rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + +/** + * @brief Send Deauthentication Request + * + * @param priv A pointer to struct lbs_private structure + * @return 0--success, -1--fail + */ +int lbs_send_deauthentication(struct lbs_private *priv) +{ + return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); +} + +/** + * @brief This function prepares command of authenticate. + * + * @param priv A pointer to struct lbs_private structure + * @param cmd A pointer to cmd_ds_command structure + * @param pdata_buf Void cast of pointer to a BSSID to authenticate with + * + * @return 0 or -1 + */ +int lbs_cmd_80211_authenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf) +{ + struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; + int ret = -1; + u8 *bssid = pdata_buf; + DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + + cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) + + S_DS_GEN); + + /* translate auth mode to 802.11 defined wire value */ + switch (priv->secinfo.auth_mode) { + case IW_AUTH_ALG_OPEN_SYSTEM: + pauthenticate->authtype = 0x00; + break; + case IW_AUTH_ALG_SHARED_KEY: + pauthenticate->authtype = 0x01; + break; + case IW_AUTH_ALG_LEAP: + pauthenticate->authtype = 0x80; + break; + default: + lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", + priv->secinfo.auth_mode); + goto out; + } + + memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bssid), pauthenticate->authtype); + ret = 0; + +out: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd) +{ + struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + + lbs_deb_enter(LBS_DEB_JOIN); + + cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* set AP MAC address */ + memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); + + /* Reason code 3 = Station is leaving */ +#define REASON_CODE_STA_LEAVING 3 + dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); + + lbs_deb_leave(LBS_DEB_JOIN); + return 0; +} + +int lbs_cmd_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) +{ + struct cmd_ds_802_11_associate *passo = &cmd->params.associate; + int ret = 0; + struct assoc_request *assoc_req = pdata_buf; + struct bss_descriptor *bss = &assoc_req->bss; + u8 *pos; + u16 tmpcap, tmplen; + struct mrvlietypes_ssidparamset *ssid; + struct mrvlietypes_phyparamset *phy; + struct mrvlietypes_ssparamset *ss; + struct mrvlietypes_ratesparamset *rates; + struct mrvlietypes_rsnparamset *rsn; + + lbs_deb_enter(LBS_DEB_ASSOC); + + pos = (u8 *) passo; + + if (!priv) { + ret = -1; + goto done; + } + + cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); + + memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); + pos += sizeof(passo->peerstaaddr); + + /* set the listen interval */ + passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); + + pos += sizeof(passo->capability); + pos += sizeof(passo->listeninterval); + pos += sizeof(passo->bcnperiod); + pos += sizeof(passo->dtimperiod); + + ssid = (struct mrvlietypes_ssidparamset *) pos; + ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); + tmplen = bss->ssid_len; + ssid->header.len = cpu_to_le16(tmplen); + memcpy(ssid->ssid, bss->ssid, tmplen); + pos += sizeof(ssid->header) + tmplen; + + phy = (struct mrvlietypes_phyparamset *) pos; + phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); + tmplen = sizeof(phy->fh_ds.dsparamset); + phy->header.len = cpu_to_le16(tmplen); + memcpy(&phy->fh_ds.dsparamset, + &bss->phyparamset.dsparamset.currentchan, + tmplen); + pos += sizeof(phy->header) + tmplen; + + ss = (struct mrvlietypes_ssparamset *) pos; + ss->header.type = cpu_to_le16(TLV_TYPE_CF); + tmplen = sizeof(ss->cf_ibss.cfparamset); + ss->header.len = cpu_to_le16(tmplen); + pos += sizeof(ss->header) + tmplen; + + rates = (struct mrvlietypes_ratesparamset *) pos; + rates->header.type = cpu_to_le16(TLV_TYPE_RATES); + memcpy(&rates->rates, &bss->rates, MAX_RATES); + tmplen = MAX_RATES; + if (get_common_rates(priv, rates->rates, &tmplen)) { + ret = -1; + goto done; + } + pos += sizeof(rates->header) + tmplen; + rates->header.len = cpu_to_le16(tmplen); + lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); + + /* Copy the infra. association rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(rates->rates, tmplen); + + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { + rsn = (struct mrvlietypes_rsnparamset *) pos; + /* WPA_IE or WPA2_IE */ + rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); + tmplen = (u16) assoc_req->wpa_ie[1]; + rsn->header.len = cpu_to_le16(tmplen); + memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, + sizeof(rsn->header) + tmplen); + pos += sizeof(rsn->header) + tmplen; + } + + /* update curbssparams */ + priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } + + cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); + + /* set the capability info */ + tmpcap = (bss->capability & CAPINFO_MASK); + if (bss->mode == IW_MODE_INFRA) + tmpcap |= WLAN_CAPABILITY_ESS; + passo->capability = cpu_to_le16(tmpcap); + lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + +int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) +{ + struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; + int ret = 0; + int cmdappendsize = 0; + struct assoc_request *assoc_req = pdata_buf; + u16 tmpcap = 0; + size_t ratesize = 0; + + lbs_deb_enter(LBS_DEB_JOIN); + + if (!priv) { + ret = -1; + goto done; + } + + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); + + /* + * Fill in the parameters for 2 data structures: + * 1. cmd_ds_802_11_ad_hoc_start command + * 2. priv->scantable[i] + * + * Driver will fill up SSID, bsstype,IBSS param, Physical Param, + * probe delay, and cap info. + * + * Firmware will fill up beacon period, DTIM, Basic rates + * and operational rates. + */ + + memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); + memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); + + lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->ssid_len); + + /* set the BSS type */ + adhs->bsstype = CMD_BSS_TYPE_IBSS; + priv->mode = IW_MODE_ADHOC; + if (priv->beacon_period == 0) + priv->beacon_period = MRVDRV_BEACON_INTERVAL; + adhs->beaconperiod = cpu_to_le16(priv->beacon_period); + + /* set Physical param set */ +#define DS_PARA_IE_ID 3 +#define DS_PARA_IE_LEN 1 + + adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; + adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; + + WARN_ON(!assoc_req->channel); + + lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n", + assoc_req->channel); + + adhs->phyparamset.dsparamset.currentchan = assoc_req->channel; + + /* set IBSS param set */ +#define IBSS_PARA_IE_ID 6 +#define IBSS_PARA_IE_LEN 2 + + adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; + adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; + adhs->ssparamset.ibssparamset.atimwindow = 0; + + /* set capability info */ + tmpcap = WLAN_CAPABILITY_IBSS; + if (assoc_req->secinfo.wep_enabled) { + lbs_deb_join("ADHOC_S_CMD: WEP enabled, " + "setting privacy on\n"); + tmpcap |= WLAN_CAPABILITY_PRIVACY; + } else { + lbs_deb_join("ADHOC_S_CMD: WEP disabled, " + "setting privacy off\n"); + } + adhs->capability = cpu_to_le16(tmpcap); + + /* probedelay */ + adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + + memset(adhs->rates, 0, sizeof(adhs->rates)); + ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); + memcpy(adhs->rates, lbs_bg_rates, ratesize); + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(adhs->rates, ratesize); + + lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", + adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); + + lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); + + if (lbs_create_dnld_countryinfo_11d(priv)) { + lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); + ret = -1; + goto done; + } + + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + + S_DS_GEN + cmdappendsize); + + ret = 0; +done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + +int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); + cmd->size = cpu_to_le16(S_DS_GEN); + + return 0; +} + +int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) +{ + struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; + struct assoc_request *assoc_req = pdata_buf; + struct bss_descriptor *bss = &assoc_req->bss; + int cmdappendsize = 0; + int ret = 0; + u16 ratesize = 0; + DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); + + join_cmd->bss.type = CMD_BSS_TYPE_IBSS; + join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); + + memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); + + memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); + + memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + + join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); + lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + bss->capability, CAPINFO_MASK); + + /* information on BSSID descriptor passed to FW */ + lbs_deb_join( + "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, join_cmd->bss.bssid), + join_cmd->bss.ssid); + + /* failtimeout */ + join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + + /* probedelay */ + join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + + priv->curbssparams.channel = bss->channel; + + /* Copy Data rates from the rates recorded in scan response */ + memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); + ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); + memcpy(join_cmd->bss.rates, bss->rates, ratesize); + if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { + lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); + ret = -1; + goto done; + } + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); + + join_cmd->bss.ssparamset.ibssparamset.atimwindow = + cpu_to_le16(bss->atimwindow); + + if (assoc_req->secinfo.wep_enabled) { + u16 tmp = le16_to_cpu(join_cmd->bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + join_cmd->bss.capability = cpu_to_le16(tmp); + } + + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + /* wake up first */ + __le32 Localpsmode; + + Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); + ret = lbs_prepare_and_send_command(priv, + CMD_802_11_PS_MODE, + CMD_ACT_SET, + 0, 0, &Localpsmode); + + if (ret) { + ret = -1; + goto done; + } + } + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } + + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + + S_DS_GEN + cmdappendsize); + +done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + +int lbs_ret_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *resp) +{ + int ret = 0; + union iwreq_data wrqu; + struct ieeetypes_assocrsp *passocrsp; + struct bss_descriptor *bss; + u16 status_code; + + lbs_deb_enter(LBS_DEB_ASSOC); + + if (!priv->in_progress_assoc_req) { + lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + passocrsp = (struct ieeetypes_assocrsp *) &resp->params; + + /* + * Older FW versions map the IEEE 802.11 Status Code in the association + * response to the following values returned in passocrsp->statuscode: + * + * IEEE Status Code Marvell Status Code + * 0 -> 0x0000 ASSOC_RESULT_SUCCESS + * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * others -> 0x0003 ASSOC_RESULT_REFUSED + * + * Other response codes: + * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) + * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for + * association response from the AP) + */ + + status_code = le16_to_cpu(passocrsp->statuscode); + switch (status_code) { + case 0x00: + break; + case 0x01: + lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); + break; + case 0x02: + lbs_deb_assoc("ASSOC_RESP: internal timer " + "expired while waiting for the AP\n"); + break; + case 0x03: + lbs_deb_assoc("ASSOC_RESP: association " + "refused by AP\n"); + break; + case 0x04: + lbs_deb_assoc("ASSOC_RESP: authentication " + "refused by AP\n"); + break; + default: + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " + " unknown\n", status_code); + break; + } + + if (status_code) { + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, + le16_to_cpu(resp->size) - S_DS_GEN); + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + /* Update current SSID and BSSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; + priv->NF[TYPE_RXPD][TYPE_AVG] = 0; + + memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); + memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); + priv->nextSNRNF = 0; + priv->numSNRNF = 0; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + +int lbs_ret_80211_disassociate(struct lbs_private *priv) +{ + lbs_deb_enter(LBS_DEB_JOIN); + + lbs_mac_event_disconnected(priv); + + lbs_deb_leave(LBS_DEB_JOIN); + return 0; +} + +int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *resp) +{ + int ret = 0; + u16 command = le16_to_cpu(resp->command); + u16 result = le16_to_cpu(resp->result); + struct cmd_ds_802_11_ad_hoc_result *padhocresult; + union iwreq_data wrqu; + struct bss_descriptor *bss; + DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + + padhocresult = &resp->params.result; + + lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size)); + lbs_deb_join("ADHOC_RESP: command = %x\n", command); + lbs_deb_join("ADHOC_RESP: result = %x\n", result); + + if (!priv->in_progress_assoc_req) { + lbs_deb_join("ADHOC_RESP: no in-progress association " + "request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Join result code 0 --> SUCCESS + */ + if (result) { + lbs_deb_join("ADHOC_RESP: failed\n"); + if (priv->connect_status == LBS_CONNECTED) + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + /* + * Now the join cmd should be successful + * If BSSID has changed use SSID to compare instead of BSSID + */ + lbs_deb_join("ADHOC_RESP: associated to '%s'\n", + escape_essid(bss->ssid, bss->ssid_len)); + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { + /* Update the created network descriptor with the new BSSID */ + memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); + } + + /* Set the BSSID from the joined/started descriptor */ + memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + /* Set the new SSID to current SSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); + lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); + lbs_deb_join("ADHOC_RESP: BSSID = %s\n", + print_mac(mac, padhocresult->bssid)); + +done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + +int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv) +{ + lbs_deb_enter(LBS_DEB_JOIN); + + lbs_mac_event_disconnected(priv); + + lbs_deb_leave(LBS_DEB_JOIN); + return 0; +} diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 08372bbf376..c516fbe518f 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -7,6 +7,33 @@ void lbs_association_worker(struct work_struct *work); struct assoc_request *lbs_get_association_request(struct lbs_private *priv); -void lbs_sync_channel(struct work_struct *work); + +struct cmd_ds_command; +int lbs_cmd_80211_authenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd); +int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd); +int lbs_cmd_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); + +int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *resp); +int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); +int lbs_ret_80211_disassociate(struct lbs_private *priv); +int lbs_ret_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *resp); + +int lbs_stop_adhoc_network(struct lbs_private *priv); + +int lbs_send_deauthentication(struct lbs_private *priv); #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b3c1acbcc65..4a82f5114ca 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -9,14 +9,51 @@ #include "decl.h" #include "defs.h" #include "dev.h" -#include "join.h" +#include "assoc.h" #include "wext.h" #include "cmd.h" static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); -static void lbs_set_cmd_ctrl_node(struct lbs_private *priv, - struct cmd_ctrl_node *ptempnode, - void *pdata_buf); + + +/** + * @brief Simple callback that copies response back into command + * + * @param priv A pointer to struct lbs_private structure + * @param extra A pointer to the original command structure for which + * 'resp' is a response + * @param resp A pointer to the command response + * + * @return 0 on success, error on failure + */ +int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp) +{ + struct cmd_header *buf = (void *)extra; + uint16_t copy_len; + + copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size)); + memcpy(buf, resp, copy_len); + return 0; +} +EXPORT_SYMBOL_GPL(lbs_cmd_copyback); + +/** + * @brief Simple callback that ignores the result. Use this if + * you just want to send a command to the hardware, but don't + * care for the result. + * + * @param priv ignored + * @param extra ignored + * @param resp ignored + * + * @return 0 for success + */ +static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp) +{ + return 0; +} /** @@ -143,8 +180,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) } EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg); -static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv, - struct cmd_ds_command *cmd, +static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd, u16 cmd_action) { struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode; @@ -338,81 +374,108 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, return ret; } -static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, - struct enc_key * pkey) +static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam, + struct enc_key *key) { lbs_deb_enter(LBS_DEB_CMD); - if (pkey->flags & KEY_INFO_WPA_ENABLED) { - pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); - } - if (pkey->flags & KEY_INFO_WPA_UNICAST) { - pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); - } - if (pkey->flags & KEY_INFO_WPA_MCAST) { - pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); - } + if (key->flags & KEY_INFO_WPA_ENABLED) + keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); + if (key->flags & KEY_INFO_WPA_UNICAST) + keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); + if (key->flags & KEY_INFO_WPA_MCAST) + keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); + + keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + keyparam->keytypeid = cpu_to_le16(key->type); + keyparam->keylen = cpu_to_le16(key->len); + memcpy(keyparam->key, key->key, key->len); - pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); - pkeyparamset->keytypeid = cpu_to_le16(pkey->type); - pkeyparamset->keylen = cpu_to_le16(pkey->len); - memcpy(pkeyparamset->key, pkey->key, pkey->len); - pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) - + sizeof(pkeyparamset->keyinfo) - + sizeof(pkeyparamset->keylen) - + sizeof(pkeyparamset->key)); + /* Length field doesn't include the {type,length} header */ + keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4); lbs_deb_leave(LBS_DEB_CMD); } -static int lbs_cmd_802_11_key_material(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action, - u32 cmd_oid, void *pdata_buf) +int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc) { - struct cmd_ds_802_11_key_material *pkeymaterial = - &cmd->params.keymaterial; - struct assoc_request * assoc_req = pdata_buf; + struct cmd_ds_802_11_key_material cmd; int ret = 0; int index = 0; lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL); - pkeymaterial->action = cpu_to_le16(cmd_action); + cmd.action = cpu_to_le16(cmd_action); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); if (cmd_action == CMD_ACT_GET) { - cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action)); - ret = 0; - goto done; - } + cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2); + } else { + memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); - memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet)); + if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) { + set_one_wpa_key(&cmd.keyParamSet[index], + &assoc->wpa_unicast_key); + index++; + } - if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { - set_one_wpa_key(&pkeymaterial->keyParamSet[index], - &assoc_req->wpa_unicast_key); - index++; - } + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) { + set_one_wpa_key(&cmd.keyParamSet[index], + &assoc->wpa_mcast_key); + index++; + } - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { - set_one_wpa_key(&pkeymaterial->keyParamSet[index], - &assoc_req->wpa_mcast_key); - index++; + /* The common header and as many keys as we included */ + cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd), + keyParamSet[index])); } + ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); + /* Copy the returned key to driver private data */ + if (!ret && cmd_action == CMD_ACT_GET) { + void *buf_ptr = cmd.keyParamSet; + void *resp_end = &(&cmd)[1]; + + while (buf_ptr < resp_end) { + struct MrvlIEtype_keyParamSet *keyparam = buf_ptr; + struct enc_key *key; + uint16_t param_set_len = le16_to_cpu(keyparam->length); + uint16_t key_len = le16_to_cpu(keyparam->keylen); + uint16_t key_flags = le16_to_cpu(keyparam->keyinfo); + uint16_t key_type = le16_to_cpu(keyparam->keytypeid); + void *end; + + end = (void *)keyparam + sizeof(keyparam->type) + + sizeof(keyparam->length) + param_set_len; + + /* Make sure we don't access past the end of the IEs */ + if (end > resp_end) + break; - cmd->size = cpu_to_le16( S_DS_GEN - + sizeof (pkeymaterial->action) - + (index * sizeof(struct MrvlIEtype_keyParamSet))); + if (key_flags & KEY_INFO_WPA_UNICAST) + key = &priv->wpa_unicast_key; + else if (key_flags & KEY_INFO_WPA_MCAST) + key = &priv->wpa_mcast_key; + else + break; - ret = 0; + /* Copy returned key into driver */ + memset(key, 0, sizeof(struct enc_key)); + if (key_len > sizeof(key->key)) + break; + key->type = key_type; + key->flags = key_flags; + key->len = key_len; + memcpy(key->key, keyparam->key, key->len); + + buf_ptr = end + 1; + } + } -done: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } -static int lbs_cmd_802_11_reset(struct lbs_private *priv, - struct cmd_ds_command *cmd, int cmd_action) +static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action) { struct cmd_ds_802_11_reset *reset = &cmd->params.reset; @@ -426,30 +489,6 @@ static int lbs_cmd_802_11_reset(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_get_log(struct lbs_private *priv, - struct cmd_ds_command *cmd) -{ - lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_GET_LOG); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_cmd_802_11_get_stat(struct lbs_private *priv, - struct cmd_ds_command *cmd) -{ - lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_GET_STAT); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, struct cmd_ds_command *cmd, int cmd_action, @@ -570,8 +609,7 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv, - struct cmd_ds_command *cmd, +static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { @@ -614,8 +652,7 @@ static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv, - struct cmd_ds_command *cmd, +static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor; @@ -788,6 +825,22 @@ out: return ret; } +int lbs_update_channel(struct lbs_private *priv) +{ + int ret; + + /* the channel in f/w could be out of sync; get the current channel */ + lbs_deb_enter(LBS_DEB_ASSOC); + + ret = lbs_get_channel(priv); + if (ret > 0) { + priv->curbssparams.channel = ret; + ret = 0; + } + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + /** * @brief Set the radio channel * @@ -842,8 +895,7 @@ static int lbs_cmd_802_11_rssi(struct lbs_private *priv, return 0; } -static int lbs_cmd_reg_access(struct lbs_private *priv, - struct cmd_ds_command *cmdptr, +static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, u8 cmd_action, void *pdata_buf) { struct lbs_offset_value *offval; @@ -917,53 +969,7 @@ static int lbs_cmd_reg_access(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_mac_address(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - - lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + - S_DS_GEN); - cmd->result = 0; - - cmd->params.macadd.action = cpu_to_le16(cmd_action); - - if (cmd_action == CMD_ACT_SET) { - memcpy(cmd->params.macadd.macadd, - priv->current_addr, ETH_ALEN); - lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6); - } - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv, - struct cmd_ds_command *cmd, - int cmd_action, void *pdata_buf) -{ - struct lbs_ioctl_regrdwr *ea = pdata_buf; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) + - S_DS_GEN); - cmd->result = 0; - - cmd->params.rdeeprom.action = cpu_to_le16(ea->action); - cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset); - cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB); - cmd->params.rdeeprom.value = 0; - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_cmd_bt_access(struct lbs_private *priv, - struct cmd_ds_command *cmd, +static int lbs_cmd_bt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { struct cmd_ds_bt_access *bt_access = &cmd->params.bt; @@ -1000,8 +1006,7 @@ static int lbs_cmd_bt_access(struct lbs_private *priv, return 0; } -static int lbs_cmd_fwt_access(struct lbs_private *priv, - struct cmd_ds_command *cmd, +static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; @@ -1153,9 +1158,9 @@ static void lbs_submit_command(struct lbs_private *priv, command == CMD_802_11_AUTHENTICATE) timeo = 10 * HZ; - lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n", - command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies); - lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize); + lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", + command, le16_to_cpu(cmd->seqnum), cmdsize); + lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); @@ -1164,9 +1169,7 @@ static void lbs_submit_command(struct lbs_private *priv, /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ timeo = HZ; - } else - lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", - command, jiffies); + } /* Setup the timer after transmit command */ mod_timer(&priv->command_timer, jiffies + timeo); @@ -1174,24 +1177,6 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_deb_leave(LBS_DEB_HOST); } -static int lbs_cmd_mac_control(struct lbs_private *priv, - struct cmd_ds_command *cmd) -{ - struct cmd_ds_mac_control *mac = &cmd->params.macctrl; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd->command = cpu_to_le16(CMD_MAC_CONTROL); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); - mac->action = cpu_to_le16(priv->currentpacketfilter); - - lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n", - le16_to_cpu(mac->action), le16_to_cpu(cmd->size)); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - /** * This function inserts command node to cmdfreeq * after cleans it. Requires priv->driver_lock held. @@ -1234,7 +1219,7 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, cmd->cmdwaitqwoken = 1; wake_up_interruptible(&cmd->cmdwait_q); - if (!cmd->callback) + if (!cmd->callback || cmd->callback == lbs_cmd_async_callback) __lbs_cleanup_and_insert_cmd(priv, cmd); priv->cur_cmd = NULL; } @@ -1278,18 +1263,20 @@ int lbs_set_radio_control(struct lbs_private *priv) return ret; } -int lbs_set_mac_packet_filter(struct lbs_private *priv) +void lbs_set_mac_control(struct lbs_private *priv) { - int ret = 0; + struct cmd_ds_mac_control cmd; lbs_deb_enter(LBS_DEB_CMD); - /* Send MAC control command to station */ - ret = lbs_prepare_and_send_command(priv, - CMD_MAC_CONTROL, 0, 0, 0, NULL); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(priv->mac_control); + cmd.reserved = 0; - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; + lbs_cmd_async(priv, CMD_MAC_CONTROL, + &cmd.hdr, sizeof(cmd)); + + lbs_deb_leave(LBS_DEB_CMD); } /** @@ -1338,7 +1325,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, goto done; } - lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf); + cmdnode->callback = NULL; + cmdnode->callback_arg = (unsigned long)pdata_buf; cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf; @@ -1353,15 +1341,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, switch (cmd_no) { case CMD_802_11_PS_MODE: - ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); - break; - - case CMD_802_11_SCAN: - ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf); - break; - - case CMD_MAC_CONTROL: - ret = lbs_cmd_mac_control(priv, cmdptr); + ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action); break; case CMD_802_11_ASSOCIATE: @@ -1376,25 +1356,15 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, case CMD_802_11_AD_HOC_START: ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; - case CMD_CODE_DNLD: - break; case CMD_802_11_RESET: - ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action); - break; - - case CMD_802_11_GET_LOG: - ret = lbs_cmd_802_11_get_log(priv, cmdptr); + ret = lbs_cmd_802_11_reset(cmdptr, cmd_action); break; case CMD_802_11_AUTHENTICATE: ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_GET_STAT: - ret = lbs_cmd_802_11_get_stat(priv, cmdptr); - break; - case CMD_802_11_SNMP_MIB: ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); @@ -1403,12 +1373,12 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: - ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); + ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_RF_TX_POWER: - ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr, - cmd_action, pdata_buf); + ret = lbs_cmd_802_11_rf_tx_power(cmdptr, + cmd_action, pdata_buf); break; case CMD_802_11_RATE_ADAPT_RATESET: @@ -1421,7 +1391,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; case CMD_802_11_MONITOR_MODE: - ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr, + ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); break; @@ -1434,26 +1404,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; case CMD_802_11_AD_HOC_STOP: - ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr); - break; - - case CMD_802_11_KEY_MATERIAL: - ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action, - cmd_oid, pdata_buf); - break; - - case CMD_802_11_PAIRWISE_TSC: - break; - case CMD_802_11_GROUP_TSC: - break; - - case CMD_802_11_MAC_ADDRESS: - ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action); - break; - - case CMD_802_11_EEPROM_ACCESS: - ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr, - cmd_action, pdata_buf); + ret = lbs_cmd_80211_ad_hoc_stop(cmdptr); break; case CMD_802_11_SET_AFC: @@ -1509,22 +1460,12 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; } - case CMD_802_11_PWR_CFG: - cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG); - cmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + - S_DS_GEN); - memmove(&cmdptr->params.pwrcfg, pdata_buf, - sizeof(struct cmd_ds_802_11_pwr_cfg)); - - ret = 0; - break; case CMD_BT_ACCESS: - ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); + ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf); break; case CMD_FWT_ACCESS: - ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); + ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf); break; case CMD_GET_TSF: @@ -1697,36 +1638,6 @@ static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv) } /** - * @brief This function cleans command node. - * - * @param ptempnode A pointer to cmdCtrlNode structure - * @return n/a - */ - -/** - * @brief This function initializes the command node. - * - * @param priv A pointer to struct lbs_private structure - * @param ptempnode A pointer to cmd_ctrl_node structure - * @param pdata_buf A pointer to informaion buffer - * @return 0 or -1 - */ -static void lbs_set_cmd_ctrl_node(struct lbs_private *priv, - struct cmd_ctrl_node *ptempnode, - void *pdata_buf) -{ - lbs_deb_enter(LBS_DEB_HOST); - - if (!ptempnode) - return; - - ptempnode->callback = NULL; - ptempnode->callback_arg = (unsigned long)pdata_buf; - - lbs_deb_leave(LBS_DEB_HOST); -} - -/** * @brief This function executes next command in command * pending queue. It will put fimware back to PS mode * if applicable. @@ -1741,9 +1652,9 @@ int lbs_execute_next_command(struct lbs_private *priv) unsigned long flags; int ret = 0; - // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the - // only caller to us is lbs_thread() and we get even when a - // data packet is received + /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the + * only caller to us is lbs_thread() and we get even when a + * data packet is received */ lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&priv->driver_lock, flags); @@ -1907,44 +1818,27 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) lbs_deb_leave(LBS_DEB_WEXT); } -static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size) +static void lbs_send_confirmsleep(struct lbs_private *priv) { unsigned long flags; - int ret = 0; + int ret; lbs_deb_enter(LBS_DEB_HOST); + lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep, + sizeof(confirm_sleep)); - lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n", - size); - - lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size); - - ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); - - spin_lock_irqsave(&priv->driver_lock, flags); - if (priv->intcounter || priv->currenttxskb) - lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n", - priv->intcounter, priv->currenttxskb); - spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep, + sizeof(confirm_sleep)); if (ret) { - lbs_pr_alert( - "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); + lbs_pr_alert("confirm_sleep failed\n"); } else { spin_lock_irqsave(&priv->driver_lock, flags); - if (!priv->intcounter) { + if (!priv->intcounter) priv->psstate = PS_STATE_SLEEP; - } else { - lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n", - priv->intcounter); - } spin_unlock_irqrestore(&priv->driver_lock, flags); - - lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n"); } - - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); - return ret; + lbs_deb_leave(LBS_DEB_HOST); } void lbs_ps_sleep(struct lbs_private *priv, int wait_option) @@ -1992,10 +1886,10 @@ void lbs_ps_wakeup(struct lbs_private *priv, int wait_option) * @param psmode Power Saving mode * @return n/a */ -void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode) +void lbs_ps_confirm_sleep(struct lbs_private *priv) { unsigned long flags =0; - u8 allowed = 1; + int allowed = 1; lbs_deb_enter(LBS_DEB_HOST); @@ -2017,8 +1911,7 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode) if (allowed) { lbs_deb_host("sending lbs_ps_confirm_sleep\n"); - sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep, - sizeof(struct PS_CMD_ConfirmSleep)); + lbs_send_confirmsleep(priv); } else { lbs_deb_host("sleep confirm has been delayed\n"); } @@ -2027,39 +1920,10 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode) } -/** - * @brief Simple callback that copies response back into command - * - * @param priv A pointer to struct lbs_private structure - * @param extra A pointer to the original command structure for which - * 'resp' is a response - * @param resp A pointer to the command response - * - * @return 0 on success, error on failure - */ -int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, - struct cmd_header *resp) -{ - struct cmd_header *buf = (void *)extra; - uint16_t copy_len; - - lbs_deb_enter(LBS_DEB_CMD); - - copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size)); - lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, " - "copy back buffer was %u bytes\n", copy_len, - le16_to_cpu(resp->size), le16_to_cpu(buf->size)); - memcpy(buf, resp, copy_len); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} -EXPORT_SYMBOL_GPL(lbs_cmd_copyback); - -struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, - struct cmd_header *in_cmd, int in_cmd_size, - int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), - unsigned long callback_arg) +static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, + uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), + unsigned long callback_arg) { struct cmd_ctrl_node *cmdnode; @@ -2096,9 +1960,6 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command lbs_deb_host("PREP_CMD: command 0x%04x\n", command); - /* here was the big old switch() statement, which is now obsolete, - * because the caller of lbs_cmd() sets up all of *cmd for us. */ - cmdnode->cmdwaitqwoken = 0; lbs_queue_cmd(priv, cmdnode); wake_up_interruptible(&priv->waitq); @@ -2108,6 +1969,15 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command return cmdnode; } +void lbs_cmd_async(struct lbs_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size) +{ + lbs_deb_enter(LBS_DEB_CMD); + __lbs_cmd_async(priv, command, in_cmd, in_cmd_size, + lbs_cmd_async_callback, 0); + lbs_deb_leave(LBS_DEB_CMD); +} + int __lbs_cmd(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index b9ab85cc791..3dfc2d43c22 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -18,12 +18,9 @@ #define lbs_cmd_with_response(priv, cmdnr, cmd) \ lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd)) -/* __lbs_cmd() will free the cmdnode and return success/failure. - __lbs_cmd_async() requires that the callback free the cmdnode */ -struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, - struct cmd_header *in_cmd, int in_cmd_size, - int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), - unsigned long callback_arg); +void lbs_cmd_async(struct lbs_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size); + int __lbs_cmd(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), @@ -57,5 +54,7 @@ int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, uint16_t *enable); +int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc); #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index f0ef7081bde..245d3c3a927 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -12,7 +12,7 @@ #include "decl.h" #include "defs.h" #include "dev.h" -#include "join.h" +#include "assoc.h" #include "wext.h" /** @@ -74,7 +74,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv) lbs_deb_cmd("disconnected, so exit PS mode\n"); lbs_ps_wakeup(priv, 0); } - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_ASSOC); } /** @@ -146,22 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv, return ret; } -static int lbs_ret_802_11_stat(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - lbs_deb_enter(LBS_DEB_CMD); -/* currently priv->wlan802_11Stat is unused - - struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; - - // TODO Convert it to Big endian befor copy - memcpy(&priv->wlan802_11Stat, - p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); -*/ - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -204,74 +188,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_key_material(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_key_material *pkeymaterial = - &resp->params.keymaterial; - u16 action = le16_to_cpu(pkeymaterial->action); - - lbs_deb_enter(LBS_DEB_CMD); - - /* Copy the returned key to driver private data */ - if (action == CMD_ACT_GET) { - u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; - u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); - - while (buf_ptr < resp_end) { - struct MrvlIEtype_keyParamSet * pkeyparamset = - (struct MrvlIEtype_keyParamSet *) buf_ptr; - struct enc_key * pkey; - u16 param_set_len = le16_to_cpu(pkeyparamset->length); - u16 key_len = le16_to_cpu(pkeyparamset->keylen); - u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo); - u16 key_type = le16_to_cpu(pkeyparamset->keytypeid); - u8 * end; - - end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) - + sizeof (pkeyparamset->length) - + param_set_len; - /* Make sure we don't access past the end of the IEs */ - if (end > resp_end) - break; - - if (key_flags & KEY_INFO_WPA_UNICAST) - pkey = &priv->wpa_unicast_key; - else if (key_flags & KEY_INFO_WPA_MCAST) - pkey = &priv->wpa_mcast_key; - else - break; - - /* Copy returned key into driver */ - memset(pkey, 0, sizeof(struct enc_key)); - if (key_len > sizeof(pkey->key)) - break; - pkey->type = key_type; - pkey->flags = key_flags; - pkey->len = key_len; - memcpy(pkey->key, pkeyparamset->key, pkey->len); - - buf_ptr = end + 1; - } - } - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - -static int lbs_ret_802_11_mac_address(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; - - lbs_deb_enter(LBS_DEB_CMD); - - memcpy(priv->current_addr, macadd->macadd, ETH_ALEN); - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -333,45 +249,6 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct lbs_ioctl_regrdwr *pbuf; - pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom; - - lbs_deb_enter_args(LBS_DEB_CMD, "len %d", - le16_to_cpu(resp->params.rdeeprom.bytecount)); - if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { - pbuf->NOB = 0; - lbs_deb_cmd("EEPROM read length too big\n"); - return -1; - } - pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); - if (pbuf->NOB > 0) { - - memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, - le16_to_cpu(resp->params.rdeeprom.bytecount)); - lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value, - le16_to_cpu(resp->params.rdeeprom.bytecount)); - } - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_ret_get_log(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog; - - lbs_deb_enter(LBS_DEB_CMD); - - /* Stored little-endian */ - memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log)); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv, struct cmd_ds_command *resp) { @@ -390,7 +267,6 @@ static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv, } static inline int handle_cmd_response(struct lbs_private *priv, - unsigned long dummy, struct cmd_header *cmd_response) { struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response; @@ -407,14 +283,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_reg_access(priv, respcmd, resp); break; - case CMD_RET(CMD_802_11_SCAN): - ret = lbs_ret_80211_scan(priv, resp); - break; - - case CMD_RET(CMD_802_11_GET_LOG): - ret = lbs_ret_get_log(priv, resp); - break; - case CMD_RET_802_11_ASSOCIATE: case CMD_RET(CMD_802_11_ASSOCIATE): case CMD_RET(CMD_802_11_REASSOCIATE): @@ -423,7 +291,7 @@ static inline int handle_cmd_response(struct lbs_private *priv, case CMD_RET(CMD_802_11_DISASSOCIATE): case CMD_RET(CMD_802_11_DEAUTHENTICATE): - ret = lbs_ret_80211_disassociate(priv, resp); + ret = lbs_ret_80211_disassociate(priv); break; case CMD_RET(CMD_802_11_AD_HOC_START): @@ -431,10 +299,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_ad_hoc_start(priv, resp); break; - case CMD_RET(CMD_802_11_GET_STAT): - ret = lbs_ret_802_11_stat(priv, resp); - break; - case CMD_RET(CMD_802_11_SNMP_MIB): ret = lbs_ret_802_11_snmp_mib(priv, resp); break; @@ -453,7 +317,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; case CMD_RET(CMD_MAC_MULTICAST_ADR): - case CMD_RET(CMD_MAC_CONTROL): case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): @@ -467,24 +330,12 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_rssi(priv, resp); break; - case CMD_RET(CMD_802_11_MAC_ADDRESS): - ret = lbs_ret_802_11_mac_address(priv, resp); - break; - case CMD_RET(CMD_802_11_AD_HOC_STOP): - ret = lbs_ret_80211_ad_hoc_stop(priv, resp); - break; - - case CMD_RET(CMD_802_11_KEY_MATERIAL): - ret = lbs_ret_802_11_key_material(priv, resp); - break; - - case CMD_RET(CMD_802_11_EEPROM_ACCESS): - ret = lbs_ret_802_11_eeprom_access(priv, resp); + ret = lbs_ret_80211_ad_hoc_stop(priv); break; case CMD_RET(CMD_802_11D_DOMAIN_INFO): - ret = lbs_ret_802_11d_domain_info(priv, resp); + ret = lbs_ret_802_11d_domain_info(resp); break; case CMD_RET(CMD_802_11_TPC_CFG): @@ -500,14 +351,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, spin_unlock_irqrestore(&priv->driver_lock, flags); break; - case CMD_RET(CMD_802_11_PWR_CFG): - spin_lock_irqsave(&priv->driver_lock, flags); - memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg, - sizeof(struct cmd_ds_802_11_pwr_cfg)); - spin_unlock_irqrestore(&priv->driver_lock, flags); - - break; - case CMD_RET(CMD_GET_TSF): spin_lock_irqsave(&priv->driver_lock, flags); memcpy((void *)priv->cur_cmd->callback_arg, @@ -566,9 +409,9 @@ int lbs_process_rx_command(struct lbs_private *priv) respcmd = le16_to_cpu(resp->command); result = le16_to_cpu(resp->result); - lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n", - respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies); - lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); + lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n", + respcmd, le16_to_cpu(resp->seqnum), priv->upld_len); + lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, priv->upld_len); if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", @@ -687,7 +530,7 @@ int lbs_process_rx_command(struct lbs_private *priv) ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, resp); } else - ret = handle_cmd_response(priv, 0, resp); + ret = handle_cmd_response(priv, resp); spin_lock_irqsave(&priv->driver_lock, flags); @@ -705,21 +548,20 @@ done: static int lbs_send_confirmwake(struct lbs_private *priv) { - struct cmd_header *cmd = &priv->lbs_ps_confirm_wake; + struct cmd_header cmd; int ret = 0; lbs_deb_enter(LBS_DEB_HOST); - cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM); - cmd->size = cpu_to_le16(sizeof(*cmd)); - cmd->seqnum = cpu_to_le16(++priv->seqnum); - cmd->result = 0; + cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM); + cmd.size = cpu_to_le16(sizeof(cmd)); + cmd.seqnum = cpu_to_le16(++priv->seqnum); + cmd.result = 0; - lbs_deb_host("SEND_WAKEC_CMD: before download\n"); + lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd, + sizeof(cmd)); - lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd)); - - ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd)); + ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd)); if (ret) lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n"); @@ -738,11 +580,9 @@ int lbs_process_event(struct lbs_private *priv) eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT; spin_unlock_irq(&priv->driver_lock); - lbs_deb_cmd("event cause %d\n", eventcause); - switch (eventcause) { case MACREG_INT_CODE_LINK_SENSED: - lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n"); + lbs_deb_cmd("EVENT: link sensed\n"); break; case MACREG_INT_CODE_DEAUTHENTICATED: @@ -761,7 +601,7 @@ int lbs_process_event(struct lbs_private *priv) break; case MACREG_INT_CODE_PS_SLEEP: - lbs_deb_cmd("EVENT: sleep\n"); + lbs_deb_cmd("EVENT: ps sleep\n"); /* handle unexpected PS SLEEP event */ if (priv->psstate == PS_STATE_FULL_POWER) { @@ -771,17 +611,17 @@ int lbs_process_event(struct lbs_private *priv) } priv->psstate = PS_STATE_PRE_SLEEP; - lbs_ps_confirm_sleep(priv, (u16) priv->psmode); + lbs_ps_confirm_sleep(priv); break; case MACREG_INT_CODE_HOST_AWAKE: - lbs_deb_cmd("EVENT: HOST_AWAKE\n"); + lbs_deb_cmd("EVENT: host awake\n"); lbs_send_confirmwake(priv); break; case MACREG_INT_CODE_PS_AWAKE: - lbs_deb_cmd("EVENT: awake\n"); + lbs_deb_cmd("EVENT: ps awake\n"); /* handle unexpected PS AWAKE event */ if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( @@ -812,14 +652,16 @@ int lbs_process_event(struct lbs_private *priv) lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); break; + case MACREG_INT_CODE_MIB_CHANGED: + lbs_deb_cmd("EVENT: MIB CHANGED\n"); + break; case MACREG_INT_CODE_INIT_DONE: + lbs_deb_cmd("EVENT: INIT DONE\n"); break; - case MACREG_INT_CODE_ADHOC_BCN_LOST: lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; - case MACREG_INT_CODE_RSSI_LOW: lbs_pr_alert("EVENT: rssi low\n"); break; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index fd67b770dd7..7072e26b42d 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -19,7 +19,7 @@ static char *szStates[] = { }; #ifdef PROC_DEBUG -static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev); +static void lbs_debug_init(struct lbs_private *priv); #endif static int open_file_generic(struct inode *inode, struct file *file) @@ -78,7 +78,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %04ld | %s |", + "%02u| %03d | %04d | %s |", numscansdone, iter_bss->channel, iter_bss->rssi, print_mac(mac, iter_bss->bssid)); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); @@ -164,173 +164,6 @@ out_unlock: return ret; } -static ssize_t lbs_extscan(struct file *file, const char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct lbs_private *priv = file->private_data; - ssize_t res, buf_size; - union iwreq_data wrqu; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - - lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0); - - memset(&wrqu, 0, sizeof(union iwreq_data)); - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - -out_unlock: - free_page(addr); - return count; -} - -static void lbs_parse_bssid(char *buf, size_t count, - struct lbs_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - unsigned int mac[ETH_ALEN]; - - hold = strstr(buf, "bssid="); - if (!hold) - return; - hold += 6; - sscanf(hold, "%02x:%02x:%02x:%02x:%02x:%02x", - mac, mac+1, mac+2, mac+3, mac+4, mac+5); - memcpy(scan_cfg->bssid, mac, ETH_ALEN); -} - -static void lbs_parse_ssid(char *buf, size_t count, - struct lbs_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold, *end; - ssize_t size; - - hold = strstr(buf, "ssid="); - if (!hold) - return; - hold += 5; - end = strchr(hold, ' '); - if (!end) - end = buf + count - 1; - - size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold)); - strncpy(scan_cfg->ssid, hold, size); - - return; -} - -static int lbs_parse_clear(char *buf, size_t count, const char *tag) -{ - char *hold; - int val; - - hold = strstr(buf, tag); - if (!hold) - return 0; - hold += strlen(tag); - sscanf(hold, "%d", &val); - - if (val != 0) - val = 1; - - return val; -} - -static int lbs_parse_dur(char *buf, size_t count, - struct lbs_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "dur="); - if (!hold) - return 0; - hold += 4; - sscanf(hold, "%d", &val); - - return val; -} - -static void lbs_parse_type(char *buf, size_t count, - struct lbs_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "type="); - if (!hold) - return; - hold += 5; - sscanf(hold, "%d", &val); - - /* type=1,2 or 3 */ - if (val < 1 || val > 3) - return; - - scan_cfg->bsstype = val; - - return; -} - -static ssize_t lbs_setuserscan(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct lbs_private *priv = file->private_data; - ssize_t res, buf_size; - struct lbs_ioctl_user_scan_cfg *scan_cfg; - union iwreq_data wrqu; - int dur; - char *buf = (char *)get_zeroed_page(GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_buf; - } - - scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL); - if (!scan_cfg) { - res = -ENOMEM; - goto out_buf; - } - res = count; - - scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY; - - dur = lbs_parse_dur(buf, count, scan_cfg); - lbs_parse_bssid(buf, count, scan_cfg); - scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid="); - lbs_parse_ssid(buf, count, scan_cfg); - scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid="); - lbs_parse_type(buf, count, scan_cfg); - - lbs_scan_networks(priv, scan_cfg, 1); - wait_event_interruptible(priv->cmd_pending, - priv->surpriseremoved || !priv->last_scanned_channel); - - if (priv->surpriseremoved) - goto out_scan_cfg; - - memset(&wrqu, 0x00, sizeof(union iwreq_data)); - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); - - out_scan_cfg: - kfree(scan_cfg); - out_buf: - free_page((unsigned long)buf); - return res; -} - - /* * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the @@ -857,8 +690,6 @@ static struct lbs_debugfs_files debugfs_files[] = { write_file_dummy), }, { "sleepparams", 0644, FOPS(lbs_sleepparams_read, lbs_sleepparams_write), }, - { "extscan", 0600, FOPS(NULL, lbs_extscan), }, - { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), }, }; static struct lbs_debugfs_files debugfs_events_files[] = { @@ -947,7 +778,7 @@ void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev) } #ifdef PROC_DEBUG - lbs_debug_init(priv, dev); + lbs_debug_init(priv); #endif exit: return; @@ -1121,7 +952,7 @@ static struct file_operations lbs_debug_fops = { * @param dev pointer net_device * @return N/A */ -static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev) +static void lbs_debug_init(struct lbs_private *priv) { int i; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 4e22341b4f3..4aea421f07c 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -17,7 +17,7 @@ struct net_device; struct cmd_ctrl_node; struct cmd_ds_command; -int lbs_set_mac_packet_filter(struct lbs_private *priv); +void lbs_set_mac_control(struct lbs_private *priv); void lbs_send_tx_feedback(struct lbs_private *priv); @@ -35,9 +35,6 @@ void lbs_interrupt(struct lbs_private *priv); int lbs_set_radio_control(struct lbs_private *priv); u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); -void lbs_get_fwversion(struct lbs_private *priv, - char *fwversion, - int maxlen); /** The proc fs interface */ int lbs_process_rx_command(struct lbs_private *priv); @@ -49,7 +46,7 @@ int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); void lbs_ps_sleep(struct lbs_private *priv, int wait_option); -void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode); +void lbs_ps_confirm_sleep(struct lbs_private *priv); void lbs_ps_wakeup(struct lbs_private *priv, int wait_option); struct chan_freq_power *lbs_find_cfp_by_band_and_channel( @@ -63,7 +60,6 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); /* main.c */ struct chan_freq_power *lbs_get_region_cfp_table(u8 region, - u8 band, int *cfp_no); struct lbs_private *lbs_add_card(void *card, struct device *dmdev); int lbs_remove_card(struct lbs_private *priv); @@ -72,4 +68,9 @@ int lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); int lbs_update_channel(struct lbs_private *priv); + +#ifndef CONFIG_IEEE80211 +const char *escape_essid(const char *essid, u8 essid_len); +#endif + #endif diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 3053cc2160b..84e8de5e21d 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -53,14 +53,14 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #endif #define lbs_deb_enter(grp) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__); #define lbs_deb_enter_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args); #define lbs_deb_leave(grp) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__); #define lbs_deb_leave_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \ - __FUNCTION__, __LINE__, ##args); + LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \ + __func__, ##args); #define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args) #define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args) #define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 5a69f2b6086..1e6bae80396 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -10,9 +10,10 @@ #include <linux/wireless.h> #include <linux/ethtool.h> #include <linux/debugfs.h> +#include <net/ieee80211.h> #include "defs.h" -#include "scan.h" +#include "hostcmd.h" extern struct ethtool_ops lbs_ethtool_ops; @@ -143,9 +144,14 @@ struct lbs_private { wait_queue_head_t waitq; struct workqueue_struct *work_thread; + /** Scanning */ struct delayed_work scan_work; struct delayed_work assoc_work; struct work_struct sync_channel; + /* remember which channel was scanned last, != 0 if currently scanning */ + int scan_channel; + u8 scan_ssid[IW_ESSID_MAX_SIZE + 1]; + u8 scan_ssid_len; /** Hardware access */ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); @@ -247,7 +253,7 @@ struct lbs_private { struct sk_buff *currenttxskb; /** NIC Operation characteristics */ - u16 currentpacketfilter; + u16 mac_control; u32 connect_status; u32 mesh_connect_status; u16 regioncode; @@ -262,9 +268,6 @@ struct lbs_private { char ps_supported; u8 needtowakeup; - struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep; - struct cmd_header lbs_ps_confirm_wake; - struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; @@ -315,16 +318,52 @@ struct lbs_private { u32 enable11d; /** MISCELLANEOUS */ - u8 *prdeeprom; struct lbs_offset_value offsetvalue; - struct cmd_ds_802_11_get_log logmsg; - u32 monitormode; - int last_scanned_channel; u8 fw_ready; }; +extern struct cmd_confirm_sleep confirm_sleep; + +/** + * @brief Structure used to store information for each beacon/probe response + */ +struct bss_descriptor { + u8 bssid[ETH_ALEN]; + + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + u16 capability; + u32 rssi; + u32 channel; + u16 beaconperiod; + u32 atimwindow; + + /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ + u8 mode; + + /* zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; + + unsigned long last_scanned; + + union ieeetypes_phyparamset phyparamset; + union IEEEtypes_ssparamset ssparamset; + + struct ieeetypes_countryinfofullset countryinfo; + + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + + u8 mesh; + + struct list_head list; +}; + /** Association request * * Encapsulates all the options that describe a specific assocation request diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 21e6f988ea8..dcfdb404678 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -6,7 +6,6 @@ #include "decl.h" #include "defs.h" #include "dev.h" -#include "join.h" #include "wext.h" #include "cmd.h" @@ -25,13 +24,14 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct lbs_private *priv = (struct lbs_private *) dev->priv; - char fwver[32]; - - lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1); + snprintf(info->fw_version, 32, "%u.%u.%u.p%u", + priv->fwrelease >> 24 & 0xff, + priv->fwrelease >> 16 & 0xff, + priv->fwrelease >> 8 & 0xff, + priv->fwrelease & 0xff); strcpy(info->driver, "libertas"); strcpy(info->version, lbs_driver_version); - strcpy(info->fw_version, fwver); } /* All 8388 parts have 16KiB EEPROM size at the time of writing. @@ -48,61 +48,28 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { struct lbs_private *priv = (struct lbs_private *) dev->priv; - struct lbs_ioctl_regrdwr regctrl; - char *ptr; + struct cmd_ds_802_11_eeprom_access cmd; int ret; - regctrl.action = 0; - regctrl.offset = eeprom->offset; - regctrl.NOB = eeprom->len; - - if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN) - return -EINVAL; - -// mutex_lock(&priv->mutex); - - priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); - if (!priv->prdeeprom) - return -ENOMEM; - memcpy(priv->prdeeprom, ®ctrl, sizeof(regctrl)); - - /* +14 is for action, offset, and NOB in - * response */ - lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n", - regctrl.action, regctrl.offset, regctrl.NOB); + lbs_deb_enter(LBS_DEB_ETHTOOL); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_EEPROM_ACCESS, - regctrl.action, - CMD_OPTION_WAITFORRSP, 0, - ®ctrl); - - if (ret) { - if (priv->prdeeprom) - kfree(priv->prdeeprom); - goto done; + if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN || + eeprom->len > LBS_EEPROM_READ_LEN) { + ret = -EINVAL; + goto out; } - mdelay(10); - - ptr = (char *)priv->prdeeprom; - - /* skip the command header, but include the "value" u32 variable */ - ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4; - - /* - * Return the result back to the user - */ - memcpy(bytes, ptr, eeprom->len); - - if (priv->prdeeprom) - kfree(priv->prdeeprom); -// mutex_unlock(&priv->mutex); - - ret = 0; - -done: - lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret); + cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) - + LBS_EEPROM_READ_LEN + eeprom->len); + cmd.action = cpu_to_le16(CMD_ACT_GET); + cmd.offset = cpu_to_le16(eeprom->offset); + cmd.len = cpu_to_le16(eeprom->len); + ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd); + if (!ret) + memcpy(bytes, cmd.value, eeprom->len); + +out: + lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 1aa04076b1a..3915c3144fa 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -33,7 +33,6 @@ #define CMD_RET_802_11_ASSOCIATE 0x8012 /* Command codes */ -#define CMD_CODE_DNLD 0x0002 #define CMD_GET_HW_SPEC 0x0003 #define CMD_EEPROM_UPDATE 0x0004 #define CMD_802_11_RESET 0x0005 @@ -68,8 +67,6 @@ #define CMD_802_11_AD_HOC_JOIN 0x002c #define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e #define CMD_802_11_ENABLE_RSN 0x002f -#define CMD_802_11_PAIRWISE_TSC 0x0036 -#define CMD_802_11_GROUP_TSC 0x0037 #define CMD_802_11_SET_AFC 0x003c #define CMD_802_11_GET_AFC 0x003d #define CMD_802_11_AD_HOC_STOP 0x0040 @@ -87,7 +84,6 @@ #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 #define CMD_802_11_SLEEP_PERIOD 0x0068 #define CMD_802_11_TPC_CFG 0x0072 -#define CMD_802_11_PWR_CFG 0x0073 #define CMD_802_11_FW_WAKE_METHOD 0x0074 #define CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define CMD_802_11_RATE_ADAPT_RATESET 0x0076 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d35b015b665..f29bc5bbda3 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -174,9 +174,11 @@ struct cmd_ds_802_11_subscribe_event { * Define data structure for CMD_802_11_SCAN */ struct cmd_ds_802_11_scan { - u8 bsstype; - u8 bssid[ETH_ALEN]; - u8 tlvbuffer[1]; + struct cmd_header hdr; + + uint8_t bsstype; + uint8_t bssid[ETH_ALEN]; + uint8_t tlvbuffer[0]; #if 0 mrvlietypes_ssidparamset_t ssidParamSet; mrvlietypes_chanlistparamset_t ChanListParamSet; @@ -185,12 +187,16 @@ struct cmd_ds_802_11_scan { }; struct cmd_ds_802_11_scan_rsp { + struct cmd_header hdr; + __le16 bssdescriptsize; - u8 nr_sets; - u8 bssdesc_and_tlvbuffer[1]; + uint8_t nr_sets; + uint8_t bssdesc_and_tlvbuffer[0]; }; struct cmd_ds_802_11_get_log { + struct cmd_header hdr; + __le32 mcasttxframe; __le32 failed; __le32 retry; @@ -207,8 +213,9 @@ struct cmd_ds_802_11_get_log { }; struct cmd_ds_mac_control { + struct cmd_header hdr; __le16 action; - __le16 reserved; + u16 reserved; }; struct cmd_ds_mac_multicast_adr { @@ -420,6 +427,8 @@ struct cmd_ds_802_11_rssi_rsp { }; struct cmd_ds_802_11_mac_address { + struct cmd_header hdr; + __le16 action; u8 macadd[ETH_ALEN]; }; @@ -471,14 +480,11 @@ struct cmd_ds_802_11_ps_mode { __le16 locallisteninterval; }; -struct PS_CMD_ConfirmSleep { - __le16 command; - __le16 size; - __le16 seqnum; - __le16 result; +struct cmd_confirm_sleep { + struct cmd_header hdr; __le16 action; - __le16 reserved1; + __le16 nullpktinterval; __le16 multipledtim; __le16 reserved; __le16 locallisteninterval; @@ -572,17 +578,20 @@ struct cmd_ds_host_sleep { } __attribute__ ((packed)); struct cmd_ds_802_11_key_material { + struct cmd_header hdr; + __le16 action; struct MrvlIEtype_keyParamSet keyParamSet[2]; } __attribute__ ((packed)); struct cmd_ds_802_11_eeprom_access { + struct cmd_header hdr; __le16 action; - - /* multiple 4 */ __le16 offset; - __le16 bytecount; - u8 value; + __le16 len; + /* firmware says it returns a maximum of 20 bytes */ +#define LBS_EEPROM_READ_LEN 20 + u8 value[LBS_EEPROM_READ_LEN]; } __attribute__ ((packed)); struct cmd_ds_802_11_tpc_cfg { @@ -600,14 +609,6 @@ struct cmd_ds_802_11_led_ctrl { u8 data[256]; } __attribute__ ((packed)); -struct cmd_ds_802_11_pwr_cfg { - __le16 action; - u8 enable; - s8 PA_P0; - s8 PA_P1; - s8 PA_P2; -} __attribute__ ((packed)); - struct cmd_ds_802_11_afc { __le16 afc_auto; union { @@ -689,15 +690,11 @@ struct cmd_ds_command { /* command Body */ union { struct cmd_ds_802_11_ps_mode psmode; - struct cmd_ds_802_11_scan scan; - struct cmd_ds_802_11_scan_rsp scanresp; - struct cmd_ds_mac_control macctrl; struct cmd_ds_802_11_associate associate; struct cmd_ds_802_11_deauthenticate deauth; struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; struct cmd_ds_802_11_ad_hoc_result result; - struct cmd_ds_802_11_get_log glog; struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; @@ -711,18 +708,14 @@ struct cmd_ds_command { struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; struct cmd_ds_802_11_disassociate dassociate; - struct cmd_ds_802_11_mac_address macadd; - struct cmd_ds_802_11_key_material keymaterial; struct cmd_ds_mac_reg_access macreg; struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_rf_reg_access rfreg; - struct cmd_ds_802_11_eeprom_access rdeeprom; struct cmd_ds_802_11d_domain_info domaininfo; struct cmd_ds_802_11d_domain_info domaininforesp; struct cmd_ds_802_11_tpc_cfg tpccfg; - struct cmd_ds_802_11_pwr_cfg pwrcfg; struct cmd_ds_802_11_afc afc; struct cmd_ds_802_11_led_ctrl ledgpio; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 038c66a98f1..53afebac714 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -880,6 +880,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } + /* The firmware for the CF card supports powersave */ + priv->ps_supported = 1; + ret = 0; goto out; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c deleted file mode 100644 index 2d4508048b6..00000000000 --- a/drivers/net/wireless/libertas/join.c +++ /dev/null @@ -1,895 +0,0 @@ -/** - * Functions implementing wlan infrastructure and adhoc join routines, - * IOCTL handlers as well as command preperation and response routines - * for sending adhoc start, adhoc join, and association commands - * to the firmware. - */ -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/wireless.h> -#include <linux/etherdevice.h> - -#include <net/iw_handler.h> - -#include "host.h" -#include "decl.h" -#include "join.h" -#include "dev.h" -#include "assoc.h" - -/* The firmware needs certain bits masked out of the beacon-derviced capability - * field when associating/joining to BSSs. - */ -#define CAPINFO_MASK (~(0xda00)) - -/** - * @brief This function finds common rates between rate1 and card rates. - * - * It will fill common rates in rate1 as output if found. - * - * NOTE: Setting the MSB of the basic rates need to be taken - * care, either before or after calling this function - * - * @param priv A pointer to struct lbs_private structure - * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer; new size of buffer on return - * - * @return 0 or -1 - */ -static int get_common_rates(struct lbs_private *priv, - u8 *rates, - u16 *rates_size) -{ - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; - u8 tmp[30]; - size_t tmp_size = 0; - - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; - } - } - - lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); - lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - - if (!priv->auto_rate) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - goto done; - } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; - } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - return ret; -} - - -/** - * @brief Sets the MSB on basic rates as the firmware requires - * - * Scan through an array and set the MSB for basic data rates. - * - * @param rates buffer of data rates - * @param len size of buffer - */ -static void lbs_set_basic_rate_flags(u8 *rates, size_t len) -{ - int i; - - for (i = 0; i < len; i++) { - if (rates[i] == 0x02 || rates[i] == 0x04 || - rates[i] == 0x0b || rates[i] == 0x16) - rates[i] |= 0x80; - } -} - -/** - * @brief Unsets the MSB on basic rates - * - * Scan through an array and unset the MSB for basic data rates. - * - * @param rates buffer of data rates - * @param len size of buffer - */ -void lbs_unset_basic_rate_flags(u8 *rates, size_t len) -{ - int i; - - for (i = 0; i < len; i++) - rates[i] &= 0x7f; -} - - -/** - * @brief Associate to a specific BSS discovered in a scan - * - * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to the BSS descriptor to associate with. - * - * @return 0-success, otherwise fail - */ -int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) -{ - int ret; - - lbs_deb_enter(LBS_DEB_ASSOC); - - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, - 0, assoc_req->bss.bssid); - - if (ret) - goto done; - - /* set preamble to firmware */ - if ( (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - else - priv->preamble = CMD_TYPE_LONG_PREAMBLE; - - lbs_set_radio_control(priv); - - ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -/** - * @brief Start an Adhoc Network - * - * @param priv A pointer to struct lbs_private structure - * @param adhocssid The ssid of the Adhoc Network - * @return 0--success, -1--fail - */ -int lbs_start_adhoc_network(struct lbs_private *priv, - struct assoc_request *assoc_req) -{ - int ret = 0; - - priv->adhoccreate = 1; - - if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { - lbs_deb_join("AdhocStart: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - } else { - lbs_deb_join("AdhocStart: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; - } - - lbs_set_radio_control(priv); - - lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); - lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); - - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); - - return ret; -} - -/** - * @brief Join an adhoc network found in a previous scan - * - * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to a BSS descriptor found in a previous scan - * to attempt to join - * - * @return 0--success, -1--fail - */ -int lbs_join_adhoc_network(struct lbs_private *priv, - struct assoc_request *assoc_req) -{ - struct bss_descriptor * bss = &assoc_req->bss; - int ret = 0; - - lbs_deb_join("%s: Current SSID '%s', ssid length %u\n", - __func__, - escape_essid(priv->curbssparams.ssid, - priv->curbssparams.ssid_len), - priv->curbssparams.ssid_len); - lbs_deb_join("%s: requested ssid '%s', ssid length %u\n", - __func__, escape_essid(bss->ssid, bss->ssid_len), - bss->ssid_len); - - /* check if the requested SSID is already joined */ - if ( priv->curbssparams.ssid_len - && !lbs_ssid_cmp(priv->curbssparams.ssid, - priv->curbssparams.ssid_len, - bss->ssid, bss->ssid_len) - && (priv->mode == IW_MODE_ADHOC) - && (priv->connect_status == LBS_CONNECTED)) { - union iwreq_data wrqu; - - lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " - "current, not attempting to re-join"); - - /* Send the re-association event though, because the association - * request really was successful, even if just a null-op. - */ - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, - ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - goto out; - } - - /* Use shortpreamble only when both creator and card supports - short preamble */ - if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - || !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { - lbs_deb_join("AdhocJoin: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; - } else { - lbs_deb_join("AdhocJoin: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - } - - lbs_set_radio_control(priv); - - lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); - lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); - - priv->adhoccreate = 0; - - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_SSID, assoc_req); - -out: - return ret; -} - -int lbs_stop_adhoc_network(struct lbs_private *priv) -{ - return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); -} - -/** - * @brief Send Deauthentication Request - * - * @param priv A pointer to struct lbs_private structure - * @return 0--success, -1--fail - */ -int lbs_send_deauthentication(struct lbs_private *priv) -{ - return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); -} - -/** - * @brief This function prepares command of authenticate. - * - * @param priv A pointer to struct lbs_private structure - * @param cmd A pointer to cmd_ds_command structure - * @param pdata_buf Void cast of pointer to a BSSID to authenticate with - * - * @return 0 or -1 - */ -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf) -{ - struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; - int ret = -1; - u8 *bssid = pdata_buf; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) - + S_DS_GEN); - - /* translate auth mode to 802.11 defined wire value */ - switch (priv->secinfo.auth_mode) { - case IW_AUTH_ALG_OPEN_SYSTEM: - pauthenticate->authtype = 0x00; - break; - case IW_AUTH_ALG_SHARED_KEY: - pauthenticate->authtype = 0x01; - break; - case IW_AUTH_ALG_LEAP: - pauthenticate->authtype = 0x80; - break; - default: - lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", - priv->secinfo.auth_mode); - goto out; - } - - memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bssid), pauthenticate->authtype); - ret = 0; - -out: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd) -{ - struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + - S_DS_GEN); - - /* set AP MAC address */ - memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); - - /* Reason code 3 = Station is leaving */ -#define REASON_CODE_STA_LEAVING 3 - dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} - -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_associate *passo = &cmd->params.associate; - int ret = 0; - struct assoc_request * assoc_req = pdata_buf; - struct bss_descriptor * bss = &assoc_req->bss; - u8 *pos; - u16 tmpcap, tmplen; - struct mrvlietypes_ssidparamset *ssid; - struct mrvlietypes_phyparamset *phy; - struct mrvlietypes_ssparamset *ss; - struct mrvlietypes_ratesparamset *rates; - struct mrvlietypes_rsnparamset *rsn; - - lbs_deb_enter(LBS_DEB_ASSOC); - - pos = (u8 *) passo; - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); - - memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); - pos += sizeof(passo->peerstaaddr); - - /* set the listen interval */ - passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); - - pos += sizeof(passo->capability); - pos += sizeof(passo->listeninterval); - pos += sizeof(passo->bcnperiod); - pos += sizeof(passo->dtimperiod); - - ssid = (struct mrvlietypes_ssidparamset *) pos; - ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); - tmplen = bss->ssid_len; - ssid->header.len = cpu_to_le16(tmplen); - memcpy(ssid->ssid, bss->ssid, tmplen); - pos += sizeof(ssid->header) + tmplen; - - phy = (struct mrvlietypes_phyparamset *) pos; - phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); - tmplen = sizeof(phy->fh_ds.dsparamset); - phy->header.len = cpu_to_le16(tmplen); - memcpy(&phy->fh_ds.dsparamset, - &bss->phyparamset.dsparamset.currentchan, - tmplen); - pos += sizeof(phy->header) + tmplen; - - ss = (struct mrvlietypes_ssparamset *) pos; - ss->header.type = cpu_to_le16(TLV_TYPE_CF); - tmplen = sizeof(ss->cf_ibss.cfparamset); - ss->header.len = cpu_to_le16(tmplen); - pos += sizeof(ss->header) + tmplen; - - rates = (struct mrvlietypes_ratesparamset *) pos; - rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); - tmplen = MAX_RATES; - if (get_common_rates(priv, rates->rates, &tmplen)) { - ret = -1; - goto done; - } - pos += sizeof(rates->header) + tmplen; - rates->header.len = cpu_to_le16(tmplen); - lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); - - /* Copy the infra. association rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(rates->rates, tmplen); - - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - rsn = (struct mrvlietypes_rsnparamset *) pos; - /* WPA_IE or WPA2_IE */ - rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); - tmplen = (u16) assoc_req->wpa_ie[1]; - rsn->header.len = cpu_to_le16(tmplen); - memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); - lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, - sizeof(rsn->header) + tmplen); - pos += sizeof(rsn->header) + tmplen; - } - - /* update curbssparams */ - priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - - /* set the capability info */ - tmpcap = (bss->capability & CAPINFO_MASK); - if (bss->mode == IW_MODE_INFRA) - tmpcap |= WLAN_CAPABILITY_ESS; - passo->capability = cpu_to_le16(tmpcap); - lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; - int ret = 0; - int cmdappendsize = 0; - struct assoc_request * assoc_req = pdata_buf; - u16 tmpcap = 0; - size_t ratesize = 0; - - lbs_deb_enter(LBS_DEB_JOIN); - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); - - /* - * Fill in the parameters for 2 data structures: - * 1. cmd_ds_802_11_ad_hoc_start command - * 2. priv->scantable[i] - * - * Driver will fill up SSID, bsstype,IBSS param, Physical Param, - * probe delay, and cap info. - * - * Firmware will fill up beacon period, DTIM, Basic rates - * and operational rates. - */ - - memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); - - lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), - assoc_req->ssid_len); - - /* set the BSS type */ - adhs->bsstype = CMD_BSS_TYPE_IBSS; - priv->mode = IW_MODE_ADHOC; - if (priv->beacon_period == 0) - priv->beacon_period = MRVDRV_BEACON_INTERVAL; - adhs->beaconperiod = cpu_to_le16(priv->beacon_period); - - /* set Physical param set */ -#define DS_PARA_IE_ID 3 -#define DS_PARA_IE_LEN 1 - - adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; - adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; - - WARN_ON(!assoc_req->channel); - - lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n", - assoc_req->channel); - - adhs->phyparamset.dsparamset.currentchan = assoc_req->channel; - - /* set IBSS param set */ -#define IBSS_PARA_IE_ID 6 -#define IBSS_PARA_IE_LEN 2 - - adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; - adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = 0; - - /* set capability info */ - tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n"); - tmpcap |= WLAN_CAPABILITY_PRIVACY; - } else { - lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n"); - } - adhs->capability = cpu_to_le16(tmpcap); - - /* probedelay */ - adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); - memcpy(adhs->rates, lbs_bg_rates, ratesize); - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(adhs->rates, ratesize); - - lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); - - lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); - - if (lbs_create_dnld_countryinfo_11d(priv)) { - lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + - S_DS_GEN + cmdappendsize); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv, - struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); - cmd->size = cpu_to_le16(S_DS_GEN); - - return 0; -} - -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; - struct assoc_request * assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - int cmdappendsize = 0; - int ret = 0; - u16 ratesize = 0; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - - join_cmd->bss.type = CMD_BSS_TYPE_IBSS; - join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - - memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); - memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - - memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); - - memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); - - join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); - lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - bss->capability, CAPINFO_MASK); - - /* information on BSSID descriptor passed to FW */ - lbs_deb_join( - "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, join_cmd->bss.bssid), - join_cmd->bss.ssid); - - /* failtimeout */ - join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); - - /* probedelay */ - join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - priv->curbssparams.channel = bss->channel; - - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); - ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); - memcpy(join_cmd->bss.rates, bss->rates, ratesize); - if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { - lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); - ret = -1; - goto done; - } - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); - - join_cmd->bss.ssparamset.ibssparamset.atimwindow = - cpu_to_le16(bss->atimwindow); - - if (assoc_req->secinfo.wep_enabled) { - u16 tmp = le16_to_cpu(join_cmd->bss.capability); - tmp |= WLAN_CAPABILITY_PRIVACY; - join_cmd->bss.capability = cpu_to_le16(tmp); - } - - if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { - /* wake up first */ - __le32 Localpsmode; - - Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_PS_MODE, - CMD_ACT_SET, - 0, 0, &Localpsmode); - - if (ret) { - ret = -1; - goto done; - } - } - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + - S_DS_GEN + cmdappendsize); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - int ret = 0; - union iwreq_data wrqu; - struct ieeetypes_assocrsp *passocrsp; - struct bss_descriptor * bss; - u16 status_code; - - lbs_deb_enter(LBS_DEB_ASSOC); - - if (!priv->in_progress_assoc_req) { - lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - passocrsp = (struct ieeetypes_assocrsp *) & resp->params; - - /* - * Older FW versions map the IEEE 802.11 Status Code in the association - * response to the following values returned in passocrsp->statuscode: - * - * IEEE Status Code Marvell Status Code - * 0 -> 0x0000 ASSOC_RESULT_SUCCESS - * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * others -> 0x0003 ASSOC_RESULT_REFUSED - * - * Other response codes: - * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) - * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for - * association response from the AP) - */ - - status_code = le16_to_cpu(passocrsp->statuscode); - switch (status_code) { - case 0x00: - break; - case 0x01: - lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); - break; - case 0x02: - lbs_deb_assoc("ASSOC_RESP: internal timer " - "expired while waiting for the AP\n"); - break; - case 0x03: - lbs_deb_assoc("ASSOC_RESP: association " - "refused by AP\n"); - break; - case 0x04: - lbs_deb_assoc("ASSOC_RESP: authentication " - "refused by AP\n"); - break; - default: - lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " - " unknown\n", status_code); - break; - } - - if (status_code) { - lbs_mac_event_disconnected(priv); - ret = -1; - goto done; - } - - lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, - le16_to_cpu(resp->size) - S_DS_GEN); - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - /* Update current SSID and BSSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n", - priv->currentpacketfilter); - - priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; - priv->NF[TYPE_RXPD][TYPE_AVG] = 0; - - memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); - memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); - priv->nextSNRNF = 0; - priv->numSNRNF = 0; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -int lbs_ret_80211_disassociate(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} - -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - int ret = 0; - u16 command = le16_to_cpu(resp->command); - u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *padhocresult; - union iwreq_data wrqu; - struct bss_descriptor *bss; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - padhocresult = &resp->params.result; - - lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size)); - lbs_deb_join("ADHOC_RESP: command = %x\n", command); - lbs_deb_join("ADHOC_RESP: result = %x\n", result); - - if (!priv->in_progress_assoc_req) { - lbs_deb_join("ADHOC_RESP: no in-progress association request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - /* - * Join result code 0 --> SUCCESS - */ - if (result) { - lbs_deb_join("ADHOC_RESP: failed\n"); - if (priv->connect_status == LBS_CONNECTED) { - lbs_mac_event_disconnected(priv); - } - ret = -1; - goto done; - } - - /* - * Now the join cmd should be successful - * If BSSID has changed use SSID to compare instead of BSSID - */ - lbs_deb_join("ADHOC_RESP: associated to '%s'\n", - escape_essid(bss->ssid, bss->ssid_len)); - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { - /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); - } - - /* Set the BSSID from the joined/started descriptor */ - memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - /* Set the new SSID to current SSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = %s\n", - print_mac(mac, padhocresult->bssid)); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h deleted file mode 100644 index c617d071f78..00000000000 --- a/drivers/net/wireless/libertas/join.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Interface for the wlan infrastructure and adhoc join routines - * - * Driver interface functions and type declarations for the join module - * implemented in join.c. Process all start/join requests for - * both adhoc and infrastructure networks - */ -#ifndef _LBS_JOIN_H -#define _LBS_JOIN_H - -#include "defs.h" -#include "dev.h" - -struct cmd_ds_command; -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv, - struct cmd_ds_command *cmd); -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd); -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp); -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv, - struct cmd_ds_command *resp); -int lbs_ret_80211_disassociate(struct lbs_private *priv, - struct cmd_ds_command *resp); -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp); - -int lbs_start_adhoc_network(struct lbs_private *priv, - struct assoc_request * assoc_req); -int lbs_join_adhoc_network(struct lbs_private *priv, - struct assoc_request * assoc_req); -int lbs_stop_adhoc_network(struct lbs_private *priv); - -int lbs_send_deauthentication(struct lbs_private *priv); - -int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req); - -void lbs_unset_basic_rate_flags(u8 *rates, size_t len); - -#endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 4d4e2f3b66a..8f112261097 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -19,8 +19,8 @@ #include "dev.h" #include "wext.h" #include "debugfs.h" +#include "scan.h" #include "assoc.h" -#include "join.h" #include "cmd.h" #define DRIVER_RELEASE_VERSION "323.p0" @@ -37,6 +37,11 @@ EXPORT_SYMBOL_GPL(lbs_debug); module_param_named(libertas_debug, lbs_debug, int, 0644); +/* This global structure is used to send the confirm_sleep command as + * fast as possible down to the firmware. */ +struct cmd_confirm_sleep confirm_sleep; + + #define LBS_TX_PWR_DEFAULT 20 /*100mW */ #define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ #define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ @@ -277,10 +282,10 @@ static ssize_t lbs_rtap_set(struct device *dev, struct lbs_private *priv = to_net_dev(dev)->priv; sscanf(buf, "%x", &monitor_mode); - if (monitor_mode != LBS_MONITOR_OFF) { - if(priv->monitormode == monitor_mode) + if (monitor_mode) { + if (priv->monitormode == monitor_mode) return strlen(buf); - if (priv->monitormode == LBS_MONITOR_OFF) { + if (!priv->monitormode) { if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) @@ -293,9 +298,9 @@ static ssize_t lbs_rtap_set(struct device *dev, } else { - if (priv->monitormode == LBS_MONITOR_OFF) + if (!priv->monitormode) return strlen(buf); - priv->monitormode = LBS_MONITOR_OFF; + priv->monitormode = 0; lbs_remove_rtap(priv); if (priv->currenttxskb) { @@ -392,7 +397,7 @@ static int lbs_dev_open(struct net_device *dev) spin_lock_irq(&priv->driver_lock); - if (priv->monitormode != LBS_MONITOR_OFF) { + if (priv->monitormode) { ret = -EBUSY; goto out; } @@ -531,34 +536,27 @@ static int lbs_set_mac_address(struct net_device *dev, void *addr) int ret = 0; struct lbs_private *priv = (struct lbs_private *) dev->priv; struct sockaddr *phwaddr = addr; + struct cmd_ds_802_11_mac_address cmd; lbs_deb_enter(LBS_DEB_NET); /* In case it was called from the mesh device */ - dev = priv->dev ; - - memset(priv->current_addr, 0, ETH_ALEN); - - /* dev->dev_addr is 8 bytes */ - lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN); - - lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN); - memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); + dev = priv->dev; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); if (ret) { lbs_deb_net("set MAC address failed\n"); - ret = -1; goto done; } - lbs_deb_hex(LBS_DEB_NET, "priv->macaddr", priv->current_addr, ETH_ALEN); - memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN); + memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); + memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); if (priv->mesh_dev) - memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); + memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); @@ -581,45 +579,45 @@ static int lbs_copy_multicast_address(struct lbs_private *priv, static void lbs_set_multicast_list(struct net_device *dev) { struct lbs_private *priv = dev->priv; - int oldpacketfilter; + int old_mac_control; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_NET); - oldpacketfilter = priv->currentpacketfilter; + old_mac_control = priv->mac_control; if (dev->flags & IFF_PROMISC) { lbs_deb_net("enable promiscuous mode\n"); - priv->currentpacketfilter |= + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; - priv->currentpacketfilter &= + priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | CMD_ACT_MAC_MULTICAST_ENABLE); } else { /* Multicast */ - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (dev->flags & IFF_ALLMULTI || dev->mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { lbs_deb_net( "enabling all multicast\n"); - priv->currentpacketfilter |= + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; if (!dev->mc_count) { lbs_deb_net("no multicast addresses, " "disabling multicast\n"); - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { int i; - priv->currentpacketfilter |= + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; priv->nr_of_multicastmacaddr = @@ -642,9 +640,8 @@ static void lbs_set_multicast_list(struct net_device *dev) } } - if (priv->currentpacketfilter != oldpacketfilter) { - lbs_set_mac_packet_filter(priv); - } + if (priv->mac_control != old_mac_control) + lbs_set_mac_control(priv); lbs_deb_leave(LBS_DEB_NET); } @@ -804,7 +801,7 @@ static int lbs_thread(void *data) lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n", priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd); - lbs_ps_confirm_sleep(priv, (u16) priv->psmode); + lbs_ps_confirm_sleep(priv); } else { /* workaround for firmware sending * deauth/linkloss event immediately @@ -945,7 +942,7 @@ static int lbs_setup_firmware(struct lbs_private *priv) goto done; } - lbs_set_mac_packet_filter(priv); + lbs_set_mac_control(priv); ret = lbs_get_data_rate(priv); if (ret < 0) { @@ -985,6 +982,18 @@ out: lbs_deb_leave(LBS_DEB_CMD); } +static void lbs_sync_channel_worker(struct work_struct *work) +{ + struct lbs_private *priv = container_of(work, struct lbs_private, + sync_channel); + + lbs_deb_enter(LBS_DEB_MAIN); + if (lbs_update_channel(priv)) + lbs_pr_info("Channel synchronization failed."); + lbs_deb_leave(LBS_DEB_MAIN); +} + + static int lbs_init_adapter(struct lbs_private *priv) { size_t bufsize; @@ -1009,14 +1018,6 @@ static int lbs_init_adapter(struct lbs_private *priv) &priv->network_free_list); } - priv->lbs_ps_confirm_sleep.seqnum = cpu_to_le16(++priv->seqnum); - priv->lbs_ps_confirm_sleep.command = - cpu_to_le16(CMD_802_11_PS_MODE); - priv->lbs_ps_confirm_sleep.size = - cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - priv->lbs_ps_confirm_sleep.action = - cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - memset(priv->current_addr, 0xff, ETH_ALEN); priv->connect_status = LBS_DISCONNECTED; @@ -1024,7 +1025,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - priv->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radioon = RADIO_ON; priv->auto_rate = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; @@ -1128,7 +1129,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); - INIT_WORK(&priv->sync_channel, lbs_sync_channel); + INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; @@ -1380,7 +1381,7 @@ static void lbs_remove_mesh(struct lbs_private *priv) * @param cfp_no A pointer to CFP number * @return A pointer to CFP */ -struct chan_freq_power *lbs_get_region_cfp_table(u8 region, u8 band, int *cfp_no) +struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) { int i, end; @@ -1414,7 +1415,7 @@ int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) memset(priv->region_channel, 0, sizeof(priv->region_channel)); - cfp = lbs_get_region_cfp_table(region, band, &cfp_no); + cfp = lbs_get_region_cfp_table(region, &cfp_no); if (cfp != NULL) { priv->region_channel[i].nrcfp = cfp_no; priv->region_channel[i].CFP = cfp; @@ -1458,6 +1459,10 @@ EXPORT_SYMBOL_GPL(lbs_interrupt); static int __init lbs_init_module(void) { lbs_deb_enter(LBS_DEB_MAIN); + memset(&confirm_sleep, 0, sizeof(confirm_sleep)); + confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE); + confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep)); + confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); lbs_debugfs_init(); lbs_deb_leave(LBS_DEB_MAIN); return 0; @@ -1554,6 +1559,32 @@ out: return ret; } +#ifndef CONFIG_IEEE80211 +const char *escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "<hidden>", sizeof("<hidden>")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else { + *d++ = *s++; + } + } + *d = '\0'; + return escaped; +} +#endif module_init(lbs_init_module); module_exit(lbs_exit_module); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 149557a478a..09f023089ea 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -155,7 +155,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; - if (priv->monitormode != LBS_MONITOR_OFF) + if (priv->monitormode) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 69f94c92b32..e72c97a0d6c 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -4,22 +4,14 @@ * IOCTL handlers as well as command preperation and response routines * for sending scan commands to the firmware. */ -#include <linux/ctype.h> -#include <linux/if.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> #include <linux/etherdevice.h> - -#include <net/ieee80211.h> -#include <net/iw_handler.h> - #include <asm/unaligned.h> #include "host.h" #include "decl.h" #include "dev.h" #include "scan.h" -#include "join.h" +#include "cmd.h" //! Approximate amount of data needed to pass a scan result back to iwlist #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ @@ -39,10 +31,9 @@ //! Memory needed to store a max number/size SSID TLV for a firmware scan #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) -//! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max -#define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config) \ - + CHAN_TLV_MAX_SIZE \ - + SSID_TLV_MAX_SIZE) +//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max +#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ + + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE) //! The maximum number of channels the firmware can scan per command #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 @@ -61,11 +52,8 @@ //! Scan time specified in the channel TLV for each channel for active scans #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 -static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - - - +static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, + struct cmd_header *resp); /*********************************************************************/ /* */ @@ -73,7 +61,24 @@ static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* */ /*********************************************************************/ -static inline void clear_bss_descriptor (struct bss_descriptor * bss) +/** + * @brief Unsets the MSB on basic rates + * + * Scan through an array and unset the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void lbs_unset_basic_rate_flags(u8 *rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + rates[i] &= 0x7f; +} + + +static inline void clear_bss_descriptor(struct bss_descriptor *bss) { /* Don't blow away ->list, just BSS data */ memset(bss, 0, offsetof(struct bss_descriptor, list)); @@ -87,7 +92,8 @@ static inline void clear_bss_descriptor (struct bss_descriptor * bss) * * @return 0: ssid is same, otherwise is different */ -int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) +int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2, + uint8_t ssid2_len) { if (ssid1_len != ssid2_len) return -1; @@ -95,76 +101,6 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) return memcmp(ssid1, ssid2, ssid1_len); } -static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, - struct bss_descriptor * match_bss) -{ - if ( !secinfo->wep_enabled - && !secinfo->WPAenabled - && !secinfo->WPA2enabled - && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC - && match_bss->rsn_ie[0] != MFIE_TYPE_RSN - && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { - return 1; - } - return 0; -} - -static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, - struct bss_descriptor * match_bss) -{ - if ( secinfo->wep_enabled - && !secinfo->WPAenabled - && !secinfo->WPA2enabled - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { - return 1; - } - return 0; -} - -static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, - struct bss_descriptor * match_bss) -{ - if ( !secinfo->wep_enabled - && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) - /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { - */ - ) { - return 1; - } - return 0; -} - -static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, - struct bss_descriptor * match_bss) -{ - if ( !secinfo->wep_enabled - && secinfo->WPA2enabled - && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) - /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { - */ - ) { - return 1; - } - return 0; -} - -static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, - struct bss_descriptor * match_bss) -{ - if ( !secinfo->wep_enabled - && !secinfo->WPAenabled - && !secinfo->WPA2enabled - && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) - && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { - return 1; - } - return 0; -} - static inline int is_same_network(struct bss_descriptor *src, struct bss_descriptor *dst) { @@ -177,83 +113,6 @@ static inline int is_same_network(struct bss_descriptor *src, !memcmp(src->ssid, dst->ssid, src->ssid_len)); } -/** - * @brief Check if a scanned network compatible with the driver settings - * - * WEP WPA WPA2 ad-hoc encrypt Network - * enabled enabled enabled AES mode privacy WPA WPA2 Compatible - * 0 0 0 0 NONE 0 0 0 yes No security - * 1 0 0 0 NONE 1 0 0 yes Static WEP - * 0 1 0 0 x 1x 1 x yes WPA - * 0 0 1 0 x 1x x 1 yes WPA2 - * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES - * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP - * - * - * @param priv A pointer to struct lbs_private - * @param index Index in scantable to check against current driver settings - * @param mode Network mode: Infrastructure or IBSS - * - * @return Index in scantable, or error code if negative - */ -static int is_network_compatible(struct lbs_private *priv, - struct bss_descriptor * bss, u8 mode) -{ - int matched = 0; - - lbs_deb_enter(LBS_DEB_SCAN); - - if (bss->mode != mode) - goto done; - - if ((matched = match_bss_no_security(&priv->secinfo, bss))) { - goto done; - } else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) { - goto done; - } else if ((matched = match_bss_wpa(&priv->secinfo, bss))) { - lbs_deb_scan( - "is_network_compatible() WPA: wpa_ie 0x%x " - "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " - "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], - priv->secinfo.wep_enabled ? "e" : "d", - priv->secinfo.WPAenabled ? "e" : "d", - priv->secinfo.WPA2enabled ? "e" : "d", - (bss->capability & WLAN_CAPABILITY_PRIVACY)); - goto done; - } else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) { - lbs_deb_scan( - "is_network_compatible() WPA2: wpa_ie 0x%x " - "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " - "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], - priv->secinfo.wep_enabled ? "e" : "d", - priv->secinfo.WPAenabled ? "e" : "d", - priv->secinfo.WPA2enabled ? "e" : "d", - (bss->capability & WLAN_CAPABILITY_PRIVACY)); - goto done; - } else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) { - lbs_deb_scan( - "is_network_compatible() dynamic WEP: " - "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", - bss->wpa_ie[0], bss->rsn_ie[0], - (bss->capability & WLAN_CAPABILITY_PRIVACY)); - goto done; - } - - /* bss security settings don't match those configured on card */ - lbs_deb_scan( - "is_network_compatible() FAILED: wpa_ie 0x%x " - "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", - bss->wpa_ie[0], bss->rsn_ie[0], - priv->secinfo.wep_enabled ? "e" : "d", - priv->secinfo.WPAenabled ? "e" : "d", - priv->secinfo.WPA2enabled ? "e" : "d", - (bss->capability & WLAN_CAPABILITY_PRIVACY)); - -done: - lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); - return matched; -} - @@ -263,17 +122,6 @@ done: /* */ /*********************************************************************/ -void lbs_scan_worker(struct work_struct *work) -{ - struct lbs_private *priv = - container_of(work, struct lbs_private, scan_work.work); - - lbs_deb_enter(LBS_DEB_SCAN); - lbs_scan_networks(priv, NULL, 0); - lbs_deb_leave(LBS_DEB_SCAN); -} - - /** * @brief Create a channel list for the driver to scan based on region info * @@ -285,25 +133,18 @@ void lbs_scan_worker(struct work_struct *work) * * @param priv A pointer to struct lbs_private structure * @param scanchanlist Output parameter: resulting channel list to scan - * @param filteredscan Flag indicating whether or not a BSSID or SSID filter - * is being sent in the command to firmware. Used to - * increase the number of channels sent in a scan - * command and to disable the firmware channel scan - * filter. * * @return void */ static int lbs_scan_create_channel_list(struct lbs_private *priv, - struct chanscanparamset * scanchanlist, - u8 filteredscan) + struct chanscanparamset *scanchanlist) { - struct region_channel *scanregion; struct chan_freq_power *cfp; int rgnidx; int chanidx; int nextchan; - u8 scantype; + uint8_t scantype; chanidx = 0; @@ -314,9 +155,8 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, scantype = CMD_SCAN_TYPE_ACTIVE; for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { - if (priv->enable11d && - (priv->connect_status != LBS_CONNECTED) && - (priv->mesh_connect_status != LBS_CONNECTED)) { + if (priv->enable11d && (priv->connect_status != LBS_CONNECTED) + && (priv->mesh_connect_status != LBS_CONNECTED)) { /* Scan all the supported chan for the first scan */ if (!priv->universal_channel[rgnidx].valid) continue; @@ -331,51 +171,32 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, scanregion = &priv->region_channel[rgnidx]; } - for (nextchan = 0; - nextchan < scanregion->nrcfp; nextchan++, chanidx++) { + for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { + struct chanscanparamset *chan = &scanchanlist[chanidx]; cfp = scanregion->CFP + nextchan; - if (priv->enable11d) { - scantype = - lbs_get_scan_type_11d(cfp->channel, - &priv-> - parsed_region_chan); - } + if (priv->enable11d) + scantype = lbs_get_scan_type_11d(cfp->channel, + &priv->parsed_region_chan); - switch (scanregion->band) { - case BAND_B: - case BAND_G: - default: - scanchanlist[chanidx].radiotype = - CMD_SCAN_RADIO_TYPE_BG; - break; - } + if (scanregion->band == BAND_B || scanregion->band == BAND_G) + chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; if (scantype == CMD_SCAN_TYPE_PASSIVE) { - scanchanlist[chanidx].maxscantime = - cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); - scanchanlist[chanidx].chanscanmode.passivescan = - 1; + chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); + chan->chanscanmode.passivescan = 1; } else { - scanchanlist[chanidx].maxscantime = - cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME); - scanchanlist[chanidx].chanscanmode.passivescan = - 0; + chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME); + chan->chanscanmode.passivescan = 0; } - scanchanlist[chanidx].channumber = cfp->channel; - - if (filteredscan) { - scanchanlist[chanidx].chanscanmode. - disablechanfilt = 1; - } + chan->channumber = cfp->channel; } } return chanidx; } - /* * Add SSID TLV of the form: * @@ -383,18 +204,16 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, * length 06 00 * ssid 4d 4e 54 45 53 54 */ -static int lbs_scan_add_ssid_tlv(u8 *tlv, - const struct lbs_ioctl_user_scan_cfg *user_cfg) +static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) { - struct mrvlietypes_ssidparamset *ssid_tlv = - (struct mrvlietypes_ssidparamset *)tlv; + struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; + ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); - ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len); - memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len); - return sizeof(ssid_tlv->header) + user_cfg->ssid_len; + ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); + memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len); + return sizeof(ssid_tlv->header) + priv->scan_ssid_len; } - /* * Add CHANLIST TLV of the form * @@ -420,13 +239,12 @@ static int lbs_scan_add_ssid_tlv(u8 *tlv, * channel 13 00 0d 00 00 00 64 00 * */ -static int lbs_scan_add_chanlist_tlv(u8 *tlv, - struct chanscanparamset *chan_list, - int chan_count) +static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, + struct chanscanparamset *chan_list, + int chan_count) { - size_t size = sizeof(struct chanscanparamset) * chan_count; - struct mrvlietypes_chanlistparamset *chan_tlv = - (struct mrvlietypes_chanlistparamset *) tlv; + size_t size = sizeof(struct chanscanparamset) *chan_count; + struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); memcpy(chan_tlv->chanscanparam, chan_list, size); @@ -434,7 +252,6 @@ static int lbs_scan_add_chanlist_tlv(u8 *tlv, return sizeof(chan_tlv->header) + size; } - /* * Add RATES TLV of the form * @@ -445,11 +262,10 @@ static int lbs_scan_add_chanlist_tlv(u8 *tlv, * The rates are in lbs_bg_rates[], but for the 802.11b * rates the high bit isn't set. */ -static int lbs_scan_add_rates_tlv(u8 *tlv) +static int lbs_scan_add_rates_tlv(uint8_t *tlv) { int i; - struct mrvlietypes_ratesparamset *rate_tlv = - (struct mrvlietypes_ratesparamset *) tlv; + struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv; rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); tlv += sizeof(rate_tlv->header); @@ -470,82 +286,74 @@ static int lbs_scan_add_rates_tlv(u8 *tlv) return sizeof(rate_tlv->header) + i; } - /* * Generate the CMD_802_11_SCAN command with the proper tlv * for a bunch of channels. */ -static int lbs_do_scan(struct lbs_private *priv, - u8 bsstype, - struct chanscanparamset *chan_list, - int chan_count, - const struct lbs_ioctl_user_scan_cfg *user_cfg) +static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, + struct chanscanparamset *chan_list, int chan_count) { int ret = -ENOMEM; - struct lbs_scan_cmd_config *scan_cmd; - u8 *tlv; /* pointer into our current, growing TLV storage area */ + struct cmd_ds_802_11_scan *scan_cmd; + uint8_t *tlv; /* pointer into our current, growing TLV storage area */ - lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, " - "chan_count %d", - bsstype, chan_list[0].channumber, chan_count); + lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d", + bsstype, chan_list[0].channumber, chan_count); /* create the fixed part for scan command */ scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); if (scan_cmd == NULL) goto out; + tlv = scan_cmd->tlvbuffer; - if (user_cfg) - memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN); + /* TODO: do we need to scan for a specific BSSID? + memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */ scan_cmd->bsstype = bsstype; /* add TLVs */ - if (user_cfg && user_cfg->ssid_len) - tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg); + if (priv->scan_ssid_len) + tlv += lbs_scan_add_ssid_tlv(priv, tlv); if (chan_list && chan_count) tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count); tlv += lbs_scan_add_rates_tlv(tlv); /* This is the final data we are about to send */ - scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer; - lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6); + scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd); + lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, + sizeof(*scan_cmd)); lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, - scan_cmd->tlvbufferlen); + tlv - scan_cmd->tlvbuffer); + + ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr, + le16_to_cpu(scan_cmd->hdr.size), + lbs_ret_80211_scan, 0); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, - CMD_OPTION_WAITFORRSP, 0, scan_cmd); out: kfree(scan_cmd); lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } - /** * @brief Internal function used to start a scan based on an input config * - * Also used from debugfs - * * Use the input user scan configuration information when provided in * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table * * @param priv A pointer to struct lbs_private structure - * @param puserscanin Pointer to the input configuration for the requested - * scan. + * @param full_scan Do a full-scan (blocking) * * @return 0 or < 0 if error */ -int lbs_scan_networks(struct lbs_private *priv, - const struct lbs_ioctl_user_scan_cfg *user_cfg, - int full_scan) +int lbs_scan_networks(struct lbs_private *priv, int full_scan) { int ret = -ENOMEM; struct chanscanparamset *chan_list; struct chanscanparamset *curr_chans; int chan_count; - u8 bsstype = CMD_BSS_TYPE_ANY; + uint8_t bsstype = CMD_BSS_TYPE_ANY; int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; - int filteredscan = 0; union iwreq_data wrqu; #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor *iter; @@ -553,8 +361,7 @@ int lbs_scan_networks(struct lbs_private *priv, DECLARE_MAC_BUF(mac); #endif - lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", - full_scan); + lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); /* Cancel any partial outstanding partial scans if this scan * is a full scan. @@ -562,30 +369,27 @@ int lbs_scan_networks(struct lbs_private *priv, if (full_scan && delayed_work_pending(&priv->scan_work)) cancel_delayed_work(&priv->scan_work); - /* Determine same scan parameters */ + /* User-specified bsstype or channel list + TODO: this can be implemented if some user-space application + need the feature. Formerly, it was accessible from debugfs, + but then nowhere used. if (user_cfg) { if (user_cfg->bsstype) - bsstype = user_cfg->bsstype; - if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) { - numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN; - filteredscan = 1; - } - } - lbs_deb_scan("numchannels %d, bsstype %d, " - "filteredscan %d\n", - numchannels, bsstype, filteredscan); + bsstype = user_cfg->bsstype; + } */ + + lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype); /* Create list of channels to scan */ chan_list = kzalloc(sizeof(struct chanscanparamset) * - LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); + LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); if (!chan_list) { lbs_pr_alert("SCAN: chan_list empty\n"); goto out; } /* We want to scan all channels */ - chan_count = lbs_scan_create_channel_list(priv, chan_list, - filteredscan); + chan_count = lbs_scan_create_channel_list(priv, chan_list); netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); @@ -595,13 +399,13 @@ int lbs_scan_networks(struct lbs_private *priv, } /* Prepare to continue an interrupted scan */ - lbs_deb_scan("chan_count %d, last_scanned_channel %d\n", - chan_count, priv->last_scanned_channel); + lbs_deb_scan("chan_count %d, scan_channel %d\n", + chan_count, priv->scan_channel); curr_chans = chan_list; /* advance channel list by already-scanned-channels */ - if (priv->last_scanned_channel > 0) { - curr_chans += priv->last_scanned_channel; - chan_count -= priv->last_scanned_channel; + if (priv->scan_channel > 0) { + curr_chans += priv->scan_channel; + chan_count -= priv->scan_channel; } /* Send scan command(s) @@ -612,9 +416,9 @@ int lbs_scan_networks(struct lbs_private *priv, while (chan_count) { int to_scan = min(numchannels, chan_count); lbs_deb_scan("scanning %d of %d channels\n", - to_scan, chan_count); + to_scan, chan_count); ret = lbs_do_scan(priv, bsstype, curr_chans, - to_scan, user_cfg); + to_scan); if (ret) { lbs_pr_err("SCAN_CMD failed\n"); goto out2; @@ -623,17 +427,16 @@ int lbs_scan_networks(struct lbs_private *priv, chan_count -= to_scan; /* somehow schedule the next part of the scan */ - if (chan_count && - !full_scan && + if (chan_count && !full_scan && !priv->surpriseremoved) { /* -1 marks just that we're currently scanning */ - if (priv->last_scanned_channel < 0) - priv->last_scanned_channel = to_scan; + if (priv->scan_channel < 0) + priv->scan_channel = to_scan; else - priv->last_scanned_channel += to_scan; + priv->scan_channel += to_scan; cancel_delayed_work(&priv->scan_work); queue_delayed_work(priv->work_thread, &priv->scan_work, - msecs_to_jiffies(300)); + msecs_to_jiffies(300)); /* skip over GIWSCAN event */ goto out; } @@ -648,13 +451,13 @@ int lbs_scan_networks(struct lbs_private *priv, lbs_deb_scan("scan table:\n"); list_for_each_entry(iter, &priv->network_list, list) lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n", - i++, print_mac(mac, iter->bssid), (s32) iter->rssi, - escape_essid(iter->ssid, iter->ssid_len)); + i++, print_mac(mac, iter->bssid), iter->rssi, + escape_essid(iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif out2: - priv->last_scanned_channel = 0; + priv->scan_channel = 0; out: if (priv->connect_status == LBS_CONNECTED) { @@ -673,7 +476,15 @@ out: return ret; } +void lbs_scan_worker(struct work_struct *work) +{ + struct lbs_private *priv = + container_of(work, struct lbs_private, scan_work.work); + lbs_deb_enter(LBS_DEB_SCAN); + lbs_scan_networks(priv, 0); + lbs_deb_leave(LBS_DEB_SCAN); +} /*********************************************************************/ @@ -694,7 +505,7 @@ out: * @return 0 or -1 */ static int lbs_process_bss(struct bss_descriptor *bss, - u8 ** pbeaconinfo, int *bytesleft) + uint8_t **pbeaconinfo, int *bytesleft) { struct ieeetypes_fhparamset *pFH; struct ieeetypes_dsparamset *pDS; @@ -702,9 +513,9 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieeetypes_ibssparamset *pibss; DECLARE_MAC_BUF(mac); struct ieeetypes_countryinfoset *pcountryinfo; - u8 *pos, *end, *p; - u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; - u16 beaconsize = 0; + uint8_t *pos, *end, *p; + uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; + uint16_t beaconsize = 0; int ret; lbs_deb_enter(LBS_DEB_SCAN); @@ -776,12 +587,11 @@ static int lbs_process_bss(struct bss_descriptor *bss, /* process variable IE */ while (pos <= end - 2) { - struct ieee80211_info_element * elem = - (struct ieee80211_info_element *) pos; + struct ieee80211_info_element * elem = (void *)pos; if (pos + elem->len > end) { lbs_deb_scan("process_bss: error in processing IE, " - "bytes left < IE length\n"); + "bytes left < IE length\n"); break; } @@ -795,7 +605,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; case MFIE_TYPE_RATES: - n_basic_rates = min_t(u8, MAX_RATES, elem->len); + n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len); memcpy(bss->rates, elem->data, n_basic_rates); got_basic_rates = 1; lbs_deb_scan("got RATES IE\n"); @@ -836,19 +646,16 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got COUNTRY IE\n"); if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) || pcountryinfo->len > 254) { - lbs_deb_scan("process_bss: 11D- Err " - "CountryInfo len %d, min %zd, max 254\n", - pcountryinfo->len, - sizeof(pcountryinfo->countrycode)); + lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n", + pcountryinfo->len, sizeof(pcountryinfo->countrycode)); ret = -1; goto done; } - memcpy(&bss->countryinfo, - pcountryinfo, pcountryinfo->len + 2); + memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", - (u8 *) pcountryinfo, - (u32) (pcountryinfo->len + 2)); + (uint8_t *) pcountryinfo, + (int) (pcountryinfo->len + 2)); break; case MFIE_TYPE_RATES_EX: @@ -872,26 +679,19 @@ static int lbs_process_bss(struct bss_descriptor *bss, case MFIE_TYPE_GENERIC: if (elem->len >= 4 && - elem->data[0] == 0x00 && - elem->data[1] == 0x50 && - elem->data[2] == 0xf2 && - elem->data[3] == 0x01) { - bss->wpa_ie_len = min(elem->len + 2, - MAX_WPA_IE_LEN); + elem->data[0] == 0x00 && elem->data[1] == 0x50 && + elem->data[2] == 0xf2 && elem->data[3] == 0x01) { + bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); lbs_deb_scan("got WPA IE\n"); - lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, - elem->len); + lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len); } else if (elem->len >= MARVELL_MESH_IE_LENGTH && - elem->data[0] == 0x00 && - elem->data[1] == 0x50 && - elem->data[2] == 0x43 && - elem->data[3] == 0x04) { + elem->data[0] == 0x00 && elem->data[1] == 0x50 && + elem->data[2] == 0x43 && elem->data[3] == 0x04) { lbs_deb_scan("got mesh IE\n"); bss->mesh = 1; } else { - lbs_deb_scan("got generiec IE: " - "%02x:%02x:%02x:%02x, len %d\n", + lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n", elem->data[0], elem->data[1], elem->data[2], elem->data[3], elem->len); @@ -903,12 +703,12 @@ static int lbs_process_bss(struct bss_descriptor *bss, bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", - bss->rsn_ie, elem->len); + bss->rsn_ie, elem->len); break; default: lbs_deb_scan("got IE 0x%04x, len %d\n", - elem->id, elem->len); + elem->id, elem->len); break; } @@ -927,213 +727,6 @@ done: } /** - * @brief This function finds a specific compatible BSSID in the scan list - * - * Used in association code - * - * @param priv A pointer to struct lbs_private - * @param bssid BSSID to find in the scan list - * @param mode Network mode: Infrastructure or IBSS - * - * @return index in BSSID list, or error return code (< 0) - */ -struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, - u8 * bssid, u8 mode) -{ - struct bss_descriptor * iter_bss; - struct bss_descriptor * found_bss = NULL; - - lbs_deb_enter(LBS_DEB_SCAN); - - if (!bssid) - goto out; - - lbs_deb_hex(LBS_DEB_SCAN, "looking for", - bssid, ETH_ALEN); - - /* Look through the scan table for a compatible match. The loop will - * continue past a matched bssid that is not compatible in case there - * is an AP with multiple SSIDs assigned to the same BSSID - */ - mutex_lock(&priv->lock); - list_for_each_entry (iter_bss, &priv->network_list, list) { - if (compare_ether_addr(iter_bss->bssid, bssid)) - continue; /* bssid doesn't match */ - switch (mode) { - case IW_MODE_INFRA: - case IW_MODE_ADHOC: - if (!is_network_compatible(priv, iter_bss, mode)) - break; - found_bss = iter_bss; - break; - default: - found_bss = iter_bss; - break; - } - } - mutex_unlock(&priv->lock); - -out: - lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); - return found_bss; -} - -/** - * @brief This function finds ssid in ssid list. - * - * Used in association code - * - * @param priv A pointer to struct lbs_private - * @param ssid SSID to find in the list - * @param bssid BSSID to qualify the SSID selection (if provided) - * @param mode Network mode: Infrastructure or IBSS - * - * @return index in BSSID list - */ -struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, - u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, - int channel) -{ - u8 bestrssi = 0; - struct bss_descriptor * iter_bss = NULL; - struct bss_descriptor * found_bss = NULL; - struct bss_descriptor * tmp_oldest = NULL; - - lbs_deb_enter(LBS_DEB_SCAN); - - mutex_lock(&priv->lock); - - list_for_each_entry (iter_bss, &priv->network_list, list) { - if ( !tmp_oldest - || (iter_bss->last_scanned < tmp_oldest->last_scanned)) - tmp_oldest = iter_bss; - - if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, - ssid, ssid_len) != 0) - continue; /* ssid doesn't match */ - if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) - continue; /* bssid doesn't match */ - if ((channel > 0) && (iter_bss->channel != channel)) - continue; /* channel doesn't match */ - - switch (mode) { - case IW_MODE_INFRA: - case IW_MODE_ADHOC: - if (!is_network_compatible(priv, iter_bss, mode)) - break; - - if (bssid) { - /* Found requested BSSID */ - found_bss = iter_bss; - goto out; - } - - if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { - bestrssi = SCAN_RSSI(iter_bss->rssi); - found_bss = iter_bss; - } - break; - case IW_MODE_AUTO: - default: - if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { - bestrssi = SCAN_RSSI(iter_bss->rssi); - found_bss = iter_bss; - } - break; - } - } - -out: - mutex_unlock(&priv->lock); - lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); - return found_bss; -} - -/** - * @brief This function finds the best SSID in the Scan List - * - * Search the scan table for the best SSID that also matches the current - * adapter network preference (infrastructure or adhoc) - * - * @param priv A pointer to struct lbs_private - * - * @return index in BSSID list - */ -static struct bss_descriptor *lbs_find_best_ssid_in_list( - struct lbs_private *priv, - u8 mode) -{ - u8 bestrssi = 0; - struct bss_descriptor * iter_bss; - struct bss_descriptor * best_bss = NULL; - - lbs_deb_enter(LBS_DEB_SCAN); - - mutex_lock(&priv->lock); - - list_for_each_entry (iter_bss, &priv->network_list, list) { - switch (mode) { - case IW_MODE_INFRA: - case IW_MODE_ADHOC: - if (!is_network_compatible(priv, iter_bss, mode)) - break; - if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) - break; - bestrssi = SCAN_RSSI(iter_bss->rssi); - best_bss = iter_bss; - break; - case IW_MODE_AUTO: - default: - if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) - break; - bestrssi = SCAN_RSSI(iter_bss->rssi); - best_bss = iter_bss; - break; - } - } - - mutex_unlock(&priv->lock); - lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); - return best_bss; -} - -/** - * @brief Find the AP with specific ssid in the scan list - * - * Used from association worker. - * - * @param priv A pointer to struct lbs_private structure - * @param pSSID A pointer to AP's ssid - * - * @return 0--success, otherwise--fail - */ -int lbs_find_best_network_ssid(struct lbs_private *priv, - u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode) -{ - int ret = -1; - struct bss_descriptor * found; - - lbs_deb_enter(LBS_DEB_SCAN); - - lbs_scan_networks(priv, NULL, 1); - if (priv->surpriseremoved) - goto out; - - found = lbs_find_best_ssid_in_list(priv, preferred_mode); - if (found && (found->ssid_len > 0)) { - memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); - *out_ssid_len = found->ssid_len; - *out_mode = found->mode; - ret = 0; - } - -out: - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); - return ret; -} - - -/** * @brief Send a scan command for all available channels filtered on a spec * * Used in association code and from debugfs @@ -1141,29 +734,24 @@ out: * @param priv A pointer to struct lbs_private structure * @param ssid A pointer to the SSID to scan for * @param ssid_len Length of the SSID - * @param clear_ssid Should existing scan results with this SSID - * be cleared? * * @return 0-success, otherwise fail */ -int lbs_send_specific_ssid_scan(struct lbs_private *priv, - u8 *ssid, u8 ssid_len, u8 clear_ssid) +int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, + uint8_t ssid_len) { - struct lbs_ioctl_user_scan_cfg scancfg; int ret = 0; - lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", - escape_essid(ssid, ssid_len), clear_ssid); + lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", + escape_essid(ssid, ssid_len)); if (!ssid_len) goto out; - memset(&scancfg, 0x00, sizeof(scancfg)); - memcpy(scancfg.ssid, ssid, ssid_len); - scancfg.ssid_len = ssid_len; - scancfg.clear_ssid = clear_ssid; + memcpy(priv->scan_ssid, ssid, ssid_len); + priv->scan_ssid_len = ssid_len; - lbs_scan_networks(priv, &scancfg, 1); + lbs_scan_networks(priv, 1); if (priv->surpriseremoved) { ret = -1; goto out; @@ -1187,17 +775,17 @@ out: #define MAX_CUSTOM_LEN 64 static inline char *lbs_translate_scan(struct lbs_private *priv, - char *start, char *stop, - struct bss_descriptor *bss) + char *start, char *stop, + struct bss_descriptor *bss) { struct chan_freq_power *cfp; char *current_val; /* For rates */ struct iw_event iwe; /* Temporary buffer */ int j; -#define PERFECT_RSSI ((u8)50) -#define WORST_RSSI ((u8)0) -#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) - u8 rssi; +#define PERFECT_RSSI ((uint8_t)50) +#define WORST_RSSI ((uint8_t)0) +#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI)) + uint8_t rssi; lbs_deb_enter(LBS_DEB_SCAN); @@ -1217,7 +805,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, /* SSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - iwe.u.data.length = min((u32) bss->ssid_len, (u32) IW_ESSID_MAX_SIZE); + iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); start = iwe_stream_add_point(start, stop, &iwe, bss->ssid); /* Mode */ @@ -1238,28 +826,26 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; iwe.u.qual.qual = - (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * - (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / - (RSSI_DIFF * RSSI_DIFF); + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / + (RSSI_DIFF * RSSI_DIFF); if (iwe.u.qual.qual > 100) iwe.u.qual.qual = 100; if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; } else { - iwe.u.qual.noise = - CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); + iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); } /* Locally created ad-hoc BSSs won't have beacons if this is the * only station in the adhoc network; so get signal strength * from receive statistics. */ - if ((priv->mode == IW_MODE_ADHOC) - && priv->adhoccreate + if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate && !lbs_ssid_cmp(priv->curbssparams.ssid, - priv->curbssparams.ssid_len, - bss->ssid, bss->ssid_len)) { + priv->curbssparams.ssid_len, + bss->ssid, bss->ssid_len)) { int snr, nf; snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; @@ -1290,14 +876,13 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } - if ((bss->mode == IW_MODE_ADHOC) + if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate && !lbs_ssid_cmp(priv->curbssparams.ssid, - priv->curbssparams.ssid_len, - bss->ssid, bss->ssid_len) - && priv->adhoccreate) { + priv->curbssparams.ssid_len, + bss->ssid, bss->ssid_len)) { iwe.u.bitrate.value = 22 * 500000; current_val = iwe_stream_add_value(start, current_val, - stop, &iwe, IW_EV_PARAM_LEN); + stop, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ if((current_val - start) > IW_EV_LCP_LEN) @@ -1326,8 +911,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, char *p = custom; iwe.cmd = IWEVCUSTOM; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), - "mesh-type: olpc"); + p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc"); iwe.u.data.length = p - custom; if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); @@ -1350,39 +934,49 @@ out: * @return 0 --success, otherwise fail */ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *wrqu, char *extra) + union iwreq_data *wrqu, char *extra) { struct lbs_private *priv = dev->priv; + int ret = 0; - lbs_deb_enter(LBS_DEB_SCAN); + lbs_deb_enter(LBS_DEB_WEXT); - if (!netif_running(dev)) - return -ENETDOWN; + if (!netif_running(dev)) { + ret = -ENETDOWN; + goto out; + } /* mac80211 does this: struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->type != IEEE80211_IF_TYPE_xxx) - return -EOPNOTSUPP; + if (sdata->type != IEEE80211_IF_TYPE_xxx) { + ret = -EOPNOTSUPP; + goto out; + } + */ if (wrqu->data.length == sizeof(struct iw_scan_req) && wrqu->data.flags & IW_SCAN_THIS_ESSID) { - req = (struct iw_scan_req *)extra; - ssid = req->essid; - ssid_len = req->essid_len; + struct iw_scan_req *req = (struct iw_scan_req *)extra; + priv->scan_ssid_len = req->essid_len; + memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); + lbs_deb_wext("set_scan, essid '%s'\n", + escape_essid(priv->scan_ssid, priv->scan_ssid_len)); + } else { + priv->scan_ssid_len = 0; } - */ if (!delayed_work_pending(&priv->scan_work)) queue_delayed_work(priv->work_thread, &priv->scan_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(50)); /* set marker that currently a scan is taking place */ - priv->last_scanned_channel = -1; + priv->scan_channel = -1; if (priv->surpriseremoved) - return -EIO; + ret = -EIO; - lbs_deb_leave(LBS_DEB_SCAN); - return 0; +out: + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; } @@ -1397,31 +991,30 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, * @return 0 --success, otherwise fail */ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) + struct iw_point *dwrq, char *extra) { #define SCAN_ITEM_SIZE 128 struct lbs_private *priv = dev->priv; int err = 0; char *ev = extra; char *stop = ev + dwrq->length; - struct bss_descriptor * iter_bss; - struct bss_descriptor * safe; + struct bss_descriptor *iter_bss; + struct bss_descriptor *safe; - lbs_deb_enter(LBS_DEB_SCAN); + lbs_deb_enter(LBS_DEB_WEXT); /* iwlist should wait until the current scan is finished */ - if (priv->last_scanned_channel) + if (priv->scan_channel) return -EAGAIN; /* Update RSSI if current BSS is a locally created ad-hoc BSS */ - if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { + if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, - CMD_OPTION_WAITFORRSP, 0, NULL); - } + CMD_OPTION_WAITFORRSP, 0, NULL); mutex_lock(&priv->lock); list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { - char * next_ev; + char *next_ev; unsigned long stale_time; if (stop - ev < SCAN_ITEM_SIZE) { @@ -1436,8 +1029,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, /* Prune old an old scan result */ stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_after(jiffies, stale_time)) { - list_move_tail (&iter_bss->list, - &priv->network_free_list); + list_move_tail(&iter_bss->list, &priv->network_free_list); clear_bss_descriptor(iter_bss); continue; } @@ -1453,7 +1045,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, dwrq->length = (ev - extra); dwrq->flags = 0; - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err); + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); return err; } @@ -1468,44 +1060,6 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, /** - * @brief Prepare a scan command to be sent to the firmware - * - * Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...) - * from cmd.c - * - * Sends a fixed length data part (specifying the BSS type and BSSID filters) - * as well as a variable number/length of TLVs to the firmware. - * - * @param priv A pointer to struct lbs_private structure - * @param cmd A pointer to cmd_ds_command structure to be sent to - * firmware with the cmd_DS_801_11_SCAN structure - * @param pdata_buf Void pointer cast of a lbs_scan_cmd_config struct used - * to set the fields/TLVs for the command sent to firmware - * - * @return 0 or -1 - */ -int lbs_cmd_80211_scan(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; - struct lbs_scan_cmd_config *pscancfg = pdata_buf; - - lbs_deb_enter(LBS_DEB_SCAN); - - /* Set fixed field variables in scan command */ - pscan->bsstype = pscancfg->bsstype; - memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); - memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); - - /* size is equal to the sizeof(fixed portions) + the TLV len + header */ - cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN - + pscancfg->tlvbufferlen + S_DS_GEN); - - lbs_deb_leave(LBS_DEB_SCAN); - return 0; -} - -/** * @brief This function handles the command response of scan * * Called from handle_cmd_response() in cmdrespc. @@ -1531,13 +1085,14 @@ int lbs_cmd_80211_scan(struct lbs_private *priv, * * @return 0 or -1 */ -int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) +static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, + struct cmd_header *resp) { - struct cmd_ds_802_11_scan_rsp *pscan; - struct bss_descriptor * iter_bss; - struct bss_descriptor * safe; - u8 *pbssinfo; - u16 scanrespsize; + struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp; + struct bss_descriptor *iter_bss; + struct bss_descriptor *safe; + uint8_t *bssinfo; + uint16_t scanrespsize; int bytesleft; int idx; int tlvbufsize; @@ -1554,48 +1109,45 @@ int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) clear_bss_descriptor(iter_bss); } - pscan = &resp->params.scanresp; - - if (pscan->nr_sets > MAX_NETWORK_COUNT) { - lbs_deb_scan( - "SCAN_RESP: too many scan results (%d, max %d)!!\n", - pscan->nr_sets, MAX_NETWORK_COUNT); + if (scanresp->nr_sets > MAX_NETWORK_COUNT) { + lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n", + scanresp->nr_sets, MAX_NETWORK_COUNT); ret = -1; goto done; } - bytesleft = le16_to_cpu(pscan->bssdescriptsize); + bytesleft = le16_to_cpu(scanresp->bssdescriptsize); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); scanrespsize = le16_to_cpu(resp->size); - lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets); + lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets); - pbssinfo = pscan->bssdesc_and_tlvbuffer; + bssinfo = scanresp->bssdesc_and_tlvbuffer; /* The size of the TLV buffer is equal to the entire command response * size (scanrespsize) minus the fixed fields (sizeof()'s), the * BSS Descriptions (bssdescriptsize as bytesLef) and the command * response header (S_DS_GEN) */ - tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize) - + sizeof(pscan->nr_sets) + tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) + + sizeof(scanresp->nr_sets) + S_DS_GEN); /* - * Process each scan response returned (pscan->nr_sets). Save + * Process each scan response returned (scanresp->nr_sets). Save * the information in the newbssentry and then insert into the * driver scan table either as an update to an existing entry * or as an addition at the end of the table */ - for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { + for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) { struct bss_descriptor new; - struct bss_descriptor * found = NULL; - struct bss_descriptor * oldest = NULL; + struct bss_descriptor *found = NULL; + struct bss_descriptor *oldest = NULL; DECLARE_MAC_BUF(mac); /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); - if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) { + if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) { /* error parsing the scan response, skipped */ lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); continue; @@ -1630,8 +1182,7 @@ int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) continue; } - lbs_deb_scan("SCAN_RESP: BSSID %s\n", - print_mac(mac, new.bssid)); + lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid)); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 319f70dde35..9e07b0464a8 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -7,198 +7,22 @@ #ifndef _LBS_SCAN_H #define _LBS_SCAN_H -#include <net/ieee80211.h> -#include "hostcmd.h" - /** * @brief Maximum number of channels that can be sent in a setuserscan ioctl - * - * @sa lbs_ioctl_user_scan_cfg */ #define LBS_IOCTL_USER_SCAN_CHAN_MAX 50 -//! Infrastructure BSS scan type in lbs_scan_cmd_config -#define LBS_SCAN_BSS_TYPE_BSS 1 - -//! Adhoc BSS scan type in lbs_scan_cmd_config -#define LBS_SCAN_BSS_TYPE_IBSS 2 - -//! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter -#define LBS_SCAN_BSS_TYPE_ANY 3 - -/** - * @brief Structure used internally in the wlan driver to configure a scan. - * - * Sent to the command processing module to configure the firmware - * scan command prepared by lbs_cmd_80211_scan. - * - * @sa lbs_scan_networks - * - */ -struct lbs_scan_cmd_config { - /** - * @brief BSS type to be sent in the firmware command - * - * Field can be used to restrict the types of networks returned in the - * scan. valid settings are: - * - * - LBS_SCAN_BSS_TYPE_BSS (infrastructure) - * - LBS_SCAN_BSS_TYPE_IBSS (adhoc) - * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) - */ - u8 bsstype; - - /** - * @brief Specific BSSID used to filter scan results in the firmware - */ - u8 bssid[ETH_ALEN]; - - /** - * @brief length of TLVs sent in command starting at tlvBuffer - */ - int tlvbufferlen; - - /** - * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command - * - * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t - * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t - */ - u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here -}; - -/** - * @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg - * - * Multiple instances of this structure are included in the IOCTL command - * to configure a instance of a scan on the specific channel. - */ -struct lbs_ioctl_user_scan_chan { - u8 channumber; //!< channel Number to scan - u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1 - u8 scantype; //!< Scan type: Active = 0, Passive = 1 - u16 scantime; //!< Scan duration in milliseconds; if 0 default used -}; - -/** - * @brief IOCTL input structure to configure an immediate scan cmd to firmware - * - * Used in the setuserscan (LBS_SET_USER_SCAN) private ioctl. Specifies - * a number of parameters to be used in general for the scan as well - * as a channel list (lbs_ioctl_user_scan_chan) for each scan period - * desired. - * - * @sa lbs_set_user_scan_ioctl - */ -struct lbs_ioctl_user_scan_cfg { - /** - * @brief BSS type to be sent in the firmware command - * - * Field can be used to restrict the types of networks returned in the - * scan. valid settings are: - * - * - LBS_SCAN_BSS_TYPE_BSS (infrastructure) - * - LBS_SCAN_BSS_TYPE_IBSS (adhoc) - * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) - */ - u8 bsstype; - - /** - * @brief BSSID filter sent in the firmware command to limit the results - */ - u8 bssid[ETH_ALEN]; - - /* Clear existing scan results matching this BSSID */ - u8 clear_bssid; - - /** - * @brief SSID filter sent in the firmware command to limit the results - */ - char ssid[IW_ESSID_MAX_SIZE]; - u8 ssid_len; - - /* Clear existing scan results matching this SSID */ - u8 clear_ssid; -}; - -/** - * @brief Structure used to store information for each beacon/probe response - */ -struct bss_descriptor { - u8 bssid[ETH_ALEN]; - - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - - u16 capability; - - /* receive signal strength in dBm */ - long rssi; - - u32 channel; - - u16 beaconperiod; - - u32 atimwindow; - - /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ - u8 mode; - - /* zero-terminated array of supported data rates */ - u8 rates[MAX_RATES + 1]; - - unsigned long last_scanned; - - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; - - struct ieeetypes_countryinfofullset countryinfo; - - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - - u8 mesh; - - struct list_head list; -}; - int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); -struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, - u8 *ssid, u8 ssid_len, u8 *bssid, u8 mode, - int channel); - -struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, - u8 *bssid, u8 mode); - -int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid, - u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode); - int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, - u8 ssid_len, u8 clear_ssid); + u8 ssid_len); -int lbs_cmd_80211_scan(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - -int lbs_ret_80211_scan(struct lbs_private *priv, - struct cmd_ds_command *resp); - -int lbs_scan_networks(struct lbs_private *priv, - const struct lbs_ioctl_user_scan_cfg *puserscanin, - int full_scan); - -struct ifreq; - -struct iw_point; -struct iw_param; -struct iw_request_info; int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra); int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra); + union iwreq_data *wrqu, char *extra); + +int lbs_scan_networks(struct lbs_private *priv, int full_scan); void lbs_scan_worker(struct work_struct *work); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 00d95f75bd8..77f1f9525b8 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -151,7 +151,7 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - if (priv->monitormode != LBS_MONITOR_OFF) { + if (priv->monitormode) { /* Keep the skb to echo it back once Tx feedback is received from FW */ skb_orphan(skb); @@ -186,8 +186,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv) int txfail; int try_count; - if (priv->monitormode == LBS_MONITOR_OFF || - priv->currenttxskb == NULL) + if (!priv->monitormode || priv->currenttxskb == NULL) return; radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index f0d57958b34..4031be42086 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -239,4 +239,17 @@ struct mrvlietypes_ledgpio { struct led_pin ledpin[1]; } __attribute__ ((packed)); +struct led_bhv { + uint8_t firmwarestate; + uint8_t led; + uint8_t ledstate; + uint8_t ledarg; +} __attribute__ ((packed)); + + +struct mrvlietypes_ledbhv { + struct mrvlietypesheader header; + struct led_bhv ledbhv[1]; +} __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index e8bfc26b10a..0973d015a52 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -16,8 +16,8 @@ #include "decl.h" #include "defs.h" #include "dev.h" -#include "join.h" #include "wext.h" +#include "scan.h" #include "assoc.h" #include "cmd.h" @@ -579,6 +579,9 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->num_bitrates); range->num_frequency = 0; + + range->scan_capa = IW_SCAN_CAPA_ESSID; + if (priv->enable11d && (priv->connect_status == LBS_CONNECTED || priv->mesh_connect_status == LBS_CONNECTED)) { @@ -602,7 +605,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("chan_no %d\n", chan_no); range->freq[range->num_frequency].i = (long)chan_no; range->freq[range->num_frequency].m = - (long)lbs_chan_2_freq(chan_no, band) * 100000; + (long)lbs_chan_2_freq(chan_no) * 100000; range->freq[range->num_frequency].e = 1; range->num_frequency++; } @@ -653,13 +656,10 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->num_encoding_sizes = 2; range->max_encoding_tokens = 4; - range->min_pmp = 1000000; - range->max_pmp = 120000000; - range->min_pmt = 1000; - range->max_pmt = 1000000; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + /* + * Right now we support only "iwconfig ethX power on|off" + */ + range->pm_capa = IW_POWER_ON; /* * Minimum version we recommend @@ -781,21 +781,14 @@ static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { struct lbs_private *priv = dev->priv; - int mode; lbs_deb_enter(LBS_DEB_WEXT); - mode = priv->psmode; - - if ((vwrq->disabled = (mode == LBS802_11POWERMODECAM)) - || priv->connect_status == LBS_DISCONNECTED) - { - goto out; - } - vwrq->value = 0; + vwrq->flags = 0; + vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM + || priv->connect_status == LBS_DISCONNECTED; -out: lbs_deb_leave(LBS_DEB_WEXT); return 0; } @@ -817,6 +810,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) int stats_valid = 0; u8 rssi; u32 tx_retries; + struct cmd_ds_802_11_get_log log; lbs_deb_enter(LBS_DEB_WEXT); @@ -860,7 +854,11 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) /* Quality by TX errors */ priv->wstats.discard.retries = priv->stats.tx_errors; - tx_retries = le32_to_cpu(priv->logmsg.retry); + memset(&log, 0, sizeof(log)); + log.hdr.size = cpu_to_le16(sizeof(log)); + lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log); + + tx_retries = le32_to_cpu(log.retry); if (tx_retries > 75) tx_qual = (90 - tx_retries) * POOR / 15; @@ -876,10 +874,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; quality = min(quality, tx_qual); - priv->wstats.discard.code = le32_to_cpu(priv->logmsg.wepundecryptable); - priv->wstats.discard.fragment = le32_to_cpu(priv->logmsg.rxfrag); + priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable); priv->wstats.discard.retries = tx_retries; - priv->wstats.discard.misc = le32_to_cpu(priv->logmsg.ackfailure); + priv->wstats.discard.misc = le32_to_cpu(log.ackfailure); /* Calculate quality */ priv->wstats.qual.qual = min_t(u8, quality, 100); @@ -889,8 +886,6 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) /* update stats asynchronously for future calls */ lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, 0, 0, NULL); - lbs_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0, - 0, 0, NULL); out: if (!stats_valid) { priv->wstats.miss.beacon = 0; @@ -2065,23 +2060,6 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, return ret; } -void lbs_get_fwversion(struct lbs_private *priv, char *fwversion, int maxlen) -{ - char fwver[32]; - - mutex_lock(&priv->lock); - - sprintf(fwver, "%u.%u.%u.p%u", - priv->fwrelease >> 24 & 0xff, - priv->fwrelease >> 16 & 0xff, - priv->fwrelease >> 8 & 0xff, - priv->fwrelease & 0xff); - - mutex_unlock(&priv->lock); - snprintf(fwversion, maxlen, fwver); -} - - /* * iwconfig settable callbacks */ diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index a563d9a231b..4c08db49760 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -4,19 +4,6 @@ #ifndef _LBS_WEXT_H_ #define _LBS_WEXT_H_ -/** lbs_ioctl_regrdwr */ -struct lbs_ioctl_regrdwr { - /** Which register to access */ - u16 whichreg; - /** Read or Write */ - u16 action; - u32 offset; - u16 NOB; - u32 value; -}; - -#define LBS_MONITOR_OFF 0 - extern struct iw_handler_def lbs_handler_def; extern struct iw_handler_def mesh_handler_def; diff --git a/drivers/net/wireless/net2280.h b/drivers/net/wireless/net2280.h deleted file mode 100644 index 120eb831b28..00000000000 --- a/drivers/net/wireless/net2280.h +++ /dev/null @@ -1,452 +0,0 @@ -#ifndef NET2280_H -#define NET2280_H -/* - * NetChip 2280 high/full speed USB device controller. - * Unlike many such controllers, this one talks PCI. - */ - -/* - * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) - * Copyright (C) 2003 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/*-------------------------------------------------------------------------*/ - -/* NET2280 MEMORY MAPPED REGISTERS - * - * The register layout came from the chip documentation, and the bit - * number definitions were extracted from chip specification. - * - * Use the shift operator ('<<') to build bit masks, with readl/writel - * to access the registers through PCI. - */ - -/* main registers, BAR0 + 0x0000 */ -struct net2280_regs { - // offset 0x0000 - __le32 devinit; -#define LOCAL_CLOCK_FREQUENCY 8 -#define FORCE_PCI_RESET 7 -#define PCI_ID 6 -#define PCI_ENABLE 5 -#define FIFO_SOFT_RESET 4 -#define CFG_SOFT_RESET 3 -#define PCI_SOFT_RESET 2 -#define USB_SOFT_RESET 1 -#define M8051_RESET 0 - __le32 eectl; -#define EEPROM_ADDRESS_WIDTH 23 -#define EEPROM_CHIP_SELECT_ACTIVE 22 -#define EEPROM_PRESENT 21 -#define EEPROM_VALID 20 -#define EEPROM_BUSY 19 -#define EEPROM_CHIP_SELECT_ENABLE 18 -#define EEPROM_BYTE_READ_START 17 -#define EEPROM_BYTE_WRITE_START 16 -#define EEPROM_READ_DATA 8 -#define EEPROM_WRITE_DATA 0 - __le32 eeclkfreq; - u32 _unused0; - // offset 0x0010 - - __le32 pciirqenb0; /* interrupt PCI master ... */ -#define SETUP_PACKET_INTERRUPT_ENABLE 7 -#define ENDPOINT_F_INTERRUPT_ENABLE 6 -#define ENDPOINT_E_INTERRUPT_ENABLE 5 -#define ENDPOINT_D_INTERRUPT_ENABLE 4 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 - __le32 pciirqenb1; -#define PCI_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - __le32 cpu_irqenb0; /* ... or onboard 8051 */ -#define SETUP_PACKET_INTERRUPT_ENABLE 7 -#define ENDPOINT_F_INTERRUPT_ENABLE 6 -#define ENDPOINT_E_INTERRUPT_ENABLE 5 -#define ENDPOINT_D_INTERRUPT_ENABLE 4 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 - __le32 cpu_irqenb1; -#define CPU_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_INTA_INTERRUPT_ENABLE 24 -#define PCI_PME_INTERRUPT_ENABLE 23 -#define PCI_SERR_INTERRUPT_ENABLE 22 -#define PCI_PERR_INTERRUPT_ENABLE 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - - // offset 0x0020 - u32 _unused1; - __le32 usbirqenb1; -#define USB_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_INTA_INTERRUPT_ENABLE 24 -#define PCI_PME_INTERRUPT_ENABLE 23 -#define PCI_SERR_INTERRUPT_ENABLE 22 -#define PCI_PERR_INTERRUPT_ENABLE 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - __le32 irqstat0; -#define INTA_ASSERTED 12 -#define SETUP_PACKET_INTERRUPT 7 -#define ENDPOINT_F_INTERRUPT 6 -#define ENDPOINT_E_INTERRUPT 5 -#define ENDPOINT_D_INTERRUPT 4 -#define ENDPOINT_C_INTERRUPT 3 -#define ENDPOINT_B_INTERRUPT 2 -#define ENDPOINT_A_INTERRUPT 1 -#define ENDPOINT_0_INTERRUPT 0 - __le32 irqstat1; -#define POWER_STATE_CHANGE_INTERRUPT 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 -#define PCI_PARITY_ERROR_INTERRUPT 25 -#define PCI_INTA_INTERRUPT 24 -#define PCI_PME_INTERRUPT 23 -#define PCI_SERR_INTERRUPT 22 -#define PCI_PERR_INTERRUPT 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 -#define PCI_RETRY_ABORT_INTERRUPT 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 -#define GPIO_INTERRUPT 13 -#define DMA_D_INTERRUPT 12 -#define DMA_C_INTERRUPT 11 -#define DMA_B_INTERRUPT 10 -#define DMA_A_INTERRUPT 9 -#define EEPROM_DONE_INTERRUPT 8 -#define VBUS_INTERRUPT 7 -#define CONTROL_STATUS_INTERRUPT 6 -#define ROOT_PORT_RESET_INTERRUPT 4 -#define SUSPEND_REQUEST_INTERRUPT 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 -#define RESUME_INTERRUPT 1 -#define SOF_INTERRUPT 0 - // offset 0x0030 - __le32 idxaddr; - __le32 idxdata; - __le32 fifoctl; -#define PCI_BASE2_RANGE 16 -#define IGNORE_FIFO_AVAILABILITY 3 -#define PCI_BASE2_SELECT 2 -#define FIFO_CONFIGURATION_SELECT 0 - u32 _unused2; - // offset 0x0040 - __le32 memaddr; -#define START 28 -#define DIRECTION 27 -#define FIFO_DIAGNOSTIC_SELECT 24 -#define MEMORY_ADDRESS 0 - __le32 memdata0; - __le32 memdata1; - u32 _unused3; - // offset 0x0050 - __le32 gpioctl; -#define GPIO3_LED_SELECT 12 -#define GPIO3_INTERRUPT_ENABLE 11 -#define GPIO2_INTERRUPT_ENABLE 10 -#define GPIO1_INTERRUPT_ENABLE 9 -#define GPIO0_INTERRUPT_ENABLE 8 -#define GPIO3_OUTPUT_ENABLE 7 -#define GPIO2_OUTPUT_ENABLE 6 -#define GPIO1_OUTPUT_ENABLE 5 -#define GPIO0_OUTPUT_ENABLE 4 -#define GPIO3_DATA 3 -#define GPIO2_DATA 2 -#define GPIO1_DATA 1 -#define GPIO0_DATA 0 - __le32 gpiostat; -#define GPIO3_INTERRUPT 3 -#define GPIO2_INTERRUPT 2 -#define GPIO1_INTERRUPT 1 -#define GPIO0_INTERRUPT 0 -} __attribute__ ((packed)); - -/* usb control, BAR0 + 0x0080 */ -struct net2280_usb_regs { - // offset 0x0080 - __le32 stdrsp; -#define STALL_UNSUPPORTED_REQUESTS 31 -#define SET_TEST_MODE 16 -#define GET_OTHER_SPEED_CONFIGURATION 15 -#define GET_DEVICE_QUALIFIER 14 -#define SET_ADDRESS 13 -#define ENDPOINT_SET_CLEAR_HALT 12 -#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 -#define GET_STRING_DESCRIPTOR_2 10 -#define GET_STRING_DESCRIPTOR_1 9 -#define GET_STRING_DESCRIPTOR_0 8 -#define GET_SET_INTERFACE 6 -#define GET_SET_CONFIGURATION 5 -#define GET_CONFIGURATION_DESCRIPTOR 4 -#define GET_DEVICE_DESCRIPTOR 3 -#define GET_ENDPOINT_STATUS 2 -#define GET_INTERFACE_STATUS 1 -#define GET_DEVICE_STATUS 0 - __le32 prodvendid; -#define PRODUCT_ID 16 -#define VENDOR_ID 0 - __le32 relnum; - __le32 usbctl; -#define SERIAL_NUMBER_INDEX 16 -#define PRODUCT_ID_STRING_ENABLE 13 -#define VENDOR_ID_STRING_ENABLE 12 -#define USB_ROOT_PORT_WAKEUP_ENABLE 11 -#define VBUS_PIN 10 -#define TIMED_DISCONNECT 9 -#define SUSPEND_IMMEDIATELY 7 -#define SELF_POWERED_USB_DEVICE 6 -#define REMOTE_WAKEUP_SUPPORT 5 -#define PME_POLARITY 4 -#define USB_DETECT_ENABLE 3 -#define PME_WAKEUP_ENABLE 2 -#define DEVICE_REMOTE_WAKEUP_ENABLE 1 -#define SELF_POWERED_STATUS 0 - // offset 0x0090 - __le32 usbstat; -#define HIGH_SPEED 7 -#define FULL_SPEED 6 -#define GENERATE_RESUME 5 -#define GENERATE_DEVICE_REMOTE_WAKEUP 4 - __le32 xcvrdiag; -#define FORCE_HIGH_SPEED_MODE 31 -#define FORCE_FULL_SPEED_MODE 30 -#define USB_TEST_MODE 24 -#define LINE_STATE 16 -#define TRANSCEIVER_OPERATION_MODE 2 -#define TRANSCEIVER_SELECT 1 -#define TERMINATION_SELECT 0 - __le32 setup0123; - __le32 setup4567; - // offset 0x0090 - u32 _unused0; - __le32 ouraddr; -#define FORCE_IMMEDIATE 7 -#define OUR_USB_ADDRESS 0 - __le32 ourconfig; -} __attribute__ ((packed)); - -/* pci control, BAR0 + 0x0100 */ -struct net2280_pci_regs { - // offset 0x0100 - __le32 pcimstctl; -#define PCI_ARBITER_PARK_SELECT 13 -#define PCI_MULTI LEVEL_ARBITER 12 -#define PCI_RETRY_ABORT_ENABLE 11 -#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 -#define DMA_READ_MULTIPLE_ENABLE 9 -#define DMA_READ_LINE_ENABLE 8 -#define PCI_MASTER_COMMAND_SELECT 6 -#define MEM_READ_OR_WRITE 0 -#define IO_READ_OR_WRITE 1 -#define CFG_READ_OR_WRITE 2 -#define PCI_MASTER_START 5 -#define PCI_MASTER_READ_WRITE 4 -#define PCI_MASTER_WRITE 0 -#define PCI_MASTER_READ 1 -#define PCI_MASTER_BYTE_WRITE_ENABLES 0 - __le32 pcimstaddr; - __le32 pcimstdata; - __le32 pcimststat; -#define PCI_ARBITER_CLEAR 2 -#define PCI_EXTERNAL_ARBITER 1 -#define PCI_HOST_MODE 0 -} __attribute__ ((packed)); - -/* dma control, BAR0 + 0x0180 ... array of four structs like this, - * for channels 0..3. see also struct net2280_dma: descriptor - * that can be loaded into some of these registers. - */ -struct net2280_dma_regs { /* [11.7] */ - // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, - __le32 dmactl; -#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 -#define DMA_CLEAR_COUNT_ENABLE 21 -#define DESCRIPTOR_POLLING_RATE 19 -#define POLL_CONTINUOUS 0 -#define POLL_1_USEC 1 -#define POLL_100_USEC 2 -#define POLL_1_MSEC 3 -#define DMA_VALID_BIT_POLLING_ENABLE 18 -#define DMA_VALID_BIT_ENABLE 17 -#define DMA_SCATTER_GATHER_ENABLE 16 -#define DMA_OUT_AUTO_START_ENABLE 4 -#define DMA_PREEMPT_ENABLE 3 -#define DMA_FIFO_VALIDATE 2 -#define DMA_ENABLE 1 -#define DMA_ADDRESS_HOLD 0 - __le32 dmastat; -#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 -#define DMA_TRANSACTION_DONE_INTERRUPT 24 -#define DMA_ABORT 1 -#define DMA_START 0 - u32 _unused0[2]; - // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, - __le32 dmacount; -#define VALID_BIT 31 -#define DMA_DIRECTION 30 -#define DMA_DONE_INTERRUPT_ENABLE 29 -#define END_OF_CHAIN 28 -#define DMA_BYTE_COUNT_MASK ((1<<24)-1) -#define DMA_BYTE_COUNT 0 - __le32 dmaaddr; - __le32 dmadesc; - u32 _unused1; -} __attribute__ ((packed)); - -/* dedicated endpoint registers, BAR0 + 0x0200 */ - -struct net2280_dep_regs { /* [11.8] */ - // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 - __le32 dep_cfg; - // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 - __le32 dep_rsp; - u32 _unused[2]; -} __attribute__ ((packed)); - -/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs - * like this, for ep0 then the configurable endpoints A..F - * ep0 reserved for control; E and F have only 64 bytes of fifo - */ -struct net2280_ep_regs { /* [11.9] */ - // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 - __le32 ep_cfg; -#define ENDPOINT_BYTE_COUNT 16 -#define ENDPOINT_ENABLE 10 -#define ENDPOINT_TYPE 8 -#define ENDPOINT_DIRECTION 7 -#define ENDPOINT_NUMBER 0 - __le32 ep_rsp; -#define SET_NAK_OUT_PACKETS 15 -#define SET_EP_HIDE_STATUS_PHASE 14 -#define SET_EP_FORCE_CRC_ERROR 13 -#define SET_INTERRUPT_MODE 12 -#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 -#define SET_NAK_OUT_PACKETS_MODE 10 -#define SET_ENDPOINT_TOGGLE 9 -#define SET_ENDPOINT_HALT 8 -#define CLEAR_NAK_OUT_PACKETS 7 -#define CLEAR_EP_HIDE_STATUS_PHASE 6 -#define CLEAR_EP_FORCE_CRC_ERROR 5 -#define CLEAR_INTERRUPT_MODE 4 -#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 -#define CLEAR_NAK_OUT_PACKETS_MODE 2 -#define CLEAR_ENDPOINT_TOGGLE 1 -#define CLEAR_ENDPOINT_HALT 0 - __le32 ep_irqenb; -#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 -#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 -#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 -#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 -#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 - __le32 ep_stat; -#define FIFO_VALID_COUNT 24 -#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 -#define TIMEOUT 21 -#define USB_STALL_SENT 20 -#define USB_IN_NAK_SENT 19 -#define USB_IN_ACK_RCVD 18 -#define USB_OUT_PING_NAK_SENT 17 -#define USB_OUT_ACK_SENT 16 -#define FIFO_OVERFLOW 13 -#define FIFO_UNDERFLOW 12 -#define FIFO_FULL 11 -#define FIFO_EMPTY 10 -#define FIFO_FLUSH 9 -#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 -#define NAK_OUT_PACKETS 4 -#define DATA_PACKET_RECEIVED_INTERRUPT 3 -#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 -#define DATA_OUT_PING_TOKEN_INTERRUPT 1 -#define DATA_IN_TOKEN_INTERRUPT 0 - // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 - __le32 ep_avail; - __le32 ep_data; - u32 _unused0[2]; -} __attribute__ ((packed)); - -struct net2280_reg_write { - __le16 port; - __le32 addr; - __le32 val; -} __attribute__ ((packed)); - -struct net2280_reg_read { - __le16 port; - __le32 addr; -} __attribute__ ((packed)); -#endif /* NET2280_H */ diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig new file mode 100644 index 00000000000..d3469d08f96 --- /dev/null +++ b/drivers/net/wireless/p54/Kconfig @@ -0,0 +1,63 @@ +config P54_COMMON + tristate "Softmac Prism54 support" + depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL + ---help--- + This is common code for isl38xx based cards. + This module does nothing by itself - the USB/PCI frontends + also need to be enabled in order to support any devices. + + These devices require softmac firmware which can be found at + http://prism54.org/ + + If you choose to build a module, it'll be called p54common. + +config P54_USB + tristate "Prism54 USB support" + depends on P54_COMMON && USB + select CRC32 + ---help--- + This driver is for USB isl38xx based wireless cards. + These are USB based adapters found in devices such as: + + 3COM 3CRWE254G72 + SMC 2862W-G + Accton 802.11g WN4501 USB + Siemens Gigaset USB + Netgear WG121 + Netgear WG111 + Medion 40900, Roper Europe + Shuttle PN15, Airvast WM168g, IOGear GWU513 + Linksys WUSB54G + Linksys WUSB54G Portable + DLink DWL-G120 Spinnaker + DLink DWL-G122 + Belkin F5D7050 ver 1000 + Cohiba Proto board + SMC 2862W-G version 2 + U.S. Robotics U5 802.11g Adapter + FUJITSU E-5400 USB D1700 + Sagem XG703A + DLink DWL-G120 Cohiba + Spinnaker Proto board + Linksys WUSB54AG + Inventel UR054G + Spinnaker DUT + + These devices require softmac firmware which can be found at + http://prism54.org/ + + If you choose to build a module, it'll be called p54usb. + +config P54_PCI + tristate "Prism54 PCI support" + depends on P54_COMMON && PCI + ---help--- + This driver is for PCI isl38xx based wireless cards. + This driver supports most devices that are supported by the + fullmac prism54 driver plus many devices which are not + supported by the fullmac driver/firmware. + + This driver requires softmac firmware which can be found at + http://prism54.org/ + + If you choose to build a module, it'll be called p54pci. diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile new file mode 100644 index 00000000000..4fa9ce71736 --- /dev/null +++ b/drivers/net/wireless/p54/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_P54_COMMON) += p54common.o +obj-$(CONFIG_P54_USB) += p54usb.o +obj-$(CONFIG_P54_PCI) += p54pci.o diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h new file mode 100644 index 00000000000..4915d9d5420 --- /dev/null +++ b/drivers/net/wireless/p54/net2280.h @@ -0,0 +1,452 @@ +#ifndef NET2280_H +#define NET2280_H +/* + * NetChip 2280 high/full speed USB device controller. + * Unlike many such controllers, this one talks PCI. + */ + +/* + * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*-------------------------------------------------------------------------*/ + +/* NET2280 MEMORY MAPPED REGISTERS + * + * The register layout came from the chip documentation, and the bit + * number definitions were extracted from chip specification. + * + * Use the shift operator ('<<') to build bit masks, with readl/writel + * to access the registers through PCI. + */ + +/* main registers, BAR0 + 0x0000 */ +struct net2280_regs { + /* offset 0x0000 */ + __le32 devinit; +#define LOCAL_CLOCK_FREQUENCY 8 +#define FORCE_PCI_RESET 7 +#define PCI_ID 6 +#define PCI_ENABLE 5 +#define FIFO_SOFT_RESET 4 +#define CFG_SOFT_RESET 3 +#define PCI_SOFT_RESET 2 +#define USB_SOFT_RESET 1 +#define M8051_RESET 0 + __le32 eectl; +#define EEPROM_ADDRESS_WIDTH 23 +#define EEPROM_CHIP_SELECT_ACTIVE 22 +#define EEPROM_PRESENT 21 +#define EEPROM_VALID 20 +#define EEPROM_BUSY 19 +#define EEPROM_CHIP_SELECT_ENABLE 18 +#define EEPROM_BYTE_READ_START 17 +#define EEPROM_BYTE_WRITE_START 16 +#define EEPROM_READ_DATA 8 +#define EEPROM_WRITE_DATA 0 + __le32 eeclkfreq; + u32 _unused0; + /* offset 0x0010 */ + + __le32 pciirqenb0; /* interrupt PCI master ... */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + __le32 pciirqenb1; +#define PCI_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + __le32 cpu_irqenb0; /* ... or onboard 8051 */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + __le32 cpu_irqenb1; +#define CPU_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + + /* offset 0x0020 */ + u32 _unused1; + __le32 usbirqenb1; +#define USB_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + __le32 irqstat0; +#define INTA_ASSERTED 12 +#define SETUP_PACKET_INTERRUPT 7 +#define ENDPOINT_F_INTERRUPT 6 +#define ENDPOINT_E_INTERRUPT 5 +#define ENDPOINT_D_INTERRUPT 4 +#define ENDPOINT_C_INTERRUPT 3 +#define ENDPOINT_B_INTERRUPT 2 +#define ENDPOINT_A_INTERRUPT 1 +#define ENDPOINT_0_INTERRUPT 0 + __le32 irqstat1; +#define POWER_STATE_CHANGE_INTERRUPT 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 +#define PCI_PARITY_ERROR_INTERRUPT 25 +#define PCI_INTA_INTERRUPT 24 +#define PCI_PME_INTERRUPT 23 +#define PCI_SERR_INTERRUPT 22 +#define PCI_PERR_INTERRUPT 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 +#define PCI_RETRY_ABORT_INTERRUPT 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 +#define GPIO_INTERRUPT 13 +#define DMA_D_INTERRUPT 12 +#define DMA_C_INTERRUPT 11 +#define DMA_B_INTERRUPT 10 +#define DMA_A_INTERRUPT 9 +#define EEPROM_DONE_INTERRUPT 8 +#define VBUS_INTERRUPT 7 +#define CONTROL_STATUS_INTERRUPT 6 +#define ROOT_PORT_RESET_INTERRUPT 4 +#define SUSPEND_REQUEST_INTERRUPT 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 +#define RESUME_INTERRUPT 1 +#define SOF_INTERRUPT 0 + /* offset 0x0030 */ + __le32 idxaddr; + __le32 idxdata; + __le32 fifoctl; +#define PCI_BASE2_RANGE 16 +#define IGNORE_FIFO_AVAILABILITY 3 +#define PCI_BASE2_SELECT 2 +#define FIFO_CONFIGURATION_SELECT 0 + u32 _unused2; + /* offset 0x0040 */ + __le32 memaddr; +#define START 28 +#define DIRECTION 27 +#define FIFO_DIAGNOSTIC_SELECT 24 +#define MEMORY_ADDRESS 0 + __le32 memdata0; + __le32 memdata1; + u32 _unused3; + /* offset 0x0050 */ + __le32 gpioctl; +#define GPIO3_LED_SELECT 12 +#define GPIO3_INTERRUPT_ENABLE 11 +#define GPIO2_INTERRUPT_ENABLE 10 +#define GPIO1_INTERRUPT_ENABLE 9 +#define GPIO0_INTERRUPT_ENABLE 8 +#define GPIO3_OUTPUT_ENABLE 7 +#define GPIO2_OUTPUT_ENABLE 6 +#define GPIO1_OUTPUT_ENABLE 5 +#define GPIO0_OUTPUT_ENABLE 4 +#define GPIO3_DATA 3 +#define GPIO2_DATA 2 +#define GPIO1_DATA 1 +#define GPIO0_DATA 0 + __le32 gpiostat; +#define GPIO3_INTERRUPT 3 +#define GPIO2_INTERRUPT 2 +#define GPIO1_INTERRUPT 1 +#define GPIO0_INTERRUPT 0 +} __attribute__ ((packed)); + +/* usb control, BAR0 + 0x0080 */ +struct net2280_usb_regs { + /* offset 0x0080 */ + __le32 stdrsp; +#define STALL_UNSUPPORTED_REQUESTS 31 +#define SET_TEST_MODE 16 +#define GET_OTHER_SPEED_CONFIGURATION 15 +#define GET_DEVICE_QUALIFIER 14 +#define SET_ADDRESS 13 +#define ENDPOINT_SET_CLEAR_HALT 12 +#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 +#define GET_STRING_DESCRIPTOR_2 10 +#define GET_STRING_DESCRIPTOR_1 9 +#define GET_STRING_DESCRIPTOR_0 8 +#define GET_SET_INTERFACE 6 +#define GET_SET_CONFIGURATION 5 +#define GET_CONFIGURATION_DESCRIPTOR 4 +#define GET_DEVICE_DESCRIPTOR 3 +#define GET_ENDPOINT_STATUS 2 +#define GET_INTERFACE_STATUS 1 +#define GET_DEVICE_STATUS 0 + __le32 prodvendid; +#define PRODUCT_ID 16 +#define VENDOR_ID 0 + __le32 relnum; + __le32 usbctl; +#define SERIAL_NUMBER_INDEX 16 +#define PRODUCT_ID_STRING_ENABLE 13 +#define VENDOR_ID_STRING_ENABLE 12 +#define USB_ROOT_PORT_WAKEUP_ENABLE 11 +#define VBUS_PIN 10 +#define TIMED_DISCONNECT 9 +#define SUSPEND_IMMEDIATELY 7 +#define SELF_POWERED_USB_DEVICE 6 +#define REMOTE_WAKEUP_SUPPORT 5 +#define PME_POLARITY 4 +#define USB_DETECT_ENABLE 3 +#define PME_WAKEUP_ENABLE 2 +#define DEVICE_REMOTE_WAKEUP_ENABLE 1 +#define SELF_POWERED_STATUS 0 + /* offset 0x0090 */ + __le32 usbstat; +#define HIGH_SPEED 7 +#define FULL_SPEED 6 +#define GENERATE_RESUME 5 +#define GENERATE_DEVICE_REMOTE_WAKEUP 4 + __le32 xcvrdiag; +#define FORCE_HIGH_SPEED_MODE 31 +#define FORCE_FULL_SPEED_MODE 30 +#define USB_TEST_MODE 24 +#define LINE_STATE 16 +#define TRANSCEIVER_OPERATION_MODE 2 +#define TRANSCEIVER_SELECT 1 +#define TERMINATION_SELECT 0 + __le32 setup0123; + __le32 setup4567; + /* offset 0x0090 */ + u32 _unused0; + __le32 ouraddr; +#define FORCE_IMMEDIATE 7 +#define OUR_USB_ADDRESS 0 + __le32 ourconfig; +} __attribute__ ((packed)); + +/* pci control, BAR0 + 0x0100 */ +struct net2280_pci_regs { + /* offset 0x0100 */ + __le32 pcimstctl; +#define PCI_ARBITER_PARK_SELECT 13 +#define PCI_MULTI LEVEL_ARBITER 12 +#define PCI_RETRY_ABORT_ENABLE 11 +#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 +#define DMA_READ_MULTIPLE_ENABLE 9 +#define DMA_READ_LINE_ENABLE 8 +#define PCI_MASTER_COMMAND_SELECT 6 +#define MEM_READ_OR_WRITE 0 +#define IO_READ_OR_WRITE 1 +#define CFG_READ_OR_WRITE 2 +#define PCI_MASTER_START 5 +#define PCI_MASTER_READ_WRITE 4 +#define PCI_MASTER_WRITE 0 +#define PCI_MASTER_READ 1 +#define PCI_MASTER_BYTE_WRITE_ENABLES 0 + __le32 pcimstaddr; + __le32 pcimstdata; + __le32 pcimststat; +#define PCI_ARBITER_CLEAR 2 +#define PCI_EXTERNAL_ARBITER 1 +#define PCI_HOST_MODE 0 +} __attribute__ ((packed)); + +/* dma control, BAR0 + 0x0180 ... array of four structs like this, + * for channels 0..3. see also struct net2280_dma: descriptor + * that can be loaded into some of these registers. + */ +struct net2280_dma_regs { /* [11.7] */ + /* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */ + __le32 dmactl; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 +#define DMA_CLEAR_COUNT_ENABLE 21 +#define DESCRIPTOR_POLLING_RATE 19 +#define POLL_CONTINUOUS 0 +#define POLL_1_USEC 1 +#define POLL_100_USEC 2 +#define POLL_1_MSEC 3 +#define DMA_VALID_BIT_POLLING_ENABLE 18 +#define DMA_VALID_BIT_ENABLE 17 +#define DMA_SCATTER_GATHER_ENABLE 16 +#define DMA_OUT_AUTO_START_ENABLE 4 +#define DMA_PREEMPT_ENABLE 3 +#define DMA_FIFO_VALIDATE 2 +#define DMA_ENABLE 1 +#define DMA_ADDRESS_HOLD 0 + __le32 dmastat; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 +#define DMA_TRANSACTION_DONE_INTERRUPT 24 +#define DMA_ABORT 1 +#define DMA_START 0 + u32 _unused0[2]; + /* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */ + __le32 dmacount; +#define VALID_BIT 31 +#define DMA_DIRECTION 30 +#define DMA_DONE_INTERRUPT_ENABLE 29 +#define END_OF_CHAIN 28 +#define DMA_BYTE_COUNT_MASK ((1<<24)-1) +#define DMA_BYTE_COUNT 0 + __le32 dmaaddr; + __le32 dmadesc; + u32 _unused1; +} __attribute__ ((packed)); + +/* dedicated endpoint registers, BAR0 + 0x0200 */ + +struct net2280_dep_regs { /* [11.8] */ + /* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */ + __le32 dep_cfg; + /* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */ + __le32 dep_rsp; + u32 _unused[2]; +} __attribute__ ((packed)); + +/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs + * like this, for ep0 then the configurable endpoints A..F + * ep0 reserved for control; E and F have only 64 bytes of fifo + */ +struct net2280_ep_regs { /* [11.9] */ + /* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */ + __le32 ep_cfg; +#define ENDPOINT_BYTE_COUNT 16 +#define ENDPOINT_ENABLE 10 +#define ENDPOINT_TYPE 8 +#define ENDPOINT_DIRECTION 7 +#define ENDPOINT_NUMBER 0 + __le32 ep_rsp; +#define SET_NAK_OUT_PACKETS 15 +#define SET_EP_HIDE_STATUS_PHASE 14 +#define SET_EP_FORCE_CRC_ERROR 13 +#define SET_INTERRUPT_MODE 12 +#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 +#define SET_NAK_OUT_PACKETS_MODE 10 +#define SET_ENDPOINT_TOGGLE 9 +#define SET_ENDPOINT_HALT 8 +#define CLEAR_NAK_OUT_PACKETS 7 +#define CLEAR_EP_HIDE_STATUS_PHASE 6 +#define CLEAR_EP_FORCE_CRC_ERROR 5 +#define CLEAR_INTERRUPT_MODE 4 +#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 +#define CLEAR_NAK_OUT_PACKETS_MODE 2 +#define CLEAR_ENDPOINT_TOGGLE 1 +#define CLEAR_ENDPOINT_HALT 0 + __le32 ep_irqenb; +#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 +#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 +#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 + __le32 ep_stat; +#define FIFO_VALID_COUNT 24 +#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 +#define TIMEOUT 21 +#define USB_STALL_SENT 20 +#define USB_IN_NAK_SENT 19 +#define USB_IN_ACK_RCVD 18 +#define USB_OUT_PING_NAK_SENT 17 +#define USB_OUT_ACK_SENT 16 +#define FIFO_OVERFLOW 13 +#define FIFO_UNDERFLOW 12 +#define FIFO_FULL 11 +#define FIFO_EMPTY 10 +#define FIFO_FLUSH 9 +#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 +#define NAK_OUT_PACKETS 4 +#define DATA_PACKET_RECEIVED_INTERRUPT 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT 1 +#define DATA_IN_TOKEN_INTERRUPT 0 + /* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */ + __le32 ep_avail; + __le32 ep_data; + u32 _unused0[2]; +} __attribute__ ((packed)); + +struct net2280_reg_write { + __le16 port; + __le32 addr; + __le32 val; +} __attribute__ ((packed)); + +struct net2280_reg_read { + __le16 port; + __le32 addr; +} __attribute__ ((packed)); +#endif /* NET2280_H */ diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54/p54.h index 744c866066c..06d2c67f4c8 100644 --- a/drivers/net/wireless/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -64,10 +64,6 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - /* FIXME: this channels/modes/rates stuff sucks */ - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; struct ieee80211_tx_queue_stats tx_stats; }; diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54/p54common.c index d191e055a78..63f9badf3f5 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -27,6 +27,46 @@ MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54common"); +static struct ieee80211_rate p54_rates[] = { + { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_channels[] = { + { .center_freq = 2412, .hw_value = 1, }, + { .center_freq = 2417, .hw_value = 2, }, + { .center_freq = 2422, .hw_value = 3, }, + { .center_freq = 2427, .hw_value = 4, }, + { .center_freq = 2432, .hw_value = 5, }, + { .center_freq = 2437, .hw_value = 6, }, + { .center_freq = 2442, .hw_value = 7, }, + { .center_freq = 2447, .hw_value = 8, }, + { .center_freq = 2452, .hw_value = 9, }, + { .center_freq = 2457, .hw_value = 10, }, + { .center_freq = 2462, .hw_value = 11, }, + { .center_freq = 2467, .hw_value = 12, }, + { .center_freq = 2472, .hw_value = 13, }, + { .center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band band_2GHz = { + .channels = p54_channels, + .n_channels = ARRAY_SIZE(p54_channels), + .bitrates = p54_rates, + .n_bitrates = ARRAY_SIZE(p54_rates), +}; + + void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) { struct p54_common *priv = dev->priv; @@ -257,6 +297,10 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) /* make it overrun */ entry_len = len; break; + default: + printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", + le16_to_cpu(entry->code)); + break; } entry = (void *)entry + (entry_len + 1)*2; @@ -312,10 +356,10 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) u16 freq = le16_to_cpu(hdr->freq); rx_status.ssi = hdr->rssi; - rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */ - rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5; + /* XX correct? */ + rx_status.rate_idx = hdr->rate & 0xf; rx_status.freq = freq; - rx_status.phymode = MODE_IEEE80211G; + rx_status.band = IEEE80211_BAND_2GHZ; rx_status.antenna = hdr->antenna; rx_status.mactime = le64_to_cpu(hdr->timestamp); rx_status.flag |= RX_FLAG_TSFT; @@ -353,7 +397,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) while (entry != (struct sk_buff *)&priv->tx_queue) { range = (struct memrecord *)&entry->cb; if (range->start_addr == addr) { - struct ieee80211_tx_status status = {{0}}; + struct ieee80211_tx_status status; struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; int pad = 0; @@ -369,6 +413,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) kfree_skb(entry); break; } + memset(&status, 0, sizeof(status)); memcpy(&status.control, range->control, sizeof(status.control)); kfree(range->control); @@ -551,7 +596,9 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = control->tx_rate; + rate = control->tx_rate->hw_value; + if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + rate |= 0x10; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) rate |= 0x40; else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) @@ -721,13 +768,12 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) return 0; } -#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \ +#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \ do { \ queue.aifs = cpu_to_le16(ai_fs); \ queue.cwmin = cpu_to_le16(cw_min); \ queue.cwmax = cpu_to_le16(cw_max); \ - queue.txop = (burst == 0) ? \ - 0 : cpu_to_le16((burst * 100) / 32 + 1); \ + queue.txop = cpu_to_le16(_txop); \ } while(0) static void p54_init_vdcf(struct ieee80211_hw *dev) @@ -745,10 +791,10 @@ static void p54_init_vdcf(struct ieee80211_hw *dev) vdcf = (struct p54_tx_control_vdcf *) hdr->data; - P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f); - P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e); - P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014); - P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000); + P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0); } static void p54_set_vdcf(struct ieee80211_hw *dev) @@ -853,7 +899,7 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { int ret; - ret = p54_set_freq(dev, cpu_to_le16(conf->freq)); + ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); return ret; } @@ -901,7 +947,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, int queue, if ((params) && !((queue < 0) || (queue > 4))) { P54_SET_QUEUE(vdcf->queue[queue], params->aifs, - params->cw_min, params->cw_max, params->burst_time); + params->cw_min, params->cw_max, params->txop); } else return -EINVAL; @@ -948,7 +994,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) { struct ieee80211_hw *dev; struct p54_common *priv; - int i; dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); if (!dev) @@ -957,18 +1002,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_INVALID; skb_queue_head_init(&priv->tx_queue); - memcpy(priv->channels, p54_channels, sizeof(p54_channels)); - memcpy(priv->rates, p54_rates, sizeof(p54_rates)); - priv->modes[1].mode = MODE_IEEE80211B; - priv->modes[1].num_rates = 4; - priv->modes[1].rates = priv->rates; - priv->modes[1].num_channels = ARRAY_SIZE(p54_channels); - priv->modes[1].channels = priv->channels; - priv->modes[0].mode = MODE_IEEE80211G; - priv->modes[0].num_rates = ARRAY_SIZE(p54_rates); - priv->modes[0].rates = priv->rates; - priv->modes[0].num_channels = ARRAY_SIZE(p54_channels); - priv->modes[0].channels = priv->channels; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS; dev->channel_change_time = 1000; /* TODO: find actual value */ @@ -990,14 +1024,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) p54_init_vdcf(dev); - for (i = 0; i < 2; i++) { - if (ieee80211_register_hwmode(dev, &priv->modes[i])) { - kfree(priv->cached_vdcf); - ieee80211_free_hw(dev); - return NULL; - } - } - return dev; } EXPORT_SYMBOL_GPL(p54_init_common); diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54/p54common.h index b67ff34e26f..c15b56e1d75 100644 --- a/drivers/net/wireless/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -251,79 +251,4 @@ struct p54_tx_control_vdcf { __le16 frameburst; } __attribute__ ((packed)); -static const struct ieee80211_rate p54_rates[] = { - { .rate = 10, - .val = 0, - .val2 = 0x10, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 20, - .val = 1, - .val2 = 0x11, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 55, - .val = 2, - .val2 = 0x12, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 110, - .val = 3, - .val2 = 0x13, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 60, - .val = 4, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 90, - .val = 5, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 120, - .val = 6, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 180, - .val = 7, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 240, - .val = 8, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 360, - .val = 9, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 480, - .val = 10, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 540, - .val = 11, - .flags = IEEE80211_RATE_OFDM }, -}; - -// TODO: just generate this.. -static const struct ieee80211_channel p54_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484} -}; - #endif /* PRISM54COMMON_H */ diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54/p54pci.c index fa527723fbe..fa527723fbe 100644 --- a/drivers/net/wireless/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 5bedd7af385..5bedd7af385 100644 --- a/drivers/net/wireless/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 98ddbb3b327..98ddbb3b327 100644 --- a/drivers/net/wireless/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c diff --git a/drivers/net/wireless/p54usb.h b/drivers/net/wireless/p54/p54usb.h index d1896b396c1..d1896b396c1 100644 --- a/drivers/net/wireless/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 1b595a6525f..e5b3c282009 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -165,7 +165,7 @@ prism54_update_stats(struct work_struct *work) struct obj_bss bss, *bss2; union oid_res_t r; - down(&priv->stats_sem); + mutex_lock(&priv->stats_lock); /* Noise floor. * I'm not sure if the unit is dBm. @@ -207,7 +207,7 @@ prism54_update_stats(struct work_struct *work) mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); priv->local_iwstatistics.discard.retries = r.u; - up(&priv->stats_sem); + mutex_unlock(&priv->stats_lock); return; } @@ -218,12 +218,12 @@ prism54_get_wireless_stats(struct net_device *ndev) islpci_private *priv = netdev_priv(ndev); /* If the stats are being updated return old data */ - if (down_trylock(&priv->stats_sem) == 0) { + if (mutex_trylock(&priv->stats_lock)) { memcpy(&priv->iwstatistics, &priv->local_iwstatistics, sizeof (struct iw_statistics)); /* They won't be marked updated for the next time */ priv->local_iwstatistics.qual.updated = 0; - up(&priv->stats_sem); + mutex_unlock(&priv->stats_lock); } else priv->iwstatistics.qual.updated = 0; @@ -1780,7 +1780,7 @@ prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, void prism54_acl_init(struct islpci_acl *acl) { - sema_init(&acl->sem, 1); + mutex_init(&acl->lock); INIT_LIST_HEAD(&acl->mac_list); acl->size = 0; acl->policy = MAC_POLICY_OPEN; @@ -1792,10 +1792,10 @@ prism54_clear_mac(struct islpci_acl *acl) struct list_head *ptr, *next; struct mac_entry *entry; - down(&acl->sem); + mutex_lock(&acl->lock); if (acl->size == 0) { - up(&acl->sem); + mutex_unlock(&acl->lock); return; } @@ -1806,7 +1806,7 @@ prism54_clear_mac(struct islpci_acl *acl) kfree(entry); } acl->size = 0; - up(&acl->sem); + mutex_unlock(&acl->lock); } void @@ -1833,13 +1833,13 @@ prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, memcpy(entry->addr, addr->sa_data, ETH_ALEN); - if (down_interruptible(&acl->sem)) { + if (mutex_lock_interruptible(&acl->lock)) { kfree(entry); return -ERESTARTSYS; } list_add_tail(&entry->_list, &acl->mac_list); acl->size++; - up(&acl->sem); + mutex_unlock(&acl->lock); return 0; } @@ -1856,18 +1856,18 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, if (addr->sa_family != ARPHRD_ETHER) return -EOPNOTSUPP; - if (down_interruptible(&acl->sem)) + if (mutex_lock_interruptible(&acl->lock)) return -ERESTARTSYS; list_for_each_entry(entry, &acl->mac_list, _list) { if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { list_del(&entry->_list); acl->size--; kfree(entry); - up(&acl->sem); + mutex_unlock(&acl->lock); return 0; } } - up(&acl->sem); + mutex_unlock(&acl->lock); return -EINVAL; } @@ -1882,7 +1882,7 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, dwrq->length = 0; - if (down_interruptible(&acl->sem)) + if (mutex_lock_interruptible(&acl->lock)) return -ERESTARTSYS; list_for_each_entry(entry, &acl->mac_list, _list) { @@ -1891,7 +1891,7 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, dwrq->length++; dst++; } - up(&acl->sem); + mutex_unlock(&acl->lock); return 0; } @@ -1955,11 +1955,11 @@ prism54_mac_accept(struct islpci_acl *acl, char *mac) struct mac_entry *entry; int res = 0; - if (down_interruptible(&acl->sem)) + if (mutex_lock_interruptible(&acl->lock)) return -ERESTARTSYS; if (acl->policy == MAC_POLICY_OPEN) { - up(&acl->sem); + mutex_unlock(&acl->lock); return 1; } @@ -1970,7 +1970,7 @@ prism54_mac_accept(struct islpci_acl *acl, char *mac) } } res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; - up(&acl->sem); + mutex_unlock(&acl->lock); return res; } @@ -2081,6 +2081,7 @@ link_changed(struct net_device *ndev, u32 bitrate) islpci_private *priv = netdev_priv(ndev); if (bitrate) { + netif_carrier_on(ndev); if (priv->iw_mode == IW_MODE_INFRA) { union iwreq_data uwrq; prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, @@ -2089,8 +2090,10 @@ link_changed(struct net_device *ndev, u32 bitrate) } else send_simple_event(netdev_priv(ndev), "Link established"); - } else + } else { + netif_carrier_off(ndev); send_simple_event(netdev_priv(ndev), "Link lost"); + } } /* Beacon/ProbeResp payload header */ @@ -2114,7 +2117,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; - down(&priv->wpa_sem); + mutex_lock(&priv->wpa_lock); /* try to use existing entry */ list_for_each(ptr, &priv->bss_wpa_list) { @@ -2165,7 +2168,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, kfree(bss); } - up(&priv->wpa_sem); + mutex_unlock(&priv->wpa_lock); } static size_t @@ -2175,7 +2178,7 @@ prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) struct islpci_bss_wpa_ie *bss = NULL; size_t len = 0; - down(&priv->wpa_sem); + mutex_lock(&priv->wpa_lock); list_for_each(ptr, &priv->bss_wpa_list) { bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); @@ -2187,7 +2190,7 @@ prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) len = bss->wpa_ie_len; memcpy(wpa_ie, bss->wpa_ie, len); } - up(&priv->wpa_sem); + mutex_unlock(&priv->wpa_lock); return len; } @@ -2196,7 +2199,7 @@ void prism54_wpa_bss_ie_init(islpci_private *priv) { INIT_LIST_HEAD(&priv->bss_wpa_list); - sema_init(&priv->wpa_sem, 1); + mutex_init(&priv->wpa_lock); } void diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index dbb538ccb4e..04c2638d75a 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -387,7 +387,9 @@ islpci_open(struct net_device *ndev) } netif_start_queue(ndev); -/* netif_mark_up( ndev ); */ + + /* Turn off carrier unless we know we have associated */ + netif_carrier_off(ndev); return 0; } @@ -864,7 +866,7 @@ islpci_setup(struct pci_dev *pdev) mutex_init(&priv->mgmt_lock); priv->mgmt_received = NULL; init_waitqueue_head(&priv->mgmt_wqueue); - sema_init(&priv->stats_sem, 1); + mutex_init(&priv->stats_lock); spin_lock_init(&priv->slock); /* init state machine with off#1 state */ diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 4e0182ce835..8e55a5fcffa 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -55,7 +55,7 @@ struct islpci_acl { enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; struct list_head mac_list; /* a list of mac_entry */ int size; /* size of queue */ - struct semaphore sem; /* accessed in ioctls and trap_work */ + struct mutex lock; /* accessed in ioctls and trap_work */ }; struct islpci_membuf { @@ -88,7 +88,7 @@ typedef struct { /* Take care of the wireless stats */ struct work_struct stats_work; - struct semaphore stats_sem; + struct mutex stats_lock; /* remember when we last updated the stats */ unsigned long stats_timestamp; /* The first is accessed under semaphore locking. @@ -178,7 +178,7 @@ typedef struct { int wpa; /* WPA mode enabled */ struct list_head bss_wpa_list; int num_bss_wpa; - struct semaphore wpa_sem; + struct mutex wpa_lock; u8 wpa_ie[MAX_WPA_IE_LEN]; size_t wpa_ie_len; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 10b776c1adc..977751f372f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -154,128 +154,121 @@ MODULE_PARM_DESC(workaround_interval, #define NDIS_802_11_LENGTH_RATES 8 #define NDIS_802_11_LENGTH_RATES_EX 16 -struct NDIS_802_11_SSID { - __le32 SsidLength; - u8 Ssid[NDIS_802_11_LENGTH_SSID]; -} __attribute__((packed)); - -enum NDIS_802_11_NETWORK_TYPE { - Ndis802_11FH, - Ndis802_11DS, - Ndis802_11OFDM5, - Ndis802_11OFDM24, - Ndis802_11NetworkTypeMax +enum ndis_80211_net_type { + ndis_80211_type_freq_hop, + ndis_80211_type_direct_seq, + ndis_80211_type_ofdm_a, + ndis_80211_type_ofdm_g }; -struct NDIS_802_11_CONFIGURATION_FH { - __le32 Length; - __le32 HopPattern; - __le32 HopSet; - __le32 DwellTime; -} __attribute__((packed)); - -struct NDIS_802_11_CONFIGURATION { - __le32 Length; - __le32 BeaconPeriod; - __le32 ATIMWindow; - __le32 DSConfig; - struct NDIS_802_11_CONFIGURATION_FH FHConfig; -} __attribute__((packed)); - -enum NDIS_802_11_NETWORK_INFRASTRUCTURE { - Ndis802_11IBSS, - Ndis802_11Infrastructure, - Ndis802_11AutoUnknown, - Ndis802_11InfrastructureMax +enum ndis_80211_net_infra { + ndis_80211_infra_adhoc, + ndis_80211_infra_infra, + ndis_80211_infra_auto_unknown }; -enum NDIS_802_11_AUTHENTICATION_MODE { - Ndis802_11AuthModeOpen, - Ndis802_11AuthModeShared, - Ndis802_11AuthModeAutoSwitch, - Ndis802_11AuthModeWPA, - Ndis802_11AuthModeWPAPSK, - Ndis802_11AuthModeWPANone, - Ndis802_11AuthModeWPA2, - Ndis802_11AuthModeWPA2PSK, - Ndis802_11AuthModeMax +enum ndis_80211_auth_mode { + ndis_80211_auth_open, + ndis_80211_auth_shared, + ndis_80211_auth_auto_switch, + ndis_80211_auth_wpa, + ndis_80211_auth_wpa_psk, + ndis_80211_auth_wpa_none, + ndis_80211_auth_wpa2, + ndis_80211_auth_wpa2_psk }; -enum NDIS_802_11_ENCRYPTION_STATUS { - Ndis802_11WEPEnabled, - Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, - Ndis802_11WEPDisabled, - Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, - Ndis802_11WEPKeyAbsent, - Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, - Ndis802_11WEPNotSupported, - Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, - Ndis802_11Encryption2Enabled, - Ndis802_11Encryption2KeyAbsent, - Ndis802_11Encryption3Enabled, - Ndis802_11Encryption3KeyAbsent +enum ndis_80211_encr_status { + ndis_80211_encr_wep_enabled, + ndis_80211_encr_disabled, + ndis_80211_encr_wep_key_absent, + ndis_80211_encr_not_supported, + ndis_80211_encr_tkip_enabled, + ndis_80211_encr_tkip_key_absent, + ndis_80211_encr_ccmp_enabled, + ndis_80211_encr_ccmp_key_absent }; -enum NDIS_802_11_PRIVACY_FILTER { - Ndis802_11PrivFilterAcceptAll, - Ndis802_11PrivFilter8021xWEP +enum ndis_80211_priv_filter { + ndis_80211_priv_accept_all, + ndis_80211_priv_8021x_wep }; -struct NDIS_WLAN_BSSID_EX { - __le32 Length; - u8 MacAddress[6]; - u8 Padding[2]; - struct NDIS_802_11_SSID Ssid; - __le32 Privacy; - __le32 Rssi; - __le32 NetworkTypeInUse; - struct NDIS_802_11_CONFIGURATION Configuration; - __le32 InfrastructureMode; - u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX]; - __le32 IELength; - u8 IEs[0]; +struct ndis_80211_ssid { + __le32 length; + u8 essid[NDIS_802_11_LENGTH_SSID]; +} __attribute__((packed)); + +struct ndis_80211_conf_freq_hop { + __le32 length; + __le32 hop_pattern; + __le32 hop_set; + __le32 dwell_time; +} __attribute__((packed)); + +struct ndis_80211_conf { + __le32 length; + __le32 beacon_period; + __le32 atim_window; + __le32 ds_config; + struct ndis_80211_conf_freq_hop fh_config; +} __attribute__((packed)); + +struct ndis_80211_bssid_ex { + __le32 length; + u8 mac[6]; + u8 padding[2]; + struct ndis_80211_ssid ssid; + __le32 privacy; + __le32 rssi; + __le32 net_type; + struct ndis_80211_conf config; + __le32 net_infra; + u8 rates[NDIS_802_11_LENGTH_RATES_EX]; + __le32 ie_length; + u8 ies[0]; } __attribute__((packed)); -struct NDIS_802_11_BSSID_LIST_EX { - __le32 NumberOfItems; - struct NDIS_WLAN_BSSID_EX Bssid[0]; +struct ndis_80211_bssid_list_ex { + __le32 num_items; + struct ndis_80211_bssid_ex bssid[0]; } __attribute__((packed)); -struct NDIS_802_11_FIXED_IEs { - u8 Timestamp[8]; - __le16 BeaconInterval; - __le16 Capabilities; +struct ndis_80211_fixed_ies { + u8 timestamp[8]; + __le16 beacon_interval; + __le16 capabilities; } __attribute__((packed)); -struct NDIS_802_11_WEP { - __le32 Length; - __le32 KeyIndex; - __le32 KeyLength; - u8 KeyMaterial[32]; +struct ndis_80211_wep_key { + __le32 size; + __le32 index; + __le32 length; + u8 material[32]; } __attribute__((packed)); -struct NDIS_802_11_KEY { - __le32 Length; - __le32 KeyIndex; - __le32 KeyLength; - u8 Bssid[6]; - u8 Padding[6]; - u8 KeyRSC[8]; - u8 KeyMaterial[32]; +struct ndis_80211_key { + __le32 size; + __le32 index; + __le32 length; + u8 bssid[6]; + u8 padding[6]; + u8 rsc[8]; + u8 material[32]; } __attribute__((packed)); -struct NDIS_802_11_REMOVE_KEY { - __le32 Length; - __le32 KeyIndex; - u8 Bssid[6]; +struct ndis_80211_remove_key { + __le32 size; + __le32 index; + u8 bssid[6]; } __attribute__((packed)); -struct RNDIS_CONFIG_PARAMETER_INFOBUFFER { - __le32 ParameterNameOffset; - __le32 ParameterNameLength; - __le32 ParameterType; - __le32 ParameterValueOffset; - __le32 ParameterValueLength; +struct ndis_config_param { + __le32 name_offs; + __le32 name_length; + __le32 type; + __le32 value_offs; + __le32 value_length; } __attribute__((packed)); /* these have to match what is in wpa_supplicant */ @@ -334,7 +327,7 @@ struct rndis_wext_private { /* hardware state */ int radio_on; int infra_mode; - struct NDIS_802_11_SSID essid; + struct ndis_80211_ssid essid; /* encryption stuff */ int encr_tx_key_index; @@ -484,7 +477,7 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) static int rndis_set_config_parameter(struct usbnet *dev, char *param, int value_type, void *value) { - struct RNDIS_CONFIG_PARAMETER_INFOBUFFER *infobuf; + struct ndis_config_param *infobuf; int value_len, info_len, param_len, ret, i; __le16 *unibuf; __le32 *dst_value; @@ -519,12 +512,11 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, devdbg(dev, "setting config parameter: %s, value: %d", param, *(u32 *)value); - infobuf->ParameterNameOffset = cpu_to_le32(sizeof(*infobuf)); - infobuf->ParameterNameLength = cpu_to_le32(param_len); - infobuf->ParameterType = cpu_to_le32(value_type); - infobuf->ParameterValueOffset = cpu_to_le32(sizeof(*infobuf) + - param_len); - infobuf->ParameterValueLength = cpu_to_le32(value_len); + infobuf->name_offs = cpu_to_le32(sizeof(*infobuf)); + infobuf->name_length = cpu_to_le32(param_len); + infobuf->type = cpu_to_le32(value_type); + infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len); + infobuf->value_length = cpu_to_le32(value_len); /* simple string to unicode string conversion */ unibuf = (void *)infobuf + sizeof(*infobuf); @@ -630,7 +622,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index); -static int get_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid) +static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { int ret, len; @@ -638,14 +630,14 @@ static int get_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid) ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len); if (ret != 0) - ssid->SsidLength = 0; + ssid->length = 0; #ifdef DEBUG { unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1]; - memcpy(tmp, ssid->Ssid, le32_to_cpu(ssid->SsidLength)); - tmp[le32_to_cpu(ssid->SsidLength)] = 0; + memcpy(tmp, ssid->essid, le32_to_cpu(ssid->length)); + tmp[le32_to_cpu(ssid->length)] = 0; devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret); } #endif @@ -653,7 +645,7 @@ static int get_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid) } -static int set_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid) +static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret; @@ -697,7 +689,7 @@ static int is_associated(struct usbnet *usbdev) static int disassociate(struct usbnet *usbdev, int reset_ssid) { struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - struct NDIS_802_11_SSID ssid; + struct ndis_80211_ssid ssid; int i, ret = 0; if (priv->radio_on) { @@ -714,12 +706,12 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) /* disassociate causes radio to be turned off; if reset_ssid * is given, set random ssid to enable radio */ if (reset_ssid) { - ssid.SsidLength = cpu_to_le32(sizeof(ssid.Ssid)); - get_random_bytes(&ssid.Ssid[2], sizeof(ssid.Ssid)-2); - ssid.Ssid[0] = 0x1; - ssid.Ssid[1] = 0xff; - for (i = 2; i < sizeof(ssid.Ssid); i++) - ssid.Ssid[i] = 0x1 + (ssid.Ssid[i] * 0xfe / 0xff); + ssid.length = cpu_to_le32(sizeof(ssid.essid)); + get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2); + ssid.essid[0] = 0x1; + ssid.essid[1] = 0xff; + for (i = 2; i < sizeof(ssid.essid); i++) + ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff); ret = set_essid(usbdev, &ssid); } return ret; @@ -737,23 +729,23 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = Ndis802_11AuthModeWPA2; + auth_mode = ndis_80211_auth_wpa2; else - auth_mode = Ndis802_11AuthModeWPA2PSK; + auth_mode = ndis_80211_auth_wpa2_psk; } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = Ndis802_11AuthModeWPA; + auth_mode = ndis_80211_auth_wpa; else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPAPSK; + auth_mode = ndis_80211_auth_wpa_psk; else - auth_mode = Ndis802_11AuthModeWPANone; + auth_mode = ndis_80211_auth_wpa_none; } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = Ndis802_11AuthModeAutoSwitch; + auth_mode = ndis_80211_auth_auto_switch; else - auth_mode = Ndis802_11AuthModeShared; + auth_mode = ndis_80211_auth_shared; } else - auth_mode = Ndis802_11AuthModeOpen; + auth_mode = ndis_80211_auth_open; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -778,9 +770,9 @@ static int set_priv_filter(struct usbnet *usbdev) if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) - tmp = cpu_to_le32(Ndis802_11PrivFilter8021xWEP); + tmp = cpu_to_le32(ndis_80211_priv_8021x_wep); else - tmp = cpu_to_le32(Ndis802_11PrivFilterAcceptAll); + tmp = cpu_to_le32(ndis_80211_priv_accept_all); return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp, sizeof(tmp)); @@ -798,18 +790,18 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) groupwise); if (pairwise & IW_AUTH_CIPHER_CCMP) - encr_mode = Ndis802_11Encryption3Enabled; + encr_mode = ndis_80211_encr_ccmp_enabled; else if (pairwise & IW_AUTH_CIPHER_TKIP) - encr_mode = Ndis802_11Encryption2Enabled; + encr_mode = ndis_80211_encr_tkip_enabled; else if (pairwise & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) - encr_mode = Ndis802_11Encryption1Enabled; + encr_mode = ndis_80211_encr_wep_enabled; else if (groupwise & IW_AUTH_CIPHER_CCMP) - encr_mode = Ndis802_11Encryption3Enabled; + encr_mode = ndis_80211_encr_ccmp_enabled; else if (groupwise & IW_AUTH_CIPHER_TKIP) - encr_mode = Ndis802_11Encryption2Enabled; + encr_mode = ndis_80211_encr_tkip_enabled; else - encr_mode = Ndis802_11EncryptionDisabled; + encr_mode = ndis_80211_encr_disabled; tmp = cpu_to_le32(encr_mode); ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, @@ -877,7 +869,7 @@ static void set_default_iw_params(struct usbnet *usbdev) priv->wpa_keymgmt = 0; priv->wpa_version = 0; - set_infra_mode(usbdev, Ndis802_11Infrastructure); + set_infra_mode(usbdev, ndis_80211_infra_infra); set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, IW_AUTH_ALG_OPEN_SYSTEM); set_priv_filter(usbdev); @@ -899,7 +891,7 @@ static int deauthenticate(struct usbnet *usbdev) static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - struct NDIS_802_11_WEP ndis_key; + struct ndis_80211_wep_key ndis_key; int ret; if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4) @@ -907,13 +899,13 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) memset(&ndis_key, 0, sizeof(ndis_key)); - ndis_key.Length = cpu_to_le32(sizeof(ndis_key)); - ndis_key.KeyLength = cpu_to_le32(key_len); - ndis_key.KeyIndex = cpu_to_le32(index); - memcpy(&ndis_key.KeyMaterial, key, key_len); + ndis_key.size = cpu_to_le32(sizeof(ndis_key)); + ndis_key.length = cpu_to_le32(key_len); + ndis_key.index = cpu_to_le32(index); + memcpy(&ndis_key.material, key, key_len); if (index == priv->encr_tx_key_index) { - ndis_key.KeyIndex |= cpu_to_le32(1 << 31); + ndis_key.index |= cpu_to_le32(1 << 31); ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, IW_AUTH_CIPHER_NONE); if (ret) @@ -940,7 +932,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - struct NDIS_802_11_REMOVE_KEY remove_key; + struct ndis_80211_remove_key remove_key; __le32 keyindex; int ret; @@ -954,17 +946,17 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP || priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP || priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) { - remove_key.Length = cpu_to_le32(sizeof(remove_key)); - remove_key.KeyIndex = cpu_to_le32(index); + remove_key.size = cpu_to_le32(sizeof(remove_key)); + remove_key.index = cpu_to_le32(index); if (bssid) { /* pairwise key */ if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) - remove_key.KeyIndex |= cpu_to_le32(1 << 30); - memcpy(remove_key.Bssid, bssid, - sizeof(remove_key.Bssid)); + remove_key.index |= cpu_to_le32(1 << 30); + memcpy(remove_key.bssid, bssid, + sizeof(remove_key.bssid)); } else - memset(remove_key.Bssid, 0xff, - sizeof(remove_key.Bssid)); + memset(remove_key.bssid, 0xff, + sizeof(remove_key.bssid)); ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_KEY, &remove_key, sizeof(remove_key)); @@ -1184,7 +1176,7 @@ static int rndis_iw_get_name(struct net_device *dev, static int rndis_iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { - struct NDIS_802_11_SSID ssid; + struct ndis_80211_ssid ssid; int length = wrqu->essid.length; struct usbnet *usbdev = dev->priv; @@ -1194,11 +1186,11 @@ static int rndis_iw_set_essid(struct net_device *dev, if (length > NDIS_802_11_LENGTH_SSID) length = NDIS_802_11_LENGTH_SSID; - ssid.SsidLength = cpu_to_le32(length); + ssid.length = cpu_to_le32(length); if (length > 0) - memcpy(ssid.Ssid, essid, length); + memcpy(ssid.essid, essid, length); else - memset(ssid.Ssid, 0, NDIS_802_11_LENGTH_SSID); + memset(ssid.essid, 0, NDIS_802_11_LENGTH_SSID); set_assoc_params(usbdev); @@ -1212,16 +1204,16 @@ static int rndis_iw_set_essid(struct net_device *dev, static int rndis_iw_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { - struct NDIS_802_11_SSID ssid; + struct ndis_80211_ssid ssid; struct usbnet *usbdev = dev->priv; int ret; ret = get_essid(usbdev, &ssid); - if (ret == 0 && le32_to_cpu(ssid.SsidLength) > 0) { + if (ret == 0 && le32_to_cpu(ssid.length) > 0) { wrqu->essid.flags = 1; - wrqu->essid.length = le32_to_cpu(ssid.SsidLength); - memcpy(essid, ssid.Ssid, wrqu->essid.length); + wrqu->essid.length = le32_to_cpu(ssid.length); + memcpy(essid, ssid.essid, wrqu->essid.length); essid[wrqu->essid.length] = 0; } else { memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID)); @@ -1398,13 +1390,13 @@ static int rndis_iw_get_mode(struct net_device *dev, struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (priv->infra_mode) { - case Ndis802_11IBSS: + case ndis_80211_infra_adhoc: wrqu->mode = IW_MODE_ADHOC; break; - case Ndis802_11Infrastructure: + case ndis_80211_infra_infra: wrqu->mode = IW_MODE_INFRA; break; - /*case Ndis802_11AutoUnknown:*/ + /*case ndis_80211_infra_auto_unknown:*/ default: wrqu->mode = IW_MODE_AUTO; break; @@ -1424,14 +1416,14 @@ static int rndis_iw_set_mode(struct net_device *dev, switch (wrqu->mode) { case IW_MODE_ADHOC: - mode = Ndis802_11IBSS; + mode = ndis_80211_infra_adhoc; break; case IW_MODE_INFRA: - mode = Ndis802_11Infrastructure; + mode = ndis_80211_infra_infra; break; /*case IW_MODE_AUTO:*/ default: - mode = Ndis802_11AutoUnknown; + mode = ndis_80211_infra_auto_unknown; break; } @@ -1507,7 +1499,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = dev->priv; struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - struct NDIS_802_11_KEY ndis_key; + struct ndis_80211_key ndis_key; int keyidx, ret; u8 *addr; @@ -1532,54 +1524,54 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) return remove_key(usbdev, keyidx, NULL); - if (ext->key_len > sizeof(ndis_key.KeyMaterial)) + if (ext->key_len > sizeof(ndis_key.material)) return -1; memset(&ndis_key, 0, sizeof(ndis_key)); - ndis_key.Length = cpu_to_le32(sizeof(ndis_key) - - sizeof(ndis_key.KeyMaterial) + ext->key_len); - ndis_key.KeyLength = cpu_to_le32(ext->key_len); - ndis_key.KeyIndex = cpu_to_le32(keyidx); + ndis_key.size = cpu_to_le32(sizeof(ndis_key) - + sizeof(ndis_key.material) + ext->key_len); + ndis_key.length = cpu_to_le32(ext->key_len); + ndis_key.index = cpu_to_le32(keyidx); if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - memcpy(ndis_key.KeyRSC, ext->rx_seq, 6); - ndis_key.KeyIndex |= cpu_to_le32(1 << 29); + memcpy(ndis_key.rsc, ext->rx_seq, 6); + ndis_key.index |= cpu_to_le32(1 << 29); } addr = ext->addr.sa_data; if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { /* group key */ - if (priv->infra_mode == Ndis802_11IBSS) - memset(ndis_key.Bssid, 0xff, ETH_ALEN); + if (priv->infra_mode == ndis_80211_infra_adhoc) + memset(ndis_key.bssid, 0xff, ETH_ALEN); else - get_bssid(usbdev, ndis_key.Bssid); + get_bssid(usbdev, ndis_key.bssid); } else { /* pairwise key */ - ndis_key.KeyIndex |= cpu_to_le32(1 << 30); - memcpy(ndis_key.Bssid, addr, ETH_ALEN); + ndis_key.index |= cpu_to_le32(1 << 30); + memcpy(ndis_key.bssid, addr, ETH_ALEN); } if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - ndis_key.KeyIndex |= cpu_to_le32(1 << 31); + ndis_key.index |= cpu_to_le32(1 << 31); if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { /* wpa_supplicant gives us the Michael MIC RX/TX keys in * different order than NDIS spec, so swap the order here. */ - memcpy(ndis_key.KeyMaterial, ext->key, 16); - memcpy(ndis_key.KeyMaterial + 16, ext->key + 24, 8); - memcpy(ndis_key.KeyMaterial + 24, ext->key + 16, 8); + memcpy(ndis_key.material, ext->key, 16); + memcpy(ndis_key.material + 16, ext->key + 24, 8); + memcpy(ndis_key.material + 24, ext->key + 16, 8); } else - memcpy(ndis_key.KeyMaterial, ext->key, ext->key_len); + memcpy(ndis_key.material, ext->key, ext->key_len); ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.Length)); + le32_to_cpu(ndis_key.size)); devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret); if (ret != 0) return ret; priv->encr_key_len[keyidx] = ext->key_len; - memcpy(&priv->encr_keys[keyidx], ndis_key.KeyMaterial, ext->key_len); + memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len); if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) priv->encr_tx_key_index = keyidx; @@ -1611,7 +1603,7 @@ static int rndis_iw_set_scan(struct net_device *dev, static char *rndis_translate_scan(struct net_device *dev, - char *cev, char *end_buf, struct NDIS_WLAN_BSSID_EX *bssid) + char *cev, char *end_buf, struct ndis_80211_bssid_ex *bssid) { #ifdef DEBUG struct usbnet *usbdev = dev->priv; @@ -1624,60 +1616,55 @@ static char *rndis_translate_scan(struct net_device *dev, unsigned char sbuf[32]; DECLARE_MAC_BUF(mac); - bssid_len = le32_to_cpu(bssid->Length); + bssid_len = le32_to_cpu(bssid->length); - devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->MacAddress)); + devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bssid->MacAddress, ETH_ALEN); + memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN); - devdbg(usbdev, "SSID(%d) %s", - le32_to_cpu(bssid->Ssid.SsidLength), - bssid->Ssid.Ssid); + devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length), + bssid->ssid.essid); iwe.cmd = SIOCGIWESSID; - iwe.u.essid.length = le32_to_cpu(bssid->Ssid.SsidLength); + iwe.u.essid.length = le32_to_cpu(bssid->ssid.length); iwe.u.essid.flags = 1; - cev = iwe_stream_add_point(cev, end_buf, &iwe, - bssid->Ssid.Ssid); + cev = iwe_stream_add_point(cev, end_buf, &iwe, bssid->ssid.essid); - devdbg(usbdev, "MODE %d", - le32_to_cpu(bssid->InfrastructureMode)); + devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra)); iwe.cmd = SIOCGIWMODE; - switch (le32_to_cpu(bssid->InfrastructureMode)) { - case Ndis802_11IBSS: + switch (le32_to_cpu(bssid->net_infra)) { + case ndis_80211_infra_adhoc: iwe.u.mode = IW_MODE_ADHOC; break; - case Ndis802_11Infrastructure: + case ndis_80211_infra_infra: iwe.u.mode = IW_MODE_INFRA; break; - /*case Ndis802_11AutoUnknown:*/ + /*case ndis_80211_infra_auto_unknown:*/ default: iwe.u.mode = IW_MODE_AUTO; break; } cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN); - devdbg(usbdev, "FREQ %d kHz", - le32_to_cpu(bssid->Configuration.DSConfig)); + devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config)); iwe.cmd = SIOCGIWFREQ; - dsconfig_to_freq(le32_to_cpu(bssid->Configuration.DSConfig), - &iwe.u.freq); + dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq); cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN); - devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->Rssi)); + devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi)); iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->Rssi)); - iwe.u.qual.level = le32_to_cpu(bssid->Rssi); + iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->rssi)); + iwe.u.qual.level = le32_to_cpu(bssid->rssi); iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN); - devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->Privacy)); + devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy)); iwe.cmd = SIOCGIWENCODE; iwe.u.data.length = 0; - if (le32_to_cpu(bssid->Privacy) == Ndis802_11PrivFilterAcceptAll) + if (le32_to_cpu(bssid->privacy) == ndis_80211_priv_accept_all) iwe.u.data.flags = IW_ENCODE_DISABLED; else iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; @@ -1687,10 +1674,10 @@ static char *rndis_translate_scan(struct net_device *dev, devdbg(usbdev, "RATES:"); current_val = cev + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; - for (i = 0; i < sizeof(bssid->SupportedRates); i++) { - if (bssid->SupportedRates[i] & 0x7f) { + for (i = 0; i < sizeof(bssid->rates); i++) { + if (bssid->rates[i] & 0x7f) { iwe.u.bitrate.value = - ((bssid->SupportedRates[i] & 0x7f) * + ((bssid->rates[i] & 0x7f) * 500000); devdbg(usbdev, " %d", iwe.u.bitrate.value); current_val = iwe_stream_add_value(cev, @@ -1702,24 +1689,24 @@ static char *rndis_translate_scan(struct net_device *dev, if ((current_val - cev) > IW_EV_LCP_LEN) cev = current_val; - beacon = le32_to_cpu(bssid->Configuration.BeaconPeriod); + beacon = le32_to_cpu(bssid->config.beacon_period); devdbg(usbdev, "BCN_INT %d", beacon); iwe.cmd = IWEVCUSTOM; snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon); iwe.u.data.length = strlen(sbuf); cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf); - atim = le32_to_cpu(bssid->Configuration.ATIMWindow); + atim = le32_to_cpu(bssid->config.atim_window); devdbg(usbdev, "ATIM %d", atim); iwe.cmd = IWEVCUSTOM; snprintf(sbuf, sizeof(sbuf), "atim=%u", atim); iwe.u.data.length = strlen(sbuf); cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf); - ie = (void *)(bssid->IEs + sizeof(struct NDIS_802_11_FIXED_IEs)); + ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); ie_len = min(bssid_len - (int)sizeof(*bssid), - (int)le32_to_cpu(bssid->IELength)); - ie_len -= sizeof(struct NDIS_802_11_FIXED_IEs); + (int)le32_to_cpu(bssid->ie_length)); + ie_len -= sizeof(struct ndis_80211_fixed_ies); while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) { if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 && memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) || @@ -1746,8 +1733,8 @@ static int rndis_iw_get_scan(struct net_device *dev, struct usbnet *usbdev = dev->priv; void *buf = NULL; char *cev = extra; - struct NDIS_802_11_BSSID_LIST_EX *bssid_list; - struct NDIS_WLAN_BSSID_EX *bssid; + struct ndis_80211_bssid_list_ex *bssid_list; + struct ndis_80211_bssid_ex *bssid; int ret = -EINVAL, len, count, bssid_len; devdbg(usbdev, "SIOCGIWSCAN"); @@ -1765,16 +1752,16 @@ static int rndis_iw_get_scan(struct net_device *dev, goto out; bssid_list = buf; - bssid = bssid_list->Bssid; - bssid_len = le32_to_cpu(bssid->Length); - count = le32_to_cpu(bssid_list->NumberOfItems); + bssid = bssid_list->bssid; + bssid_len = le32_to_cpu(bssid->length); + count = le32_to_cpu(bssid_list->num_items); devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count); while (count && ((void *)bssid + bssid_len) <= (buf + len)) { cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA, bssid); bssid = (void *)bssid + bssid_len; - bssid_len = le32_to_cpu(bssid->Length); + bssid_len = le32_to_cpu(bssid->length); count--; } @@ -1948,7 +1935,7 @@ static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = dev->priv; - struct NDIS_802_11_CONFIGURATION config; + struct ndis_80211_conf config; unsigned int dsconfig; int len, ret; @@ -1967,7 +1954,7 @@ static int rndis_iw_set_freq(struct net_device *dev, return 0; } - config.DSConfig = cpu_to_le32(dsconfig); + config.ds_config = cpu_to_le32(dsconfig); devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e); return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, @@ -1979,13 +1966,13 @@ static int rndis_iw_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = dev->priv; - struct NDIS_802_11_CONFIGURATION config; + struct ndis_80211_conf config; int len, ret; len = sizeof(config); ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); if (ret == 0) - dsconfig_to_freq(le32_to_cpu(config.DSConfig), &wrqu->freq); + dsconfig_to_freq(le32_to_cpu(config.ds_config), &wrqu->freq); devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m); return ret; @@ -2266,14 +2253,14 @@ static int rndis_wext_get_caps(struct usbnet *dev) n = 8; for (i = 0; i < n; i++) { switch (le32_to_cpu(networks_supported.items[i])) { - case Ndis802_11FH: - case Ndis802_11DS: + case ndis_80211_type_freq_hop: + case ndis_80211_type_direct_seq: priv->caps |= CAP_MODE_80211B; break; - case Ndis802_11OFDM5: + case ndis_80211_type_ofdm_a: priv->caps |= CAP_MODE_80211A; break; - case Ndis802_11OFDM24: + case ndis_80211_type_ofdm_g: priv->caps |= CAP_MODE_80211G; break; } diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index da05b1faf60..a1e3938cba9 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -5,30 +5,28 @@ config RT2X00 This will enable the experimental support for the Ralink drivers, developed in the rt2x00 project <http://rt2x00.serialmonkey.com>. - These drivers will make use of the Devicescape ieee80211 stack. + These drivers will make use of the mac80211 stack. When building one of the individual drivers, the rt2x00 library will also be created. That library (when the driver is built as a module) will be called "rt2x00lib.ko". +if RT2X00 + config RT2X00_LIB tristate - depends on RT2X00 config RT2X00_LIB_PCI tristate - depends on RT2X00 select RT2X00_LIB config RT2X00_LIB_USB tristate - depends on RT2X00 select RT2X00_LIB config RT2X00_LIB_FIRMWARE boolean depends on RT2X00_LIB - select CRC_ITU_T select FW_LOADER config RT2X00_LIB_RFKILL @@ -37,9 +35,13 @@ config RT2X00_LIB_RFKILL select RFKILL select INPUT_POLLDEV +config RT2X00_LIB_LEDS + boolean + depends on RT2X00_LIB + config RT2400PCI tristate "Ralink rt2400 pci/pcmcia support" - depends on RT2X00 && PCI + depends on PCI select RT2X00_LIB_PCI select EEPROM_93CX6 ---help--- @@ -56,9 +58,16 @@ config RT2400PCI_RFKILL hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. +config RT2400PCI_LEDS + bool "RT2400 leds support" + depends on RT2400PCI && LEDS_CLASS + select RT2X00_LIB_LEDS + ---help--- + This adds support for led triggers provided my mac80211. + config RT2500PCI tristate "Ralink rt2500 pci/pcmcia support" - depends on RT2X00 && PCI + depends on PCI select RT2X00_LIB_PCI select EEPROM_93CX6 ---help--- @@ -75,11 +84,19 @@ config RT2500PCI_RFKILL hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. +config RT2500PCI_LEDS + bool "RT2500 leds support" + depends on RT2500PCI && LEDS_CLASS + select RT2X00_LIB_LEDS + ---help--- + This adds support for led triggers provided my mac80211. + config RT61PCI tristate "Ralink rt61 pci/pcmcia support" - depends on RT2X00 && PCI + depends on PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE + select CRC_ITU_T select EEPROM_93CX6 ---help--- This is an experimental driver for the Ralink rt61 wireless chip. @@ -95,25 +112,47 @@ config RT61PCI_RFKILL hardware button to control the radio state. This feature depends on the RF switch subsystem rfkill. +config RT61PCI_LEDS + bool "RT61 leds support" + depends on RT61PCI && LEDS_CLASS + select RT2X00_LIB_LEDS + ---help--- + This adds support for led triggers provided my mac80211. + config RT2500USB tristate "Ralink rt2500 usb support" - depends on RT2X00 && USB + depends on USB select RT2X00_LIB_USB ---help--- This is an experimental driver for the Ralink rt2500 wireless chip. When compiled as a module, this driver will be called "rt2500usb.ko". +config RT2500USB_LEDS + bool "RT2500 leds support" + depends on RT2500USB && LEDS_CLASS + select RT2X00_LIB_LEDS + ---help--- + This adds support for led triggers provided my mac80211. + config RT73USB tristate "Ralink rt73 usb support" - depends on RT2X00 && USB + depends on USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE + select CRC_ITU_T ---help--- This is an experimental driver for the Ralink rt73 wireless chip. When compiled as a module, this driver will be called "rt73usb.ko". +config RT73USB_LEDS + bool "RT73 leds support" + depends on RT73USB && LEDS_CLASS + select RT2X00_LIB_LEDS + ---help--- + This adds support for led triggers provided my mac80211. + config RT2X00_LIB_DEBUGFS bool "Ralink debugfs support" depends on RT2X00_LIB && MAC80211_DEBUGFS @@ -128,3 +167,4 @@ config RT2X00_DEBUG ---help--- Enable debugging output for all rt2x00 modules +endif diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 30d654a42ee..1087dbcf1a0 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -1,22 +1,17 @@ -rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o +rt2x00lib-y += rt2x00dev.o +rt2x00lib-y += rt2x00mac.o +rt2x00lib-y += rt2x00config.o +rt2x00lib-y += rt2x00queue.o +rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o +rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o +rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o +rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o -ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y) - rt2x00lib-objs += rt2x00debug.o -endif - -ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y) - rt2x00lib-objs += rt2x00rfkill.o -endif - -ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y) - rt2x00lib-objs += rt2x00firmware.o -endif - -obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o -obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o -obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o -obj-$(CONFIG_RT2400PCI) += rt2400pci.o -obj-$(CONFIG_RT2500PCI) += rt2500pci.o -obj-$(CONFIG_RT61PCI) += rt61pci.o -obj-$(CONFIG_RT2500USB) += rt2500usb.o -obj-$(CONFIG_RT73USB) += rt73usb.o +obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o +obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o +obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o +obj-$(CONFIG_RT2400PCI) += rt2400pci.o +obj-$(CONFIG_RT2500PCI) += rt2500pci.o +obj-$(CONFIG_RT61PCI) += rt61pci.o +obj-$(CONFIG_RT2500USB) += rt2500usb.o +obj-$(CONFIG_RT73USB) += rt73usb.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index c69f85ed766..b41187af130 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -243,53 +243,109 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) #define rt2400pci_rfkill_poll NULL #endif /* CONFIG_RT2400PCI_RFKILL */ -/* - * Configuration handlers. - */ -static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, - __le32 *mac) +#ifdef CONFIG_RT2400PCI_LEDS +static void rt2400pci_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, - (2 * sizeof(__le32))); + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + u32 reg; + + rt2x00pci_register_read(led->rt2x00dev, LEDCSR, ®); + + if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) + rt2x00_set_field32(®, LEDCSR_LINK, enabled); + else if (led->type == LED_TYPE_ACTIVITY) + rt2x00_set_field32(®, LEDCSR_ACTIVITY, enabled); + + rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg); } -static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, - __le32 *bssid) +static int rt2400pci_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, - (2 * sizeof(__le32))); + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; + + rt2x00pci_register_read(led->rt2x00dev, LEDCSR, ®); + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); + rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg); + + return 0; } +#endif /* CONFIG_RT2400PCI_LEDS */ -static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +/* + * Configuration handlers. + */ +static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) { u32 reg; - rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Enable beacon config + * Start configuration steps. + * Note that the version error will always be dropped + * since there is no filter for it at this time. */ - rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); - rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 20)); - rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(filter_flags & FIF_PROMISC_IN_BSS) && + !rt2x00dev->intf_ap_count); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR0, 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); +static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) +{ + unsigned int bcn_preload; + u32 reg; + + if (flags & CONFIG_UPDATE_TYPE) { + /* + * 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); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, CSR14_TBCN, 1); + 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, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) { int preamble_mask; u32 reg; @@ -297,11 +353,13 @@ static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, /* * When short preamble is enabled, we should set bit 0x08 */ - preamble_mask = short_preamble << 3; + preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, + erp->ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, + erp->ack_consume_time); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); @@ -397,6 +455,13 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, u8 r1; u8 r4; + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + rt2400pci_bbp_read(rt2x00dev, 4, &r4); rt2400pci_bbp_read(rt2x00dev, 1, &r1); @@ -410,14 +475,8 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, case ANTENNA_A: rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); break; } @@ -432,14 +491,8 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, case ANTENNA_A: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); break; } @@ -481,8 +534,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); @@ -498,45 +551,17 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, } static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, - struct ieee80211_tx_queue_params *params) + const int cw_min, const int cw_max) { u32 reg; rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_CWMIN, params->cw_min); - rt2x00_set_field32(®, CSR11_CWMAX, params->cw_max); + rt2x00_set_field32(®, CSR11_CWMIN, cw_min); + rt2x00_set_field32(®, CSR11_CWMAX, cw_max); rt2x00pci_register_write(rt2x00dev, CSR11, reg); } /* - * LED functions. - */ -static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); - - rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); - rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); - rt2x00_set_field32(®, LEDCSR_LINK, - (rt2x00dev->led_mode != LED_MODE_ASUS)); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, - (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); - rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); -} - -static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); - rt2x00_set_field32(®, LEDCSR_LINK, 0); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); - rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); -} - -/* * Link tuning */ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, @@ -593,90 +618,94 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) * Initialization functions. */ static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - __le32 *rxd = entry->priv; + struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; u32 word; - rt2x00_desc_read(rxd, 2, &word); - rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->ring->data_size); - rt2x00_desc_write(rxd, 2, word); + rt2x00_desc_read(priv_rx->desc, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, + entry->queue->data_size); + rt2x00_desc_write(priv_rx->desc, 2, word); - rt2x00_desc_read(rxd, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma); - rt2x00_desc_write(rxd, 1, word); + rt2x00_desc_read(priv_rx->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); + rt2x00_desc_write(priv_rx->desc, 1, word); - rt2x00_desc_read(rxd, 0, &word); + rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); + rt2x00_desc_write(priv_rx->desc, 0, word); } static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - __le32 *txd = entry->priv; + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma); - rt2x00_desc_write(txd, 1, word); + rt2x00_desc_read(priv_tx->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); + rt2x00_desc_write(priv_tx->desc, 1, word); - rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, entry->ring->data_size); - rt2x00_desc_write(txd, 2, word); + rt2x00_desc_read(priv_tx->desc, 2, &word); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, + entry->queue->data_size); + rt2x00_desc_write(priv_tx->desc, 2, word); - rt2x00_desc_read(txd, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(txd, 0, word); + rt2x00_desc_write(priv_tx->desc, 0, word); } -static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev) +static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) { + struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci_tx *priv_tx; u32 reg; /* * Initialize registers. */ rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); - rt2x00_set_field32(®, TXCSR2_TXD_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size); - rt2x00_set_field32(®, TXCSR2_NUM_TXD, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); - rt2x00_set_field32(®, TXCSR2_NUM_ATIM, - rt2x00dev->bcn[1].stats.limit); - rt2x00_set_field32(®, TXCSR2_NUM_PRIO, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); + rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); + rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->bcn[1].limit); + rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); + priv_tx = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); + priv_tx = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); + priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - rt2x00dev->bcn[1].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); + priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - rt2x00dev->bcn[0].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); - rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit); + rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); + priv_rx = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, - rt2x00dev->rx->data_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -795,19 +824,15 @@ continue_csr_init: rt2400pci_bbp_write(rt2x00dev, 30, 0x21); rt2400pci_bbp_write(rt2x00dev, 31, 0x00); - DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); for (i = 0; i < EEPROM_BBP_SIZE; i++) { rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", - reg_id, value); rt2400pci_bbp_write(rt2x00dev, reg_id, value); } } - DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); return 0; } @@ -859,7 +884,7 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt2400pci_init_rings(rt2x00dev) || + if (rt2400pci_init_queues(rt2x00dev) || rt2400pci_init_registers(rt2x00dev) || rt2400pci_init_bbp(rt2x00dev)) { ERROR(rt2x00dev, "Register initialization failed.\n"); @@ -871,11 +896,6 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) */ rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); - /* - * Enable LED - */ - rt2400pci_enable_led(rt2x00dev); - return 0; } @@ -883,11 +903,6 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - /* - * Disable LED - */ - rt2400pci_disable_led(rt2x00dev); - rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0); /* @@ -986,10 +1001,10 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txdata_entry_desc *desc, + struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { - struct skb_desc *skbdesc = get_skb_desc(skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; u32 word; @@ -1001,19 +1016,19 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); - rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->signal); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1); - rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->service); rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6); rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1); rt2x00_desc_write(txd, 3, word); rt2x00_desc_read(txd, 4, &word); - rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, txdesc->length_low); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1); - rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1); rt2x00_desc_write(txd, 4, word); @@ -1022,14 +1037,14 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, - test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - test_bit(ENTRY_TXD_ACK, &desc->flags)); + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, - test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_RTS, - test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags)); - rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); @@ -1040,13 +1055,15 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - unsigned int queue) + const unsigned int queue) { u32 reg; - if (queue == IEEE80211_TX_QUEUE_BEACON) { + if (queue == RT2X00_BCN_QUEUE_BEACON) { rt2x00pci_register_read(rt2x00dev, CSR14, ®); if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1059,56 +1076,62 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == IEEE80211_TX_QUEUE_DATA1)); rt2x00_set_field32(®, TXCSR0_KICK_ATIM, - (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)); + (queue == RT2X00_BCN_QUEUE_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } /* * RX control handlers */ -static void rt2400pci_fill_rxdone(struct data_entry *entry, - struct rxdata_entry_desc *desc) +static void rt2400pci_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) { - __le32 *rxd = entry->priv; + struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; u32 word0; u32 word2; + u32 word3; - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 2, &word2); + rt2x00_desc_read(priv_rx->desc, 0, &word0); + rt2x00_desc_read(priv_rx->desc, 2, &word2); + rt2x00_desc_read(priv_rx->desc, 3, &word3); - desc->flags = 0; + rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) - desc->flags |= RX_FLAG_FAILED_FCS_CRC; + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - desc->flags |= RX_FLAG_FAILED_PLCP_CRC; + rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. + * The signal is the PLCP value, and needs to be stripped + * of the preamble bit (0x08). */ - desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - - entry->ring->rt2x00dev->rssi_offset; - desc->ofdm = 0; - desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); + rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08; + rxdesc->rssi = rt2x00_get_field32(word2, RXD_W3_RSSI) - + entry->queue->rt2x00dev->rssi_offset; + rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + rxdesc->dev_flags = RXDONE_SIGNAL_PLCP; + if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; } /* * Interrupt functions. */ -static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) +static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, + const enum ieee80211_tx_queue queue_idx) { - struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); - struct data_entry *entry; - __le32 *txd; + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry *entry; + struct txdone_entry_desc txdesc; u32 word; - int tx_status; - int retry; - while (!rt2x00_ring_empty(ring)) { - entry = rt2x00_get_data_entry_done(ring); - txd = entry->priv; - rt2x00_desc_read(txd, 0, &word); + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + priv_tx = entry->priv_data; + rt2x00_desc_read(priv_tx->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1117,10 +1140,10 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) /* * Obtain the status about this packet. */ - tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); - retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); + txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); - rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry); + rt2x00pci_txdone(rt2x00dev, entry, &txdesc); } } @@ -1164,7 +1187,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * 3 - Atim ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + rt2400pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); /* * 4 - Priority ring transmit done interrupt. @@ -1272,8 +1295,27 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ - rt2x00dev->led_mode = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); +#ifdef CONFIG_RT2400PCI_LEDS + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + rt2x00dev->led_radio.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_RADIO; + rt2x00dev->led_radio.led_dev.brightness_set = + rt2400pci_brightness_set; + rt2x00dev->led_radio.led_dev.blink_set = + rt2400pci_blink_set; + rt2x00dev->led_radio.flags = LED_INITIALIZED; + + if (value == LED_MODE_TXRX_ACTIVITY) { + rt2x00dev->led_qual.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_ACTIVITY; + rt2x00dev->led_qual.led_dev.brightness_set = + rt2400pci_brightness_set; + rt2x00dev->led_qual.led_dev.blink_set = + rt2400pci_blink_set; + rt2x00dev->led_qual.flags = LED_INITIALIZED; + } +#endif /* CONFIG_RT2400PCI_LEDS */ /* * Detect if this device has an hardware controlled radio. @@ -1343,8 +1385,8 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->num_modes = 1; - spec->num_rates = 4; + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK; spec->tx_power_a = NULL; spec->tx_power_bg = txpower; spec->tx_power_default = DEFAULT_TXPOWER; @@ -1374,9 +1416,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) rt2400pci_probe_hw_mode(rt2x00dev); /* - * This device requires the beacon ring + * This device requires the atim queue */ - __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1389,64 +1431,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static void rt2400pci_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - /* - * Mask off any flags we are going to ignore from - * the total_flags field. - */ - *total_flags &= - FIF_ALLMULTI | - FIF_FCSFAIL | - FIF_PLCPFAIL | - FIF_CONTROL | - FIF_OTHER_BSS | - FIF_PROMISC_IN_BSS; - - /* - * Apply some rules to the filters: - * - Some filters imply different filters to be set. - * - Some things we can't filter out at all. - */ - *total_flags |= FIF_ALLMULTI; - if (*total_flags & FIF_OTHER_BSS || - *total_flags & FIF_PROMISC_IN_BSS) - *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - - /* - * Check if there is any work left for us. - */ - if (rt2x00dev->packet_filter == *total_flags) - return; - rt2x00dev->packet_filter = *total_flags; - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * since there is no filter for it at this time. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_CRC, - !(*total_flags & FIF_FCSFAIL)); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, - !(*total_flags & FIF_PLCPFAIL)); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, - !(*total_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, RXCSR0_DROP_TODS, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1481,7 +1465,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, /* * Write configuration to register. */ - rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params); + rt2400pci_config_cw(rt2x00dev, + rt2x00dev->tx->cw_min, rt2x00dev->tx->cw_max); return 0; } @@ -1500,12 +1485,58 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void rt2400pci_reset_tsf(struct ieee80211_hw *hw) +static int rt2400pci_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; + u32 reg; + + if (unlikely(!intf->beacon)) + return -ENOBUFS; + priv_tx = intf->beacon->priv_data; - rt2x00pci_register_write(rt2x00dev, CSR16, 0); - rt2x00pci_register_write(rt2x00dev, CSR17, 0); + /* + * Fill in skb descriptor + */ + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; + skbdesc->data = skb->data; + skbdesc->data_len = skb->len; + skbdesc->desc = priv_tx->desc; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); + rt2x00_set_field32(®, CSR14_TBCN, 0); + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + + /* + * mac80211 doesn't provide the control->queue variable + * for beacons. Set our own queue identification so + * it can be used during descriptor initialization. + */ + control->queue = RT2X00_BCN_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; } static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) @@ -1525,15 +1556,14 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .configure_filter = rt2400pci_configure_filter, + .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, - .reset_tsf = rt2400pci_reset_tsf, - .beacon_update = rt2x00pci_beacon_update, + .beacon_update = rt2400pci_beacon_update, .tx_last_beacon = rt2400pci_tx_last_beacon, }; @@ -1553,19 +1583,50 @@ 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_preamble = rt2400pci_config_preamble, + .config_filter = rt2400pci_config_filter, + .config_intf = rt2400pci_config_intf, + .config_erp = rt2400pci_config_erp, .config = rt2400pci_config, }; +static const struct data_queue_desc rt2400pci_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = RXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_rx), +}; + +static const struct data_queue_desc rt2400pci_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + +static const struct data_queue_desc rt2400pci_queue_bcn = { + .entry_num = BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + +static const struct data_queue_desc rt2400pci_queue_atim = { + .entry_num = ATIM_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + static const struct rt2x00_ops rt2400pci_ops = { .name = KBUILD_MODNAME, - .rxd_size = RXD_DESC_SIZE, - .txd_size = TXD_DESC_SIZE, + .max_sta_intf = 1, + .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .rx = &rt2400pci_queue_rx, + .tx = &rt2400pci_queue_tx, + .bcn = &rt2400pci_queue_bcn, + .atim = &rt2400pci_queue_atim, .lib = &rt2400pci_rt2x00_ops, .hw = &rt2400pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index 369aac6d033..a5210f9a336 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -899,13 +899,13 @@ * Word2 */ #define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff) -#define RXD_W2_SIGNAL FIELD32(0x00ff0000) -#define RXD_W2_RSSI FIELD32(0xff000000) +#define RXD_W2_BBR0 FIELD32(0x00ff0000) +#define RXD_W2_SIGNAL FIELD32(0xff000000) /* * Word3 */ -#define RXD_W3_BBR2 FIELD32(0x000000ff) +#define RXD_W3_RSSI FIELD32(0x000000ff) #define RXD_W3_BBR3 FIELD32(0x0000ff00) #define RXD_W3_BBR4 FIELD32(0x00ff0000) #define RXD_W3_BBR5 FIELD32(0xff000000) @@ -923,13 +923,13 @@ #define RXD_W7_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to dscape value - * and from dscape value to register value. + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. * NOTE: Logics in rt2400pci for txpower are reversed * compared to the other rt2x00 drivers. A higher txpower * value means that the txpower must be lowered. This is * important when converting the value coming from the - * dscape stack to the rt2400 acceptable value. + * mac80211 stack to the rt2400 acceptable value. */ #define MIN_TXPOWER 31 #define MAX_TXPOWER 62 diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 91e87b53374..5ade097ed45 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -243,57 +243,116 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) #define rt2500pci_rfkill_poll NULL #endif /* CONFIG_RT2500PCI_RFKILL */ -/* - * Configuration handlers. - */ -static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, - __le32 *mac) +#ifdef CONFIG_RT2500PCI_LEDS +static void rt2500pci_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, - (2 * sizeof(__le32))); + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + u32 reg; + + rt2x00pci_register_read(led->rt2x00dev, LEDCSR, ®); + + if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) + rt2x00_set_field32(®, LEDCSR_LINK, enabled); + else if (led->type == LED_TYPE_ACTIVITY) + rt2x00_set_field32(®, LEDCSR_ACTIVITY, enabled); + + rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg); } -static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, - __le32 *bssid) +static int rt2500pci_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, - (2 * sizeof(__le32))); + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; + + rt2x00pci_register_read(led->rt2x00dev, LEDCSR, ®); + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); + rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg); + + return 0; } +#endif /* CONFIG_RT2500PCI_LEDS */ -static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +/* + * Configuration handlers. + */ +static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) { u32 reg; - rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Enable beacon config + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. */ - rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); - rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 20)); - rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, - rt2x00lib_get_ring(rt2x00dev, - IEEE80211_TX_QUEUE_BEACON) - ->tx_params.cw_min); - rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(filter_flags & FIF_PROMISC_IN_BSS) && + !rt2x00dev->intf_ap_count); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, RXCSR0_DROP_MCAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RXCSR0_DROP_BCAST, 0); + rt2x00pci_register_write(rt2x00dev, RXCSR0, 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); +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, RT2X00_BCN_QUEUE_BEACON); + unsigned int bcn_preload; + u32 reg; + + if (flags & CONFIG_UPDATE_TYPE) { + /* + * 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_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, CSR14_TBCN, 1); + 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 void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) { int preamble_mask; u32 reg; @@ -301,11 +360,13 @@ static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, /* * When short preamble is enabled, we should set bit 0x08 */ - preamble_mask = short_preamble << 3; + preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, + erp->ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, + erp->ack_consume_time); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); @@ -425,6 +486,13 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, u8 r14; u8 r2; + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); rt2500pci_bbp_read(rt2x00dev, 14, &r14); rt2500pci_bbp_read(rt2x00dev, 2, &r2); @@ -438,15 +506,8 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBPCSR1_CCK, 0); rt2x00_set_field32(®, BBPCSR1_OFDM, 0); break; - case ANTENNA_HW_DIVERSITY: - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); rt2x00_set_field32(®, BBPCSR1_CCK, 2); rt2x00_set_field32(®, BBPCSR1_OFDM, 2); @@ -460,15 +521,8 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, case ANTENNA_A: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); break; - case ANTENNA_HW_DIVERSITY: - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); break; } @@ -530,8 +584,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); @@ -548,34 +602,6 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, } /* - * LED functions. - */ -static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); - - rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); - rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); - rt2x00_set_field32(®, LEDCSR_LINK, - (rt2x00dev->led_mode != LED_MODE_ASUS)); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, - (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); - rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); -} - -static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); - rt2x00_set_field32(®, LEDCSR_LINK, 0); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); - rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); -} - -/* * Link tuning */ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev, @@ -610,9 +636,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; @@ -620,9 +647,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; /* @@ -684,82 +714,84 @@ dynamic_cca_tune: * Initialization functions. */ static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - __le32 *rxd = entry->priv; + struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; u32 word; - rt2x00_desc_read(rxd, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma); - rt2x00_desc_write(rxd, 1, word); + rt2x00_desc_read(priv_rx->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); + rt2x00_desc_write(priv_rx->desc, 1, word); - rt2x00_desc_read(rxd, 0, &word); + rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); + rt2x00_desc_write(priv_rx->desc, 0, word); } static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - __le32 *txd = entry->priv; + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma); - rt2x00_desc_write(txd, 1, word); + rt2x00_desc_read(priv_tx->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma); + rt2x00_desc_write(priv_tx->desc, 1, word); - rt2x00_desc_read(txd, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(txd, 0, word); + rt2x00_desc_write(priv_tx->desc, 0, word); } -static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev) +static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) { + struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci_tx *priv_tx; u32 reg; /* * Initialize registers. */ rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); - rt2x00_set_field32(®, TXCSR2_TXD_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size); - rt2x00_set_field32(®, TXCSR2_NUM_TXD, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); - rt2x00_set_field32(®, TXCSR2_NUM_ATIM, - rt2x00dev->bcn[1].stats.limit); - rt2x00_set_field32(®, TXCSR2_NUM_PRIO, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); + rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); + rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->bcn[1].limit); + rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); + priv_tx = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); + priv_tx = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); + priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, - rt2x00dev->bcn[1].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); + priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, - rt2x00dev->bcn[0].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); - rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit); + rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); + priv_rx = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); - rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, - rt2x00dev->rx->data_dma); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); return 0; @@ -947,19 +979,15 @@ continue_csr_init: rt2500pci_bbp_write(rt2x00dev, 61, 0x6d); rt2500pci_bbp_write(rt2x00dev, 62, 0x10); - DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); for (i = 0; i < EEPROM_BBP_SIZE; i++) { rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", - reg_id, value); rt2500pci_bbp_write(rt2x00dev, reg_id, value); } } - DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); return 0; } @@ -1011,7 +1039,7 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt2500pci_init_rings(rt2x00dev) || + if (rt2500pci_init_queues(rt2x00dev) || rt2500pci_init_registers(rt2x00dev) || rt2500pci_init_bbp(rt2x00dev)) { ERROR(rt2x00dev, "Register initialization failed.\n"); @@ -1023,11 +1051,6 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) */ rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); - /* - * Enable LED - */ - rt2500pci_enable_led(rt2x00dev); - return 0; } @@ -1035,11 +1058,6 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - /* - * Disable LED - */ - rt2500pci_disable_led(rt2x00dev); - rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0); /* @@ -1138,10 +1156,10 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txdata_entry_desc *desc, + struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { - struct skb_desc *skbdesc = get_skb_desc(skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; u32 word; @@ -1150,36 +1168,36 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs); - rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min); - rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs); + rt2x00_set_field32(&word, TXD_W2_CWMIN, txdesc->cw_min); + rt2x00_set_field32(&word, TXD_W2_CWMAX, txdesc->cw_max); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); - rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal); - rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service); - rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low); - rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->service); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, txdesc->length_low); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 3, word); rt2x00_desc_read(txd, 10, &word); rt2x00_set_field32(&word, TXD_W10_RTS, - test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags)); + test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_desc_write(txd, 10, word); rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, - test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - test_bit(ENTRY_TXD_ACK, &desc->flags)); + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, - test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, - test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); - rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); @@ -1192,13 +1210,15 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - unsigned int queue) + const unsigned int queue) { u32 reg; - if (queue == IEEE80211_TX_QUEUE_BEACON) { + if (queue == RT2X00_BCN_QUEUE_BEACON) { rt2x00pci_register_read(rt2x00dev, CSR14, ®); if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1211,53 +1231,63 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == IEEE80211_TX_QUEUE_DATA1)); rt2x00_set_field32(®, TXCSR0_KICK_ATIM, - (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)); + (queue == RT2X00_BCN_QUEUE_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } /* * RX control handlers */ -static void rt2500pci_fill_rxdone(struct data_entry *entry, - struct rxdata_entry_desc *desc) +static void rt2500pci_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) { - __le32 *rxd = entry->priv; + struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; u32 word0; u32 word2; - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 2, &word2); + rt2x00_desc_read(priv_rx->desc, 0, &word0); + rt2x00_desc_read(priv_rx->desc, 2, &word2); - desc->flags = 0; + rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) - desc->flags |= RX_FLAG_FAILED_FCS_CRC; + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - desc->flags |= RX_FLAG_FAILED_PLCP_CRC; - - desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - - entry->ring->rt2x00dev->rssi_offset; - desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); + rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; + + /* + * Obtain the status about this packet. + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 100kbit/s. + */ + rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + rxdesc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->queue->rt2x00dev->rssi_offset; + rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + rxdesc->dev_flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_OFDM)) + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; } /* * Interrupt functions. */ -static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) +static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, + const enum ieee80211_tx_queue queue_idx) { - struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); - struct data_entry *entry; - __le32 *txd; + struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + struct queue_entry_priv_pci_tx *priv_tx; + struct queue_entry *entry; + struct txdone_entry_desc txdesc; u32 word; - int tx_status; - int retry; - while (!rt2x00_ring_empty(ring)) { - entry = rt2x00_get_data_entry_done(ring); - txd = entry->priv; - rt2x00_desc_read(txd, 0, &word); + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + priv_tx = entry->priv_data; + rt2x00_desc_read(priv_tx->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1266,10 +1296,10 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) /* * Obtain the status about this packet. */ - tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); - retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); + txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); + txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); - rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry); + rt2x00pci_txdone(rt2x00dev, entry, &txdesc); } } @@ -1313,7 +1343,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * 3 - Atim ring transmit done interrupt. */ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + rt2500pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); /* * 4 - Priority ring transmit done interrupt. @@ -1442,8 +1472,27 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ - rt2x00dev->led_mode = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); +#ifdef CONFIG_RT2500PCI_LEDS + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + rt2x00dev->led_radio.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_RADIO; + rt2x00dev->led_radio.led_dev.brightness_set = + rt2500pci_brightness_set; + rt2x00dev->led_radio.led_dev.blink_set = + rt2500pci_blink_set; + rt2x00dev->led_radio.flags = LED_INITIALIZED; + + if (value == LED_MODE_TXRX_ACTIVITY) { + rt2x00dev->led_qual.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_ACTIVITY; + rt2x00dev->led_qual.led_dev.brightness_set = + rt2500pci_brightness_set; + rt2x00dev->led_qual.led_dev.blink_set = + rt2500pci_blink_set; + rt2x00dev->led_qual.flags = LED_INITIALIZED; + } +#endif /* CONFIG_RT2500PCI_LEDS */ /* * Detect if this device has an hardware controlled radio. @@ -1656,8 +1705,8 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->num_modes = 2; - spec->num_rates = 12; + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; spec->tx_power_a = NULL; spec->tx_power_bg = txpower; spec->tx_power_default = DEFAULT_TXPOWER; @@ -1678,9 +1727,9 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); spec->channels = rf_vals_bg_2525e; } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; - spec->num_modes = 3; } } @@ -1705,9 +1754,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) rt2500pci_probe_hw_mode(rt2x00dev); /* - * This device requires the beacon ring + * This device requires the atim queue */ - __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1720,69 +1769,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static void rt2500pci_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - /* - * Mask off any flags we are going to ignore from - * the total_flags field. - */ - *total_flags &= - FIF_ALLMULTI | - FIF_FCSFAIL | - FIF_PLCPFAIL | - FIF_CONTROL | - FIF_OTHER_BSS | - FIF_PROMISC_IN_BSS; - - /* - * Apply some rules to the filters: - * - Some filters imply different filters to be set. - * - Some things we can't filter out at all. - */ - if (mc_count) - *total_flags |= FIF_ALLMULTI; - if (*total_flags & FIF_OTHER_BSS || - *total_flags & FIF_PROMISC_IN_BSS) - *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - - /* - * Check if there is any work left for us. - */ - if (rt2x00dev->packet_filter == *total_flags) - return; - rt2x00dev->packet_filter = *total_flags; - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * and broadcast frames will always be accepted since - * there is no filter for it at this time. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_CRC, - !(*total_flags & FIF_FCSFAIL)); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, - !(*total_flags & FIF_PLCPFAIL)); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, - !(*total_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, RXCSR0_DROP_TODS, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, RXCSR0_DROP_MCAST, - !(*total_flags & FIF_ALLMULTI)); - rt2x00_set_field32(®, RXCSR0_DROP_BCAST, 0); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1811,12 +1797,59 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void rt2500pci_reset_tsf(struct ieee80211_hw *hw) +static int rt2500pci_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; + u32 reg; - rt2x00pci_register_write(rt2x00dev, CSR16, 0); - rt2x00pci_register_write(rt2x00dev, CSR17, 0); + if (unlikely(!intf->beacon)) + return -ENOBUFS; + + priv_tx = intf->beacon->priv_data; + + /* + * Fill in skb descriptor + */ + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; + skbdesc->data = skb->data; + skbdesc->data_len = skb->len; + skbdesc->desc = priv_tx->desc; + skbdesc->desc_len = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); + rt2x00_set_field32(®, CSR14_TBCN, 0); + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + + /* + * mac80211 doesn't provide the control->queue variable + * for beacons. Set our own queue identification so + * it can be used during descriptor initialization. + */ + control->queue = RT2X00_BCN_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; } static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) @@ -1836,15 +1869,14 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .configure_filter = rt2500pci_configure_filter, + .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, - .reset_tsf = rt2500pci_reset_tsf, - .beacon_update = rt2x00pci_beacon_update, + .beacon_update = rt2500pci_beacon_update, .tx_last_beacon = rt2500pci_tx_last_beacon, }; @@ -1864,19 +1896,50 @@ 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_preamble = rt2500pci_config_preamble, + .config_filter = rt2500pci_config_filter, + .config_intf = rt2500pci_config_intf, + .config_erp = rt2500pci_config_erp, .config = rt2500pci_config, }; +static const struct data_queue_desc rt2500pci_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = RXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_rx), +}; + +static const struct data_queue_desc rt2500pci_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + +static const struct data_queue_desc rt2500pci_queue_bcn = { + .entry_num = BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + +static const struct data_queue_desc rt2500pci_queue_atim = { + .entry_num = ATIM_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + static const struct rt2x00_ops rt2500pci_ops = { .name = KBUILD_MODNAME, - .rxd_size = RXD_DESC_SIZE, - .txd_size = TXD_DESC_SIZE, + .max_sta_intf = 1, + .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .rx = &rt2500pci_queue_rx, + .tx = &rt2500pci_queue_tx, + .bcn = &rt2500pci_queue_bcn, + .atim = &rt2500pci_queue_atim, .lib = &rt2500pci_rt2x00_ops, .hw = &rt2500pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 92ba0902d10..13899550465 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -1213,8 +1213,8 @@ #define RXD_W10_DROP FIELD32(0x00000001) /* - * Macro's for converting txpower from EEPROM to dscape value - * and from dscape value to register value. + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 #define MAX_TXPOWER 31 diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 638c3d24310..6bb07b33932 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -282,97 +282,136 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -/* - * Configuration handlers. - */ -static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, - __le32 *mac) +#ifdef CONFIG_RT2500USB_LEDS +static void rt2500usb_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac, - (3 * sizeof(__le16))); -} + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + u16 reg; -static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, - __le32 *bssid) -{ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid, - (3 * sizeof(__le16))); + rt2500usb_register_read(led->rt2x00dev, MAC_CSR20, ®); + + if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) + rt2x00_set_field16(®, MAC_CSR20_LINK, enabled); + else if (led->type == LED_TYPE_ACTIVITY) + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, enabled); + + rt2500usb_register_write(led->rt2x00dev, MAC_CSR20, reg); } -static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +static int rt2500usb_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); u16 reg; - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_read(led->rt2x00dev, MAC_CSR21, ®); + rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, *delay_on); + rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, *delay_off); + rt2500usb_register_write(led->rt2x00dev, MAC_CSR21, reg); - /* - * 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); + return 0; +} +#endif /* CONFIG_RT2500USB_LEDS */ + +/* + * Configuration handlers. + */ +static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) +{ + u16 reg; /* - * Enable synchronisation. + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. */ - 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, - (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); + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, + !(filter_flags & FIF_PROMISC_IN_BSS) && + !rt2x00dev->intf_ap_count); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); } -static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +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; - /* - * When in atomic context, reschedule and let rt2x00lib - * call this function again. - */ - if (in_atomic()) { - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); - return; + if (flags & CONFIG_UPDATE_TYPE) { + /* + * 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); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); + 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_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) +{ + u16 reg; + rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); - rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout); rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, - !!short_preamble); + !!erp->short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); } static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode, const int basic_rate_mask) { rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask); - - if (phymode == HWMODE_B) { - rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b); - rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040); - } else { - rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005); - rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c); - } } static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, @@ -424,6 +463,13 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, u16 csr5; u16 csr6; + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + rt2500usb_bbp_read(rt2x00dev, 2, &r2); rt2500usb_bbp_read(rt2x00dev, 14, &r14); rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5); @@ -443,14 +489,8 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0); rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2); rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2); @@ -467,14 +507,8 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, case ANTENNA_A: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); break; } @@ -510,6 +544,8 @@ static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, u16 reg; rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time); + rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs); rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, @@ -518,12 +554,11 @@ 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, - libconf->basic_rates); + rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) rt2500usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); @@ -537,36 +572,6 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, } /* - * LED functions. - */ -static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev) -{ - u16 reg; - - rt2500usb_register_read(rt2x00dev, MAC_CSR21, ®); - rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, 70); - rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, 30); - rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg); - - rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); - rt2x00_set_field16(®, MAC_CSR20_LINK, - (rt2x00dev->led_mode != LED_MODE_ASUS)); - rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, - (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); - rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); -} - -static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev) -{ - u16 reg; - - rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); - rt2x00_set_field16(®, MAC_CSR20_LINK, 0); - rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); - rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); -} - -/* * Link tuning */ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev, @@ -626,6 +631,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 +674,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 +708,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 +718,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) { @@ -878,19 +898,15 @@ continue_csr_init: rt2500usb_bbp_write(rt2x00dev, 62, 0x10); rt2500usb_bbp_write(rt2x00dev, 75, 0xff); - DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); for (i = 0; i < EEPROM_BBP_SIZE; i++) { rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", - reg_id, value); rt2500usb_bbp_write(rt2x00dev, reg_id, value); } } - DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); return 0; } @@ -920,21 +936,11 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev) return -EIO; } - /* - * Enable LED - */ - rt2500usb_enable_led(rt2x00dev); - return 0; } static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - /* - * Disable LED - */ - rt2500usb_disable_led(rt2x00dev); - rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121); rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121); @@ -1027,10 +1033,10 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txdata_entry_desc *desc, + struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { - struct skb_desc *skbdesc = get_skb_desc(skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; u32 word; @@ -1039,31 +1045,31 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ rt2x00_desc_read(txd, 1, &word); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs); - rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); - rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); - rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, - test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - test_bit(ENTRY_TXD_ACK, &desc->flags)); + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, - test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, - test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); - rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); @@ -1088,15 +1094,17 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - unsigned int queue) + const unsigned int queue) { u16 reg; - if (queue != IEEE80211_TX_QUEUE_BEACON) + if (queue != RT2X00_BCN_QUEUE_BEACON) return; rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); /* * Beacon generation will fail initially. @@ -1114,42 +1122,68 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static void rt2500usb_fill_rxdone(struct data_entry *entry, - struct rxdata_entry_desc *desc) +static void rt2500usb_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) { - struct skb_desc *skbdesc = get_skb_desc(entry->skb); - struct urb *urb = entry->priv; - __le32 *rxd = (__le32 *)(entry->skb->data + - (urb->actual_length - entry->ring->desc_size)); + struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *rxd = + (__le32 *)(entry->skb->data + + (priv_rx->urb->actual_length - entry->queue->desc_size)); + unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; + /* + * Copy descriptor to the available headroom inside the skbuffer. + */ + skb_push(entry->skb, offset); + memcpy(entry->skb->data, rxd, entry->queue->desc_size); + rxd = (__le32 *)entry->skb->data; + + /* + * The descriptor is now aligned to 4 bytes and thus it is + * now safe to read it on all architectures. + */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - desc->flags = 0; + rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) - desc->flags |= RX_FLAG_FAILED_FCS_CRC; + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - desc->flags |= RX_FLAG_FAILED_PLCP_CRC; + rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 100kbit/s. + */ + rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + entry->queue->rt2x00dev->rssi_offset; + rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + rxdesc->dev_flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_OFDM)) + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; + + /* + * Adjust the skb memory window to the frame boundaries. */ - desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - - entry->ring->rt2x00dev->rssi_offset; - desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); + skb_pull(entry->skb, offset); + skb_trim(entry->skb, rxdesc->size); /* * Set descriptor and data pointer. */ - skbdesc->desc = entry->skb->data + desc->size; - skbdesc->desc_len = entry->ring->desc_size; skbdesc->data = entry->skb->data; - skbdesc->data_len = desc->size; + skbdesc->data_len = rxdesc->size; + skbdesc->desc = rxd; + skbdesc->desc_len = entry->queue->desc_size; } /* @@ -1157,10 +1191,10 @@ static void rt2500usb_fill_rxdone(struct data_entry *entry, */ static void rt2500usb_beacondone(struct urb *urb) { - struct data_entry *entry = (struct data_entry *)urb->context; - struct data_ring *ring = entry->ring; + struct queue_entry *entry = (struct queue_entry *)urb->context; + struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data; - if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) + if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; /* @@ -1169,18 +1203,11 @@ static void rt2500usb_beacondone(struct urb *urb) * Otherwise we should free the sk_buffer, the device * should be doing the rest of the work now. */ - if (ring->index == 1) { - rt2x00_ring_index_done_inc(ring); - entry = rt2x00_get_data_entry(ring); - usb_submit_urb(entry->priv, GFP_ATOMIC); - rt2x00_ring_index_inc(ring); - } else if (ring->index_done == 1) { - entry = rt2x00_get_data_entry_done(ring); - if (entry->skb) { - dev_kfree_skb(entry->skb); - entry->skb = NULL; - } - rt2x00_ring_index_done_inc(ring); + if (priv_bcn->guardian_urb == urb) { + usb_submit_urb(priv_bcn->urb, GFP_ATOMIC); + } else if (priv_bcn->urb == urb) { + dev_kfree_skb(entry->skb); + entry->skb = NULL; } } @@ -1191,6 +1218,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; u8 *mac; + u8 bbp; rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); @@ -1245,9 +1273,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); } @@ -1258,6 +1294,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); @@ -1342,8 +1381,27 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ - rt2x00dev->led_mode = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); +#ifdef CONFIG_RT2500USB_LEDS + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + rt2x00dev->led_radio.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_RADIO; + rt2x00dev->led_radio.led_dev.brightness_set = + rt2500usb_brightness_set; + rt2x00dev->led_radio.led_dev.blink_set = + rt2500usb_blink_set; + rt2x00dev->led_radio.flags = LED_INITIALIZED; + + if (value == LED_MODE_TXRX_ACTIVITY) { + rt2x00dev->led_qual.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_ACTIVITY; + rt2x00dev->led_qual.led_dev.brightness_set = + rt2500usb_brightness_set; + rt2x00dev->led_qual.led_dev.blink_set = + rt2500usb_blink_set; + rt2x00dev->led_qual.flags = LED_INITIALIZED; + } +#endif /* CONFIG_RT2500USB_LEDS */ /* * Check if the BBP tuning should be disabled. @@ -1550,8 +1608,8 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->num_modes = 2; - spec->num_rates = 12; + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; spec->tx_power_a = NULL; spec->tx_power_bg = txpower; spec->tx_power_default = DEFAULT_TXPOWER; @@ -1572,9 +1630,9 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); spec->channels = rf_vals_bg_2525e; } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; - spec->num_modes = 3; } } @@ -1599,9 +1657,11 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt2500usb_probe_hw_mode(rt2x00dev); /* - * This device requires the beacon ring + * This device requires the atim queue */ - __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1614,125 +1674,58 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static void rt2500usb_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u16 reg; - - /* - * Mask off any flags we are going to ignore from - * the total_flags field. - */ - *total_flags &= - FIF_ALLMULTI | - FIF_FCSFAIL | - FIF_PLCPFAIL | - FIF_CONTROL | - FIF_OTHER_BSS | - FIF_PROMISC_IN_BSS; - - /* - * Apply some rules to the filters: - * - Some filters imply different filters to be set. - * - Some things we can't filter out at all. - */ - if (mc_count) - *total_flags |= FIF_ALLMULTI; - if (*total_flags & FIF_OTHER_BSS || - *total_flags & FIF_PROMISC_IN_BSS) - *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - - /* - * Check if there is any work left for us. - */ - if (rt2x00dev->packet_filter == *total_flags) - return; - rt2x00dev->packet_filter = *total_flags; - - /* - * When in atomic context, reschedule and let rt2x00lib - * call this function again. - */ - if (in_atomic()) { - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); - return; - } - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * and broadcast frames will always be accepted since - * there is no filter for it at this time. - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, - !(*total_flags & FIF_FCSFAIL)); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, - !(*total_flags & FIF_PLCPFAIL)); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, - !(*total_flags & FIF_CONTROL)); - rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, - !(*total_flags & FIF_ALLMULTI)); - rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0); - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); -} - static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - struct skb_desc *desc; - struct data_ring *ring; - struct data_entry *beacon; - struct data_entry *guardian; + 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; int pipe = usb_sndbulkpipe(usb_dev, 1); int length; + u16 reg; + + if (unlikely(!intf->beacon)) + return -ENOBUFS; + + priv_bcn = intf->beacon->priv_data; /* - * Just in case the ieee80211 doesn't set this, - * but we need this queue set for the descriptor - * initialization. + * Add the descriptor in front of the skb. */ - control->queue = IEEE80211_TX_QUEUE_BEACON; - ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + skb_push(skb, intf->beacon->queue->desc_size); + memset(skb->data, 0, intf->beacon->queue->desc_size); /* - * Obtain 2 entries, one for the guardian byte, - * the second for the actual beacon. + * Fill in skb descriptor */ - guardian = rt2x00_get_data_entry(ring); - rt2x00_ring_index_inc(ring); - beacon = rt2x00_get_data_entry(ring); + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; + 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 = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; /* - * Add the descriptor in front of the skb. + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. */ - skb_push(skb, ring->desc_size); - memset(skb->data, 0, ring->desc_size); + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); + rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); /* - * Fill in skb descriptor + * mac80211 doesn't provide the control->queue variable + * for beacons. Set our own queue identification so + * it can be used during descriptor initialization. */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len - ring->desc_size; - desc->desc = skb->data; - desc->data = skb->data + ring->desc_size; - desc->ring = ring; - desc->entry = beacon; - + control->queue = RT2X00_BCN_QUEUE_BEACON; rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* @@ -1742,27 +1735,29 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, */ length = rt2500usb_get_tx_data_len(rt2x00dev, skb); - usb_fill_bulk_urb(beacon->priv, usb_dev, pipe, - skb->data, length, rt2500usb_beacondone, beacon); + usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe, + skb->data, length, rt2500usb_beacondone, + intf->beacon); /* * Second we need to create the guardian byte. * We only need a single byte, so lets recycle * the 'flags' field we are not using for beacons. */ - guardian->flags = 0; - usb_fill_bulk_urb(guardian->priv, usb_dev, pipe, - &guardian->flags, 1, rt2500usb_beacondone, guardian); + priv_bcn->guardian_data = 0; + usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe, + &priv_bcn->guardian_data, 1, rt2500usb_beacondone, + intf->beacon); /* * Send out the guardian byte. */ - usb_submit_urb(guardian->priv, GFP_ATOMIC); + usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC); /* * Enable beacon generation. */ - rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + rt2500usb_kick_tx_queue(rt2x00dev, control->queue); return 0; } @@ -1775,7 +1770,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .configure_filter = rt2500usb_configure_filter, + .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, @@ -1798,19 +1793,50 @@ 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_preamble = rt2500usb_config_preamble, + .config_filter = rt2500usb_config_filter, + .config_intf = rt2500usb_config_intf, + .config_erp = rt2500usb_config_erp, .config = rt2500usb_config, }; +static const struct data_queue_desc rt2500usb_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = RXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_rx), +}; + +static const struct data_queue_desc rt2500usb_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_tx), +}; + +static const struct data_queue_desc rt2500usb_queue_bcn = { + .entry_num = BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_bcn), +}; + +static const struct data_queue_desc rt2500usb_queue_atim = { + .entry_num = ATIM_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_tx), +}; + static const struct rt2x00_ops rt2500usb_ops = { .name = KBUILD_MODNAME, - .rxd_size = RXD_DESC_SIZE, - .txd_size = TXD_DESC_SIZE, + .max_sta_intf = 1, + .max_ap_intf = 1, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .rx = &rt2500usb_queue_rx, + .tx = &rt2500usb_queue_tx, + .bcn = &rt2500usb_queue_bcn, + .atim = &rt2500usb_queue_atim, .lib = &rt2500usb_rt2x00_ops, .hw = &rt2500usb_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 9e0433722e3..a37a068d0c7 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -135,7 +135,7 @@ * Misc MAC_CSR registers. * MAC_CSR9: Timer control. * MAC_CSR10: Slot time. - * MAC_CSR11: IFS. + * MAC_CSR11: SIFS. * MAC_CSR12: EIFS. * MAC_CSR13: Power mode0. * MAC_CSR14: Power mode1. @@ -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. @@ -786,8 +787,8 @@ #define RXD_W3_EIV FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to dscape value - * and from dscape value to register value. + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 #define MAX_TXPOWER 31 diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6c725422af5..57bdc153952 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -27,23 +27,24 @@ #define RT2X00_H #include <linux/bitops.h> -#include <linux/prefetch.h> #include <linux/skbuff.h> #include <linux/workqueue.h> #include <linux/firmware.h> +#include <linux/leds.h> #include <linux/mutex.h> #include <linux/etherdevice.h> #include <net/mac80211.h> #include "rt2x00debug.h" +#include "rt2x00leds.h" #include "rt2x00reg.h" -#include "rt2x00ring.h" +#include "rt2x00queue.h" /* * Module information. */ -#define DRV_VERSION "2.0.14" +#define DRV_VERSION "2.1.4" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -91,26 +92,6 @@ DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args) /* - * Ring sizes. - * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes. - * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings. - * MGMT_FRAME_SIZE is used for the BEACON ring. - */ -#define DATA_FRAME_SIZE 2432 -#define MGMT_FRAME_SIZE 256 - -/* - * Number of entries in a packet ring. - * PCI devices only need 1 Beacon entry, - * but USB devices require a second because they - * have to send a Guardian byte first. - */ -#define RX_ENTRIES 12 -#define TX_ENTRIES 12 -#define ATIM_ENTRIES 1 -#define BEACON_ENTRIES 2 - -/* * Standard timing and size defines. * These values should follow the ieee80211 specifications. */ @@ -364,20 +345,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. @@ -388,42 +371,60 @@ 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; + + /* + * Actions that needed rescheduling. + */ + unsigned int delayed_flags; +#define DELAYED_UPDATE_BEACON 0x00000001 +#define DELAYED_CONFIG_ERP 0x00000002 +#define DELAYED_LED_ASSOC 0x00000004 +}; -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; } -/* +/** + * struct hw_mode_spec: Hardware specifications structure + * * Details about the supported modes, rates and channels * of a particular chipset. This is used by rt2x00lib * to build the ieee80211_hw_mode array for mac80211. + * + * @supported_bands: Bitmask contained the supported bands (2.4GHz, 5.2GHz). + * @supported_rates: Rate types which are supported (CCK, OFDM). + * @num_channels: Number of supported channels. This is used as array size + * for @tx_power_a, @tx_power_bg and @channels. + * channels: Device/chipset specific channel values (See &struct rf_channel). + * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL). + * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL). + * @tx_power_default: Default TX power value to use when either + * @tx_power_a or @tx_power_bg is missing. */ struct hw_mode_spec { - /* - * Number of modes, rates and channels. - */ - int num_modes; - int num_rates; - int num_channels; + unsigned int supported_bands; +#define SUPPORT_BAND_2GHZ 0x00000001 +#define SUPPORT_BAND_5GHZ 0x00000002 + + unsigned int supported_rates; +#define SUPPORT_RATE_CCK 0x00000001 +#define SUPPORT_RATE_OFDM 0x00000002 + + unsigned int num_channels; + const struct rf_channel *channels; - /* - * txpower values. - */ const u8 *tx_power_a; const u8 *tx_power_bg; u8 tx_power_default; - - /* - * Device/chipset specific value. - */ - const struct rf_channel *channels; }; /* @@ -439,10 +440,10 @@ struct rt2x00lib_conf { struct antenna_setup ant; - int phymode; + enum ieee80211_band band; - int basic_rates; - int slot_time; + u32 basic_rates; + u32 slot_time; short sifs; short pifs; @@ -451,6 +452,47 @@ struct rt2x00lib_conf { }; /* + * Configuration structure for erp settings. + */ +struct rt2x00lib_erp { + int short_preamble; + + int ack_timeout; + int ack_consume_time; +}; + +/* + * 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 { @@ -464,6 +506,7 @@ struct rt2x00lib_ops { */ int (*probe_hw) (struct rt2x00_dev *rt2x00dev); char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev); + u16 (*get_firmware_crc) (void *data, const size_t len); int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data, const size_t len); @@ -474,12 +517,12 @@ struct rt2x00lib_ops { void (*uninitialize) (struct rt2x00_dev *rt2x00dev); /* - * Ring initialization handlers + * queue initialization handlers */ void (*init_rxentry) (struct rt2x00_dev *rt2x00dev, - struct data_entry *entry); + struct queue_entry *entry); void (*init_txentry) (struct rt2x00_dev *rt2x00dev, - struct data_entry *entry); + struct queue_entry *entry); /* * Radio control handlers. @@ -497,35 +540,40 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txdata_entry_desc *desc, + struct txentry_desc *txdesc, struct ieee80211_tx_control *control); int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *skb, + struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control); int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, - unsigned int queue); + const unsigned int queue); /* * RX control handlers */ - void (*fill_rxdone) (struct data_entry *entry, - struct rxdata_entry_desc *desc); + void (*fill_rxdone) (struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc); /* * 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_filter) (struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags); + 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 ) + + void (*config_erp) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp); + 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 ) @@ -540,10 +588,14 @@ struct rt2x00lib_ops { */ struct rt2x00_ops { const char *name; - const unsigned int rxd_size; - const unsigned int txd_size; + 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; + const struct data_queue_desc *tx; + const struct data_queue_desc *bcn; + const struct data_queue_desc *atim; const struct rt2x00lib_ops *lib; const struct ieee80211_ops *hw; #ifdef CONFIG_RT2X00_LIB_DEBUGFS @@ -569,8 +621,11 @@ enum rt2x00_flags { /* * Driver features */ + DRIVER_SUPPORT_MIXED_INTERFACES, DRIVER_REQUIRE_FIRMWARE, - DRIVER_REQUIRE_BEACON_RING, + DRIVER_REQUIRE_BEACON_GUARD, + DRIVER_REQUIRE_ATIM_QUEUE, + DRIVER_REQUIRE_SCHEDULED, /* * Driver configuration @@ -582,7 +637,6 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, - CONFIG_SHORT_PREAMBLE, }; /* @@ -597,8 +651,10 @@ struct rt2x00_dev { * macro's should be used for correct typecasting. */ void *dev; -#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev ) -#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev ) +#define rt2x00dev_pci(__dev) ( (struct pci_dev *)(__dev)->dev ) +#define rt2x00dev_usb(__dev) ( (struct usb_interface *)(__dev)->dev ) +#define rt2x00dev_usb_dev(__dev)\ + ( (struct usb_device *)interface_to_usbdev(rt2x00dev_usb(__dev)) ) /* * Callback functions. @@ -609,18 +665,15 @@ struct rt2x00_dev { * IEEE80211 control structure. */ struct ieee80211_hw *hw; - struct ieee80211_hw_mode *hwmodes; - unsigned int curr_hwmode; -#define HWMODE_B 0 -#define HWMODE_G 1 -#define HWMODE_A 2 + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + enum ieee80211_band curr_band; /* * rfkill structure for RF state switching support. * This will only be compiled in when required. */ #ifdef CONFIG_RT2X00_LIB_RFKILL -unsigned long rfkill_state; + unsigned long rfkill_state; #define RFKILL_STATE_ALLOCATED 1 #define RFKILL_STATE_REGISTERED 2 struct rfkill *rfkill; @@ -636,6 +689,17 @@ unsigned long rfkill_state; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ /* + * LED structure for changing the LED status + * by mac8011 or the kernel. + */ +#ifdef CONFIG_RT2X00_LIB_LEDS + struct rt2x00_led led_radio; + struct rt2x00_led led_assoc; + struct rt2x00_led led_qual; + u16 led_mcu_reg; +#endif /* CONFIG_RT2X00_LIB_LEDS */ + + /* * Device flags. * In these flags the current status and some * of the device capabilities are stored. @@ -661,11 +725,13 @@ unsigned long rfkill_state; /* * Register pointers - * csr_addr: Base register address. (PCI) - * csr_cache: CSR cache for usb_control_msg. (USB) + * csr.base: CSR base register address. (PCI) + * csr.cache: CSR cache for usb_control_msg. (USB) */ - void __iomem *csr_addr; - void *csr_cache; + union csr { + void __iomem *base; + void *cache; + } csr; /* * Mutex to protect register accesses on USB devices. @@ -687,9 +753,14 @@ unsigned long rfkill_state; 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 @@ -722,16 +793,6 @@ unsigned long rfkill_state; u16 tx_power; /* - * LED register (for rt61pci & rt73usb). - */ - u16 led_reg; - - /* - * Led mode (LED_MODE_*) - */ - u8 led_mode; - - /* * Rssi <-> Dbm offset */ u8 rssi_offset; @@ -755,19 +816,18 @@ unsigned long rfkill_state; /* * Scheduled work. */ - struct work_struct beacon_work; + struct work_struct intf_work; struct work_struct filter_work; - struct work_struct config_work; /* - * Data ring arrays for RX, TX and Beacon. - * The Beacon array also contains the Atim ring + * Data queue arrays for RX, TX and Beacon. + * The Beacon array also contains the Atim queue * if that is supported by the device. */ - int data_rings; - struct data_ring *rx; - struct data_ring *tx; - struct data_ring *bcn; + int data_queues; + struct data_queue *rx; + struct data_queue *tx; + struct data_queue *bcn; /* * Firmware image. @@ -776,37 +836,6 @@ unsigned long rfkill_state; }; /* - * For-each loop for the ring array. - * All rings have been allocated as a single array, - * this means we can create a very simply loop macro - * that is capable of looping through all rings. - * ring_end(), txring_end() and ring_loop() are helper macro's which - * should not be used directly. Instead the following should be used: - * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim) - * txring_for_each() - Loops through TX data rings (TX only) - * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim) - */ -#define ring_end(__dev) \ - &(__dev)->rx[(__dev)->data_rings] - -#define txring_end(__dev) \ - &(__dev)->tx[(__dev)->hw->queues] - -#define ring_loop(__entry, __start, __end) \ - for ((__entry) = (__start); \ - prefetch(&(__entry)[1]), (__entry) != (__end); \ - (__entry) = &(__entry)[1]) - -#define ring_for_each(__dev, __entry) \ - ring_loop(__entry, (__dev)->rx, ring_end(__dev)) - -#define txring_for_each(__dev, __entry) \ - ring_loop(__entry, (__dev)->tx, txring_end(__dev)) - -#define txringall_for_each(__dev, __entry) \ - ring_loop(__entry, (__dev)->tx, ring_end(__dev)) - -/* * Generic RF access. * The RF is being accessed by word index. */ @@ -898,20 +927,43 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate) return ((size * 8 * 10) % rate); } -/* - * Library functions. +/** + * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @queue: mac80211/rt2x00 queue index + * (see &enum ieee80211_tx_queue and &enum rt2x00_bcn_queue). + */ +struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, + const unsigned int queue); + +/** + * rt2x00queue_get_entry - Get queue entry where the given index points to. + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @index: Index identifier for obtaining the correct index. + */ +struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, + enum queue_index index); + +/** + * rt2x00queue_index_inc - Index incrementation function + * @queue: Queue (&struct data_queue) to perform the action on. + * @action: Index type (&enum queue_index) to perform the action on. + * + * This function will increase the requested index on the queue, + * it will grab the appropriate locks and handle queue overflow events by + * resetting the index to the start of the queue. */ -struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, - const unsigned int queue); +void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); + /* * Interrupt context handlers. */ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); -void rt2x00lib_txdone(struct data_entry *entry, - const int status, const int retry); -void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - struct rxdata_entry_desc *desc); +void rt2x00lib_txdone(struct queue_entry *entry, + struct txdone_entry_desc *txdesc); +void rt2x00lib_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc); /* * TX descriptor initializer @@ -935,6 +987,10 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); +void rt2x00mac_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list); int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 07adc576db4..a9930a03f45 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -29,64 +29,78 @@ #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) -{ - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - if (mac) - memcpy(®, mac, ETH_ALEN); - - rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, ®[0]); -} - -void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + enum ieee80211_if_types type, + u8 *mac, u8 *bssid) { - __le32 reg[2]; + struct rt2x00intf_conf conf; + unsigned int flags = 0; - 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_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct ieee80211_bss_conf *bss_conf) +{ + struct rt2x00lib_erp erp; + + memset(&erp, 0, sizeof(erp)); + + erp.short_preamble = bss_conf->use_short_preamble; + erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10); + erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); + + if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) + erp.ack_timeout += SHORT_DIFS; + else + erp.ack_timeout += DIFS; + + if (bss_conf->use_short_preamble) { + erp.ack_timeout += SHORT_PREAMBLE; + erp.ack_consume_time += SHORT_PREAMBLE; + } else { + erp.ack_timeout += PREAMBLE; + erp.ack_consume_time += PREAMBLE; + } + + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, @@ -113,7 +127,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; @@ -123,12 +137,26 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); } +static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band) +{ + const struct rt2x00_rate *rate; + unsigned int i; + u32 mask = 0; + + for (i = 0; i < band->n_bitrates; i++) { + rate = rt2x00_get_rate(band->bitrates[i].hw_value); + if (rate->flags & DEV_RATE_BASIC) + mask |= rate->ratemask; + } + + return mask; +} + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config) { struct rt2x00lib_conf libconf; - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; + struct ieee80211_supported_band *band; struct antenna_setup *default_ant = &rt2x00dev->default_ant; struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; int flags = 0; @@ -147,9 +175,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, * Check which configuration options have been * updated and should be send to the device. */ - if (rt2x00dev->rx_status.phymode != conf->phymode) + if (rt2x00dev->rx_status.band != conf->channel->band) flags |= CONFIG_UPDATE_PHYMODE; - if (rt2x00dev->rx_status.channel != conf->channel) + if (rt2x00dev->rx_status.freq != conf->channel->center_freq) flags |= CONFIG_UPDATE_CHANNEL; if (rt2x00dev->tx_power != conf->power_level) flags |= CONFIG_UPDATE_TXPOWER; @@ -204,33 +232,15 @@ config: memset(&libconf, 0, sizeof(libconf)); if (flags & CONFIG_UPDATE_PHYMODE) { - switch (conf->phymode) { - case MODE_IEEE80211A: - libconf.phymode = HWMODE_A; - break; - case MODE_IEEE80211B: - libconf.phymode = HWMODE_B; - break; - case MODE_IEEE80211G: - libconf.phymode = HWMODE_G; - break; - default: - ERROR(rt2x00dev, - "Attempt to configure unsupported mode (%d)" - "Defaulting to 802.11b", conf->phymode); - libconf.phymode = HWMODE_B; - } - - mode = &rt2x00dev->hwmodes[libconf.phymode]; - rate = &mode->rates[mode->num_rates - 1]; - - libconf.basic_rates = - DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK; + band = &rt2x00dev->bands[conf->channel->band]; + + libconf.band = conf->channel->band; + libconf.basic_rates = rt2x00lib_get_basic_rates(band); } if (flags & CONFIG_UPDATE_CHANNEL) { memcpy(&libconf.rf, - &rt2x00dev->spec.channels[conf->channel_val], + &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); } @@ -266,7 +276,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 @@ -276,12 +286,11 @@ config: rt2x00lib_reset_link_tuner(rt2x00dev); if (flags & CONFIG_UPDATE_PHYMODE) { - rt2x00dev->curr_hwmode = libconf.phymode; - rt2x00dev->rx_status.phymode = conf->phymode; + rt2x00dev->curr_band = conf->channel->band; + rt2x00dev->rx_status.band = conf->channel->band; } - rt2x00dev->rx_status.freq = conf->freq; - rt2x00dev->rx_status.channel = conf->channel; + rt2x00dev->rx_status.freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; if (flags & CONFIG_UPDATE_ANTENNA) { diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index b44a9f4b9b7..bfab3b8780d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -33,7 +33,7 @@ #include "rt2x00lib.h" #include "rt2x00dump.h" -#define PRINT_LINE_LEN_MAX 32 +#define MAX_LINE_LENGTH 64 struct rt2x00debug_intf { /* @@ -60,8 +60,9 @@ struct rt2x00debug_intf { * - eeprom offset/value files * - bbp offset/value files * - rf offset/value files - * - frame dump folder + * - queue folder * - frame dump file + * - queue stats file */ struct dentry *driver_folder; struct dentry *driver_entry; @@ -76,8 +77,9 @@ struct rt2x00debug_intf { struct dentry *bbp_val_entry; struct dentry *rf_off_entry; struct dentry *rf_val_entry; - struct dentry *frame_folder; - struct dentry *frame_dump_entry; + struct dentry *queue_folder; + struct dentry *queue_frame_dump_entry; + struct dentry *queue_stats_entry; /* * The frame dump file only allows a single reader, @@ -116,7 +118,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; - struct skb_desc *desc = get_skb_desc(skb); + struct skb_frame_desc *desc = get_skb_frame_desc(skb); struct sk_buff *skbcopy; struct rt2x00dump_hdr *dump_hdr; struct timeval timestamp; @@ -147,7 +149,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); dump_hdr->type = cpu_to_le16(desc->frame_type); - dump_hdr->ring_index = desc->ring->queue_idx; + dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->entry_index = desc->entry->entry_idx; dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec); dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec); @@ -186,7 +188,7 @@ static int rt2x00debug_file_release(struct inode *inode, struct file *file) return 0; } -static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file) +static int rt2x00debug_open_queue_dump(struct inode *inode, struct file *file) { struct rt2x00debug_intf *intf = inode->i_private; int retval; @@ -203,7 +205,7 @@ static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file) return 0; } -static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file) +static int rt2x00debug_release_queue_dump(struct inode *inode, struct file *file) { struct rt2x00debug_intf *intf = inode->i_private; @@ -214,10 +216,10 @@ static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file) return rt2x00debug_file_release(inode, file); } -static ssize_t rt2x00debug_read_ring_dump(struct file *file, - char __user *buf, - size_t length, - loff_t *offset) +static ssize_t rt2x00debug_read_queue_dump(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) { struct rt2x00debug_intf *intf = file->private_data; struct sk_buff *skb; @@ -248,8 +250,8 @@ exit: return status; } -static unsigned int rt2x00debug_poll_ring_dump(struct file *file, - poll_table *wait) +static unsigned int rt2x00debug_poll_queue_dump(struct file *file, + poll_table *wait) { struct rt2x00debug_intf *intf = file->private_data; @@ -261,12 +263,68 @@ static unsigned int rt2x00debug_poll_ring_dump(struct file *file, return 0; } -static const struct file_operations rt2x00debug_fop_ring_dump = { +static const struct file_operations rt2x00debug_fop_queue_dump = { .owner = THIS_MODULE, - .read = rt2x00debug_read_ring_dump, - .poll = rt2x00debug_poll_ring_dump, - .open = rt2x00debug_open_ring_dump, - .release = rt2x00debug_release_ring_dump, + .read = rt2x00debug_read_queue_dump, + .poll = rt2x00debug_poll_queue_dump, + .open = rt2x00debug_open_queue_dump, + .release = rt2x00debug_release_queue_dump, +}; + +static ssize_t rt2x00debug_read_queue_stats(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + struct data_queue *queue; + unsigned long irqflags; + unsigned int lines = 1 + intf->rt2x00dev->data_queues; + size_t size; + char *data; + char *temp; + + if (*offset) + return 0; + + data = kzalloc(lines * MAX_LINE_LENGTH, GFP_KERNEL); + if (!data) + return -ENOMEM; + + temp = data + + sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n"); + + queue_for_each(intf->rt2x00dev, queue) { + spin_lock_irqsave(&queue->lock, irqflags); + + temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, + queue->count, queue->limit, queue->length, + queue->index[Q_INDEX], + queue->index[Q_INDEX_DONE], + queue->index[Q_INDEX_CRYPTO]); + + spin_unlock_irqrestore(&queue->lock, irqflags); + } + + size = strlen(data); + size = min(size, length); + + if (copy_to_user(buf, data, size)) { + kfree(data); + return -EFAULT; + } + + kfree(data); + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_queue_stats = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_queue_stats, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, }; #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ @@ -386,7 +444,7 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, { char *data; - data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return NULL; @@ -409,7 +467,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, const struct rt2x00debug *debug = intf->debug; char *data; - data = kzalloc(8 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + data = kzalloc(8 * MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return NULL; @@ -496,20 +554,24 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) #undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY - intf->frame_folder = - debugfs_create_dir("frame", intf->driver_folder); - if (IS_ERR(intf->frame_folder)) + intf->queue_folder = + debugfs_create_dir("queue", intf->driver_folder); + if (IS_ERR(intf->queue_folder)) goto exit; - intf->frame_dump_entry = - debugfs_create_file("dump", S_IRUGO, intf->frame_folder, - intf, &rt2x00debug_fop_ring_dump); - if (IS_ERR(intf->frame_dump_entry)) + intf->queue_frame_dump_entry = + debugfs_create_file("dump", S_IRUGO, intf->queue_folder, + intf, &rt2x00debug_fop_queue_dump); + if (IS_ERR(intf->queue_frame_dump_entry)) goto exit; skb_queue_head_init(&intf->frame_dump_skbqueue); init_waitqueue_head(&intf->frame_dump_waitqueue); + intf->queue_stats_entry = + debugfs_create_file("queue", S_IRUGO, intf->queue_folder, + intf, &rt2x00debug_fop_queue_stats); + return; exit: @@ -528,8 +590,9 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) skb_queue_purge(&intf->frame_dump_skbqueue); - debugfs_remove(intf->frame_dump_entry); - debugfs_remove(intf->frame_folder); + debugfs_remove(intf->queue_stats_entry); + debugfs_remove(intf->queue_frame_dump_entry); + debugfs_remove(intf->queue_folder); debugfs_remove(intf->rf_val_entry); debugfs_remove(intf->rf_off_entry); debugfs_remove(intf->bbp_val_entry); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index d37efbd09c4..c4ce895aa1c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e873a39fcce..0361524d193 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -31,34 +31,6 @@ #include "rt2x00dump.h" /* - * Ring handler. - */ -struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, - const unsigned int queue) -{ - int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); - - /* - * Check if we are requesting a reqular TX ring, - * or if we are requesting a Beacon or Atim ring. - * For Atim rings, we should check if it is supported. - */ - if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) - return &rt2x00dev->tx[queue]; - - if (!rt2x00dev->bcn || !beacon) - return NULL; - - if (queue == IEEE80211_TX_QUEUE_BEACON) - return &rt2x00dev->bcn[0]; - else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) - return &rt2x00dev->bcn[1]; - - return NULL; -} -EXPORT_SYMBOL_GPL(rt2x00lib_get_ring); - -/* * Link tuning handlers */ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) @@ -113,46 +85,6 @@ static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) } /* - * Ring initialization - */ -static void rt2x00lib_init_rxrings(struct rt2x00_dev *rt2x00dev) -{ - struct data_ring *ring = rt2x00dev->rx; - unsigned int i; - - if (!rt2x00dev->ops->lib->init_rxentry) - return; - - if (ring->data_addr) - memset(ring->data_addr, 0, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, &ring->entry[i]); - - rt2x00_ring_index_clear(ring); -} - -static void rt2x00lib_init_txrings(struct rt2x00_dev *rt2x00dev) -{ - struct data_ring *ring; - unsigned int i; - - if (!rt2x00dev->ops->lib->init_txentry) - return; - - txringall_for_each(rt2x00dev, ring) { - if (ring->data_addr) - memset(ring->data_addr, 0, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) - rt2x00dev->ops->lib->init_txentry(rt2x00dev, - &ring->entry[i]); - - rt2x00_ring_index_clear(ring); - } -} - -/* * Radio control handlers. */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -168,19 +100,21 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) return 0; /* - * Initialize all data rings. + * Initialize all data queues. */ - rt2x00lib_init_rxrings(rt2x00dev); - rt2x00lib_init_txrings(rt2x00dev); + rt2x00queue_init_rx(rt2x00dev); + rt2x00queue_init_tx(rt2x00dev); /* * Enable radio. */ - status = rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_ON); + status = + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_ON); if (status) return status; + rt2x00leds_led_radio(rt2x00dev, true); + __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); /* @@ -204,12 +138,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. @@ -225,6 +157,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) * Disable radio. */ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); + rt2x00leds_led_radio(rt2x00dev, false); } void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) @@ -241,7 +174,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); } @@ -449,6 +382,11 @@ static void rt2x00lib_link_tuner(struct work_struct *work) rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual); /* + * Send a signal to the led to update the led signal strength. + */ + rt2x00leds_led_quality(rt2x00dev, rt2x00dev->link.qual.avg_rssi); + + /* * Evaluate antenna setup, make this the last step since this could * possibly reset some statistics. */ @@ -466,59 +404,78 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, filter_work); - unsigned int filter = rt2x00dev->packet_filter; + + rt2x00dev->ops->lib->config_filter(rt2x00dev, rt2x00dev->packet_filter); +} + +static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + 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; /* - * Since we had stored the filter inside interface.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). + * 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. */ - rt2x00dev->packet_filter = 0; + 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_ERP) + rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf); - rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, - filter, &filter, 0, NULL); + if (delayed_flags & DELAYED_LED_ASSOC) + rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } -static void rt2x00lib_configuration_scheduled(struct work_struct *work) +static void rt2x00lib_intf_scheduled(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, config_work); - struct ieee80211_bss_conf bss_conf; - - bss_conf.use_short_preamble = - test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + 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 data_ring *ring = - rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); - struct data_entry *entry = rt2x00_get_data_entry(ring); - struct sk_buff *skb; + struct rt2x00_intf *intf = vif_to_intf(vif); - skb = ieee80211_beacon_get(rt2x00dev->hw, - rt2x00dev->interface.id, - &entry->tx_status.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, - &entry->tx_status.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) @@ -526,116 +483,140 @@ 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); -void rt2x00lib_txdone(struct data_entry *entry, - const int status, const int retry) +void rt2x00lib_txdone(struct queue_entry *entry, + struct txdone_entry_desc *txdesc) { - struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; - struct ieee80211_tx_status *tx_status = &entry->tx_status; - struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats; - int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY); - int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID || - status == TX_FAIL_OTHER); + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc; + struct ieee80211_tx_status tx_status; + int success = !!(txdesc->status == TX_SUCCESS || + txdesc->status == TX_SUCCESS_RETRY); + int fail = !!(txdesc->status == TX_FAIL_RETRY || + txdesc->status == TX_FAIL_INVALID || + txdesc->status == TX_FAIL_OTHER); /* * Update TX statistics. */ - tx_status->flags = 0; - tx_status->ack_signal = 0; - tx_status->excessive_retries = (status == TX_FAIL_RETRY); - tx_status->retry_count = retry; rt2x00dev->link.qual.tx_success += success; - rt2x00dev->link.qual.tx_failed += retry + fail; + rt2x00dev->link.qual.tx_failed += txdesc->retry + fail; + + /* + * Initialize TX status + */ + tx_status.flags = 0; + tx_status.ack_signal = 0; + tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY); + tx_status.retry_count = txdesc->retry; + memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); - if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { if (success) - tx_status->flags |= IEEE80211_TX_STATUS_ACK; + tx_status.flags |= IEEE80211_TX_STATUS_ACK; else - stats->dot11ACKFailureCount++; + rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - tx_status->queue_length = entry->ring->stats.limit; - tx_status->queue_number = tx_status->control.queue; + tx_status.queue_length = entry->queue->limit; + tx_status.queue_number = tx_status.control.queue; - if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { if (success) - stats->dot11RTSSuccessCount++; + rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else - stats->dot11RTSFailureCount++; + rt2x00dev->low_level_stats.dot11RTSFailureCount++; } /* - * Send the tx_status to mac80211 & debugfs. - * mac80211 will clean up the skb structure. + * Send the tx_status to debugfs. Only send the status report + * to mac80211 when the frame originated from there. If this was + * a extra frame coming through a mac80211 library call (RTS/CTS) + * then we should not send the status report back. + * If send to mac80211, mac80211 will clean up the skb structure, + * otherwise we have to do it ourself. */ - get_skb_desc(entry->skb)->frame_type = DUMP_FRAME_TXDONE; + skbdesc = get_skb_frame_desc(entry->skb); + skbdesc->frame_type = DUMP_FRAME_TXDONE; + rt2x00debug_dump_frame(rt2x00dev, entry->skb); - ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); + + if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED)) + ieee80211_tx_status_irqsafe(rt2x00dev->hw, + entry->skb, &tx_status); + else + dev_kfree_skb(entry->skb); entry->skb = NULL; } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); -void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - struct rxdata_entry_desc *desc) +void rt2x00lib_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) { - struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; + const struct rt2x00_rate *rate; unsigned int i; - int val = 0; + int idx = -1; u16 fc; /* * Update RX statistics. */ - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - for (i = 0; i < mode->num_rates; i++) { - rate = &mode->rates[i]; + sband = &rt2x00dev->bands[rt2x00dev->curr_band]; + for (i = 0; i < sband->n_bitrates; i++) { + rate = rt2x00_get_rate(sband->bitrates[i].hw_value); - /* - * When frame was received with an OFDM bitrate, - * the signal is the PLCP value. If it was received with - * a CCK bitrate the signal is the rate in 0.5kbit/s. - */ - if (!desc->ofdm) - val = DEVICE_GET_RATE_FIELD(rate->val, RATE); - else - val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); - - if (val == desc->signal) { - val = rate->val; + if (((rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) && + (rate->plcp == rxdesc->signal)) || + (!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP) && + (rate->bitrate == rxdesc->signal))) { + idx = i; break; } } + if (idx < 0) { + WARNING(rt2x00dev, "Frame received with unrecognized signal," + "signal=0x%.2x, plcp=%d.\n", rxdesc->signal, + !!(rxdesc->dev_flags & RXDONE_SIGNAL_PLCP)); + idx = 0; + } + /* * Only update link status if this is a beacon frame carrying our bssid. */ - hdr = (struct ieee80211_hdr*)skb->data; + hdr = (struct ieee80211_hdr *)entry->skb->data; fc = le16_to_cpu(hdr->frame_control); - if (is_beacon(fc) && desc->my_bss) - rt2x00lib_update_link_stats(&rt2x00dev->link, desc->rssi); + if (is_beacon(fc) && (rxdesc->dev_flags & RXDONE_MY_BSS)) + rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc->rssi); rt2x00dev->link.qual.rx_success++; - rx_status->rate = val; + rx_status->rate_idx = idx; rx_status->signal = - rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); - rx_status->ssi = desc->rssi; - rx_status->flag = desc->flags; + rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); + rx_status->ssi = rxdesc->rssi; + rx_status->flag = rxdesc->flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; /* - * Send frame to mac80211 & debugfs + * Send frame to mac80211 & debugfs. + * mac80211 will clean up the skb structure. */ - get_skb_desc(skb)->frame_type = DUMP_FRAME_RXDONE; - rt2x00debug_dump_frame(rt2x00dev, skb); - ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status); + get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE; + rt2x00debug_dump_frame(rt2x00dev, entry->skb); + ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); + entry->skb = NULL; } EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); @@ -646,83 +627,69 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct txdata_entry_desc desc; - struct skb_desc *skbdesc = get_skb_desc(skb); - struct ieee80211_hdr *ieee80211hdr = skbdesc->data; + struct txentry_desc txdesc; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data; + const struct rt2x00_rate *rate; int tx_rate; - int bitrate; int length; int duration; int residual; u16 frame_control; u16 seq_ctrl; - memset(&desc, 0, sizeof(desc)); - - desc.cw_min = skbdesc->ring->tx_params.cw_min; - desc.cw_max = skbdesc->ring->tx_params.cw_max; - desc.aifs = skbdesc->ring->tx_params.aifs; + memset(&txdesc, 0, sizeof(txdesc)); - /* - * Identify queue - */ - if (control->queue < rt2x00dev->hw->queues) - desc.queue = control->queue; - else if (control->queue == IEEE80211_TX_QUEUE_BEACON || - control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON) - desc.queue = QUEUE_MGMT; - else - desc.queue = QUEUE_OTHER; + txdesc.queue = skbdesc->entry->queue->qid; + txdesc.cw_min = skbdesc->entry->queue->cw_min; + txdesc.cw_max = skbdesc->entry->queue->cw_max; + txdesc.aifs = skbdesc->entry->queue->aifs; /* * Read required fields from ieee80211 header. */ - frame_control = le16_to_cpu(ieee80211hdr->frame_control); - seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl); + frame_control = le16_to_cpu(hdr->frame_control); + seq_ctrl = le16_to_cpu(hdr->seq_ctrl); - tx_rate = control->tx_rate; + tx_rate = control->tx_rate->hw_value; /* * Check whether this frame is to be acked */ if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) - __set_bit(ENTRY_TXD_ACK, &desc.flags); + __set_bit(ENTRY_TXD_ACK, &txdesc.flags); /* * Check if this is a RTS/CTS frame */ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { - __set_bit(ENTRY_TXD_BURST, &desc.flags); + __set_bit(ENTRY_TXD_BURST, &txdesc.flags); if (is_rts_frame(frame_control)) { - __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags); - __set_bit(ENTRY_TXD_ACK, &desc.flags); + __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags); + __set_bit(ENTRY_TXD_ACK, &txdesc.flags); } else - __clear_bit(ENTRY_TXD_ACK, &desc.flags); + __clear_bit(ENTRY_TXD_ACK, &txdesc.flags); if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate; + tx_rate = control->rts_cts_rate->hw_value; } - /* - * Check for OFDM - */ - if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK) - __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags); + rate = rt2x00_get_rate(tx_rate); /* * Check if more fragments are pending */ - if (ieee80211_get_morefrag(ieee80211hdr)) { - __set_bit(ENTRY_TXD_BURST, &desc.flags); - __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags); + if (ieee80211_get_morefrag(hdr)) { + __set_bit(ENTRY_TXD_BURST, &txdesc.flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags); } /* * Beacons and probe responses require the tsf timestamp * to be inserted into the frame. */ - if (control->queue == IEEE80211_TX_QUEUE_BEACON || + if (control->queue == RT2X00_BCN_QUEUE_BEACON || is_probe_resp(frame_control)) - __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags); + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags); /* * Determine with what IFS priority this frame should be send. @@ -730,30 +697,30 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, * or this fragment came after RTS/CTS. */ if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || - test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags)) - desc.ifs = IFS_SIFS; + test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) + txdesc.ifs = IFS_SIFS; else - desc.ifs = IFS_BACKOFF; + txdesc.ifs = IFS_BACKOFF; /* * PLCP setup * Length calculation depends on OFDM/CCK rate. */ - desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP); - desc.service = 0x04; + txdesc.signal = rate->plcp; + txdesc.service = 0x04; length = skbdesc->data_len + FCS_LEN; - if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) { - desc.length_high = (length >> 6) & 0x3f; - desc.length_low = length & 0x3f; - } else { - bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE); + if (rate->flags & DEV_RATE_OFDM) { + __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags); + txdesc.length_high = (length >> 6) & 0x3f; + txdesc.length_low = length & 0x3f; + } else { /* * Convert length to microseconds. */ - residual = get_duration_res(length, bitrate); - duration = get_duration(length, bitrate); + residual = get_duration_res(length, rate->bitrate); + duration = get_duration(length, rate->bitrate); if (residual != 0) { duration++; @@ -761,28 +728,27 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, /* * Check if we need to set the Length Extension */ - if (bitrate == 110 && residual <= 30) - desc.service |= 0x80; + if (rate->bitrate == 110 && residual <= 30) + txdesc.service |= 0x80; } - desc.length_high = (duration >> 8) & 0xff; - desc.length_low = duration & 0xff; + txdesc.length_high = (duration >> 8) & 0xff; + txdesc.length_low = duration & 0xff; /* * When preamble is enabled we should set the * preamble bit for the signal. */ - if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE)) - desc.signal |= 0x08; + if (rt2x00_get_rate_preamble(tx_rate)) + txdesc.signal |= 0x08; } - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &desc, control); + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control); /* - * Update ring entry. + * Update queue entry. */ skbdesc->entry->skb = skb; - memcpy(&skbdesc->entry->tx_status.control, control, sizeof(*control)); /* * The frame has been completely initialized and ready @@ -798,133 +764,167 @@ EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); /* * Driver initialization handlers. */ +const struct rt2x00_rate rt2x00_supported_rates[12] = { + { + .flags = DEV_RATE_CCK | DEV_RATE_BASIC, + .bitrate = 10, + .ratemask = BIT(0), + .plcp = 0x00, + }, + { + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .bitrate = 20, + .ratemask = BIT(1), + .plcp = 0x01, + }, + { + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .bitrate = 55, + .ratemask = BIT(2), + .plcp = 0x02, + }, + { + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .bitrate = 110, + .ratemask = BIT(3), + .plcp = 0x03, + }, + { + .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .bitrate = 60, + .ratemask = BIT(4), + .plcp = 0x0b, + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 90, + .ratemask = BIT(5), + .plcp = 0x0f, + }, + { + .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .bitrate = 120, + .ratemask = BIT(6), + .plcp = 0x0a, + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 180, + .ratemask = BIT(7), + .plcp = 0x0e, + }, + { + .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .bitrate = 240, + .ratemask = BIT(8), + .plcp = 0x09, + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 360, + .ratemask = BIT(9), + .plcp = 0x0d, + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 480, + .ratemask = BIT(10), + .plcp = 0x08, + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 540, + .ratemask = BIT(11), + .plcp = 0x0c, + }, +}; + static void rt2x00lib_channel(struct ieee80211_channel *entry, const int channel, const int tx_power, const int value) { - entry->chan = channel; - if (channel <= 14) - entry->freq = 2407 + (5 * channel); - else - entry->freq = 5000 + (5 * channel); - entry->val = value; - entry->flag = - IEEE80211_CHAN_W_IBSS | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_SCAN; - entry->power_level = tx_power; - entry->antenna_max = 0xff; + entry->center_freq = ieee80211_channel_to_frequency(channel); + entry->hw_value = value; + entry->max_power = tx_power; + entry->max_antenna_gain = 0xff; } static void rt2x00lib_rate(struct ieee80211_rate *entry, - const int rate, const int mask, - const int plcp, const int flags) + const u16 index, const struct rt2x00_rate *rate) { - entry->rate = rate; - entry->val = - DEVICE_SET_RATE_FIELD(rate, RATE) | - DEVICE_SET_RATE_FIELD(mask, RATEMASK) | - DEVICE_SET_RATE_FIELD(plcp, PLCP); - entry->flags = flags; - entry->val2 = entry->val; - if (entry->flags & IEEE80211_RATE_PREAMBLE2) - entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE); - entry->min_rssi_ack = 0; - entry->min_rssi_ack_delta = 0; + entry->flags = 0; + entry->bitrate = rate->bitrate; + entry->hw_value = rt2x00_create_rate_hw_value(index, 0); + entry->hw_value_short = entry->hw_value; + + if (rate->flags & DEV_RATE_SHORT_PREAMBLE) { + entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE; + entry->hw_value_short |= rt2x00_create_rate_hw_value(index, 1); + } } static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, struct hw_mode_spec *spec) { struct ieee80211_hw *hw = rt2x00dev->hw; - struct ieee80211_hw_mode *hwmodes; struct ieee80211_channel *channels; struct ieee80211_rate *rates; + unsigned int num_rates; unsigned int i; unsigned char tx_power; - hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL); - if (!hwmodes) - goto exit; + num_rates = 0; + if (spec->supported_rates & SUPPORT_RATE_CCK) + num_rates += 4; + if (spec->supported_rates & SUPPORT_RATE_OFDM) + num_rates += 8; channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL); if (!channels) - goto exit_free_modes; + return -ENOMEM; - rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL); + rates = kzalloc(sizeof(*rates) * num_rates, GFP_KERNEL); if (!rates) goto exit_free_channels; /* * Initialize Rate list. */ - rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB, - 0x00, IEEE80211_RATE_CCK); - rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB, - 0x01, IEEE80211_RATE_CCK_2); - rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB, - 0x02, IEEE80211_RATE_CCK_2); - rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB, - 0x03, IEEE80211_RATE_CCK_2); - - if (spec->num_rates > 4) { - rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB, - 0x0b, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB, - 0x0f, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB, - 0x0a, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB, - 0x0e, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB, - 0x09, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB, - 0x0d, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB, - 0x08, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB, - 0x0c, IEEE80211_RATE_OFDM); - } + for (i = 0; i < num_rates; i++) + rt2x00lib_rate(&rates[i], i, rt2x00_get_rate(i)); /* * Initialize Channel list. */ for (i = 0; i < spec->num_channels; i++) { - if (spec->channels[i].channel <= 14) - tx_power = spec->tx_power_bg[i]; - else if (spec->tx_power_a) - tx_power = spec->tx_power_a[i]; - else - tx_power = spec->tx_power_default; + if (spec->channels[i].channel <= 14) { + if (spec->tx_power_bg) + tx_power = spec->tx_power_bg[i]; + else + tx_power = spec->tx_power_default; + } else { + if (spec->tx_power_a) + tx_power = spec->tx_power_a[i]; + else + tx_power = spec->tx_power_default; + } rt2x00lib_channel(&channels[i], spec->channels[i].channel, tx_power, i); } /* - * Intitialize 802.11b - * Rates: CCK. - * Channels: OFDM. - */ - if (spec->num_modes > HWMODE_B) { - hwmodes[HWMODE_B].mode = MODE_IEEE80211B; - hwmodes[HWMODE_B].num_channels = 14; - hwmodes[HWMODE_B].num_rates = 4; - hwmodes[HWMODE_B].channels = channels; - hwmodes[HWMODE_B].rates = rates; - } - - /* - * Intitialize 802.11g + * Intitialize 802.11b, 802.11g * Rates: CCK, OFDM. - * Channels: OFDM. - */ - if (spec->num_modes > HWMODE_G) { - hwmodes[HWMODE_G].mode = MODE_IEEE80211G; - hwmodes[HWMODE_G].num_channels = 14; - hwmodes[HWMODE_G].num_rates = spec->num_rates; - hwmodes[HWMODE_G].channels = channels; - hwmodes[HWMODE_G].rates = rates; + * Channels: 2.4 GHz + */ + if (spec->supported_bands & SUPPORT_BAND_2GHZ) { + rt2x00dev->bands[IEEE80211_BAND_2GHZ].n_channels = 14; + rt2x00dev->bands[IEEE80211_BAND_2GHZ].n_bitrates = num_rates; + rt2x00dev->bands[IEEE80211_BAND_2GHZ].channels = channels; + rt2x00dev->bands[IEEE80211_BAND_2GHZ].bitrates = rates; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &rt2x00dev->bands[IEEE80211_BAND_2GHZ]; } /* @@ -932,40 +932,21 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, * Rates: OFDM. * Channels: OFDM, UNII, HiperLAN2. */ - if (spec->num_modes > HWMODE_A) { - hwmodes[HWMODE_A].mode = MODE_IEEE80211A; - hwmodes[HWMODE_A].num_channels = spec->num_channels - 14; - hwmodes[HWMODE_A].num_rates = spec->num_rates - 4; - hwmodes[HWMODE_A].channels = &channels[14]; - hwmodes[HWMODE_A].rates = &rates[4]; + if (spec->supported_bands & SUPPORT_BAND_5GHZ) { + rt2x00dev->bands[IEEE80211_BAND_5GHZ].n_channels = + spec->num_channels - 14; + rt2x00dev->bands[IEEE80211_BAND_5GHZ].n_bitrates = + num_rates - 4; + rt2x00dev->bands[IEEE80211_BAND_5GHZ].channels = &channels[14]; + rt2x00dev->bands[IEEE80211_BAND_5GHZ].bitrates = &rates[4]; + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &rt2x00dev->bands[IEEE80211_BAND_5GHZ]; } - if (spec->num_modes > HWMODE_G && - ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G])) - goto exit_free_rates; - - if (spec->num_modes > HWMODE_B && - ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B])) - goto exit_free_rates; - - if (spec->num_modes > HWMODE_A && - ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A])) - goto exit_free_rates; - - rt2x00dev->hwmodes = hwmodes; - return 0; -exit_free_rates: - kfree(rates); - -exit_free_channels: + exit_free_channels: kfree(channels); - -exit_free_modes: - kfree(hwmodes); - -exit: ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n"); return -ENOMEM; } @@ -975,11 +956,11 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); - if (likely(rt2x00dev->hwmodes)) { - kfree(rt2x00dev->hwmodes->channels); - kfree(rt2x00dev->hwmodes->rates); - kfree(rt2x00dev->hwmodes); - rt2x00dev->hwmodes = NULL; + if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) { + kfree(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels); + kfree(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->bitrates); + rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; } } @@ -1012,86 +993,6 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialization/uninitialization handlers. */ -static int rt2x00lib_alloc_entries(struct data_ring *ring, - const u16 max_entries, const u16 data_size, - const u16 desc_size) -{ - struct data_entry *entry; - unsigned int i; - - ring->stats.limit = max_entries; - ring->data_size = data_size; - ring->desc_size = desc_size; - - /* - * Allocate all ring entries. - */ - entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - for (i = 0; i < ring->stats.limit; i++) { - entry[i].flags = 0; - entry[i].ring = ring; - entry[i].skb = NULL; - entry[i].entry_idx = i; - } - - ring->entry = entry; - - return 0; -} - -static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev) -{ - struct data_ring *ring; - - /* - * Allocate the RX ring. - */ - if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE, - rt2x00dev->ops->rxd_size)) - return -ENOMEM; - - /* - * First allocate the TX rings. - */ - txring_for_each(rt2x00dev, ring) { - if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE, - rt2x00dev->ops->txd_size)) - return -ENOMEM; - } - - if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) - return 0; - - /* - * Allocate the BEACON ring. - */ - if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES, - MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size)) - return -ENOMEM; - - /* - * Allocate the Atim ring. - */ - if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES, - DATA_FRAME_SIZE, rt2x00dev->ops->txd_size)) - return -ENOMEM; - - return 0; -} - -static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev) -{ - struct data_ring *ring; - - ring_for_each(rt2x00dev, ring) { - kfree(ring->entry); - ring->entry = NULL; - } -} - static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) { if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) @@ -1108,9 +1009,9 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) rt2x00dev->ops->lib->uninitialize(rt2x00dev); /* - * Free allocated ring entries. + * Free allocated queue entries. */ - rt2x00lib_free_ring_entries(rt2x00dev); + rt2x00queue_uninitialize(rt2x00dev); } static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) @@ -1121,13 +1022,11 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) return 0; /* - * Allocate all ring entries. + * Allocate all queue entries. */ - status = rt2x00lib_alloc_ring_entries(rt2x00dev); - if (status) { - ERROR(rt2x00dev, "Ring entries allocation failed.\n"); + status = rt2x00queue_initialize(rt2x00dev); + if (status) return status; - } /* * Initialize the device. @@ -1146,7 +1045,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) return 0; exit: - rt2x00lib_free_ring_entries(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); return status; } @@ -1162,11 +1061,9 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) * If this is the first interface which is added, * we should load the firmware now. */ - if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) { - retval = rt2x00lib_load_firmware(rt2x00dev); - if (retval) - return retval; - } + retval = rt2x00lib_load_firmware(rt2x00dev); + if (retval) + return retval; /* * Initialize the device. @@ -1184,6 +1081,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; @@ -1200,74 +1101,25 @@ 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); } /* * driver allocation handlers. */ -static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) +int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; - unsigned int index; - - /* - * We need the following rings: - * RX: 1 - * TX: hw->queues - * Beacon: 1 (if required) - * Atim: 1 (if required) - */ - rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues + - (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)); - - ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL); - if (!ring) { - ERROR(rt2x00dev, "Ring allocation failed.\n"); - return -ENOMEM; - } - - /* - * Initialize pointers - */ - rt2x00dev->rx = ring; - rt2x00dev->tx = &rt2x00dev->rx[1]; - if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) - rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues]; + int retval = -ENOMEM; /* - * Initialize ring parameters. - * RX: queue_idx = 0 - * TX: queue_idx = IEEE80211_TX_QUEUE_DATA0 + index - * TX: cw_min: 2^5 = 32. - * TX: cw_max: 2^10 = 1024. + * Make room for rt2x00_intf inside the per-interface + * structure ieee80211_vif. */ - rt2x00dev->rx->rt2x00dev = rt2x00dev; - rt2x00dev->rx->queue_idx = 0; - - index = IEEE80211_TX_QUEUE_DATA0; - txring_for_each(rt2x00dev, ring) { - ring->rt2x00dev = rt2x00dev; - ring->queue_idx = index++; - ring->tx_params.aifs = 2; - ring->tx_params.cw_min = 5; - ring->tx_params.cw_max = 10; - } - - return 0; -} - -static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev) -{ - kfree(rt2x00dev->rx); - rt2x00dev->rx = NULL; - rt2x00dev->tx = NULL; - rt2x00dev->bcn = NULL; -} - -int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) -{ - int retval = -ENOMEM; + rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); /* * Let the driver probe the device to detect the capabilities. @@ -1281,20 +1133,14 @@ 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 ring array. + * Allocate queue array. */ - retval = rt2x00lib_alloc_rings(rt2x00dev); + retval = rt2x00queue_allocate(rt2x00dev); if (retval) goto exit; @@ -1310,6 +1156,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Register extra components. */ + rt2x00leds_register(rt2x00dev); rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); @@ -1343,6 +1190,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00debug_deregister(rt2x00dev); rt2x00rfkill_free(rt2x00dev); + rt2x00leds_unregister(rt2x00dev); /* * Free ieee80211_hw memory. @@ -1355,9 +1203,9 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) rt2x00lib_free_firmware(rt2x00dev); /* - * Free ring structures. + * Free queue structures. */ - rt2x00lib_free_rings(rt2x00dev); + rt2x00queue_free(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); @@ -1388,6 +1236,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) /* * Suspend/disable extra components. */ + rt2x00leds_suspend(rt2x00dev); rt2x00rfkill_suspend(rt2x00dev); rt2x00debug_deregister(rt2x00dev); @@ -1412,9 +1261,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"); @@ -1424,6 +1294,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) */ rt2x00debug_register(rt2x00dev); rt2x00rfkill_resume(rt2x00dev); + rt2x00leds_resume(rt2x00dev); /* * Only continue if mac80211 had open interfaces. @@ -1445,9 +1316,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. @@ -1463,12 +1337,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/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h index 99f3f367adc..7169c222a48 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dump.h +++ b/drivers/net/wireless/rt2x00/rt2x00dump.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -93,8 +93,8 @@ enum rt2x00_dump_type { * @chip_rf: RF chipset * @chip_rev: Chipset revision * @type: The frame type (&rt2x00_dump_type) - * @ring_index: The index number of the data ring. - * @entry_index: The index number of the entry inside the data ring. + * @queue_index: The index number of the data queue. + * @entry_index: The index number of the entry inside the data queue. * @timestamp_sec: Timestamp - seconds * @timestamp_usec: Timestamp - microseconds */ @@ -111,7 +111,7 @@ struct rt2x00dump_hdr { __le32 chip_rev; __le16 type; - __u8 ring_index; + __u8 queue_index; __u8 entry_index; __le32 timestamp_sec; diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index 0a475e4e244..b971bc6e7ee 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -23,7 +23,6 @@ Abstract: rt2x00 firmware loading routines. */ -#include <linux/crc-itu-t.h> #include <linux/kernel.h> #include <linux/module.h> @@ -37,7 +36,6 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) char *fw_name; int retval; u16 crc; - u16 tmp; /* * Read correct firmware from harddisk. @@ -63,18 +61,9 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) return -ENOENT; } - /* - * Validate the firmware using 16 bit CRC. - * The last 2 bytes of the firmware are the CRC - * so substract those 2 bytes from the CRC checksum, - * and set those 2 bytes to 0 when calculating CRC. - */ - tmp = 0; - crc = crc_itu_t(0, fw->data, fw->size - 2); - crc = crc_itu_t(crc, (u8 *)&tmp, 2); - + crc = rt2x00dev->ops->lib->get_firmware_crc(fw->data, fw->size); if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) { - ERROR(rt2x00dev, "Firmware CRC error.\n"); + ERROR(rt2x00dev, "Firmware checksum error.\n"); retval = -ENOENT; goto exit; } @@ -96,6 +85,9 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) { int retval; + if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) + return 0; + if (!rt2x00dev->fw) { retval = rt2x00lib_request_firmware(rt2x00dev); if (retval) @@ -116,4 +108,3 @@ void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) release_firmware(rt2x00dev->fw); rt2x00dev->fw = NULL; } - diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c new file mode 100644 index 00000000000..40c1f5c1b80 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -0,0 +1,219 @@ +/* + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + <http://rt2x00.serialmonkey.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 led specific routines. + */ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include "rt2x00.h" +#include "rt2x00lib.h" + +void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi) +{ + struct rt2x00_led *led = &rt2x00dev->led_qual; + unsigned int brightness; + + if ((led->type != LED_TYPE_QUALITY) || !(led->flags & LED_REGISTERED)) + return; + + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + + /* + * Get the rssi level, this is used to convert the rssi + * to a LED value inside the range LED_OFF - LED_FULL. + */ + if (rssi <= 30) + rssi = 0; + else if (rssi <= 39) + rssi = 1; + else if (rssi <= 49) + rssi = 2; + else if (rssi <= 53) + rssi = 3; + else if (rssi <= 63) + rssi = 4; + else + rssi = 5; + + /* + * Note that we must _not_ send LED_OFF since the driver + * is going to calculate the value and might use it in a + * division. + */ + brightness = ((LED_FULL / 6) * rssi) + 1; + if (brightness != led->led_dev.brightness) { + led->led_dev.brightness_set(&led->led_dev, brightness); + led->led_dev.brightness = brightness; + } +} + +void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +{ + struct rt2x00_led *led = &rt2x00dev->led_assoc; + unsigned int brightness; + + if ((led->type != LED_TYPE_ASSOC) || !(led->flags & LED_REGISTERED)) + return; + + brightness = enabled ? LED_FULL : LED_OFF; + if (brightness != led->led_dev.brightness) { + led->led_dev.brightness_set(&led->led_dev, brightness); + led->led_dev.brightness = brightness; + } +} + +void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled) +{ + struct rt2x00_led *led = &rt2x00dev->led_radio; + unsigned int brightness; + + if ((led->type != LED_TYPE_RADIO) || !(led->flags & LED_REGISTERED)) + return; + + brightness = enabled ? LED_FULL : LED_OFF; + if (brightness != led->led_dev.brightness) { + led->led_dev.brightness_set(&led->led_dev, brightness); + led->led_dev.brightness = brightness; + } +} + +static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, + const char *name) +{ + struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); + int retval; + + led->led_dev.name = name; + + retval = led_classdev_register(device, &led->led_dev); + if (retval) { + ERROR(rt2x00dev, "Failed to register led handler.\n"); + return retval; + } + + led->flags |= LED_REGISTERED; + + return 0; +} + +void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) +{ + char dev_name[16]; + char name[32]; + int retval; + unsigned long on_period; + unsigned long off_period; + + snprintf(dev_name, sizeof(dev_name), "%s-%s", + rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy)); + + if (rt2x00dev->led_radio.flags & LED_INITIALIZED) { + snprintf(name, sizeof(name), "%s:radio", dev_name); + + retval = rt2x00leds_register_led(rt2x00dev, + &rt2x00dev->led_radio, + name); + if (retval) + goto exit_fail; + } + + if (rt2x00dev->led_assoc.flags & LED_INITIALIZED) { + snprintf(name, sizeof(name), "%s:assoc", dev_name); + + retval = rt2x00leds_register_led(rt2x00dev, + &rt2x00dev->led_assoc, + name); + if (retval) + goto exit_fail; + } + + if (rt2x00dev->led_qual.flags & LED_INITIALIZED) { + snprintf(name, sizeof(name), "%s:quality", dev_name); + + retval = rt2x00leds_register_led(rt2x00dev, + &rt2x00dev->led_qual, + name); + if (retval) + goto exit_fail; + } + + /* + * Initialize blink time to default value: + * On period: 70ms + * Off period: 30ms + */ + if (rt2x00dev->led_radio.led_dev.blink_set) { + on_period = 70; + off_period = 30; + rt2x00dev->led_radio.led_dev.blink_set( + &rt2x00dev->led_radio.led_dev, &on_period, &off_period); + } + + return; + +exit_fail: + rt2x00leds_unregister(rt2x00dev); +} + +static void rt2x00leds_unregister_led(struct rt2x00_led *led) +{ + led_classdev_unregister(&led->led_dev); + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->flags &= ~LED_REGISTERED; +} + +void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->led_qual.flags & LED_REGISTERED) + rt2x00leds_unregister_led(&rt2x00dev->led_qual); + if (rt2x00dev->led_assoc.flags & LED_REGISTERED) + rt2x00leds_unregister_led(&rt2x00dev->led_assoc); + if (rt2x00dev->led_radio.flags & LED_REGISTERED) + rt2x00leds_unregister_led(&rt2x00dev->led_radio); +} + +void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->led_qual.flags & LED_REGISTERED) + led_classdev_suspend(&rt2x00dev->led_qual.led_dev); + if (rt2x00dev->led_assoc.flags & LED_REGISTERED) + led_classdev_suspend(&rt2x00dev->led_assoc.led_dev); + if (rt2x00dev->led_radio.flags & LED_REGISTERED) + led_classdev_suspend(&rt2x00dev->led_radio.led_dev); +} + +void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->led_radio.flags & LED_REGISTERED) + led_classdev_resume(&rt2x00dev->led_radio.led_dev); + if (rt2x00dev->led_assoc.flags & LED_REGISTERED) + led_classdev_resume(&rt2x00dev->led_assoc.led_dev); + if (rt2x00dev->led_qual.flags & LED_REGISTERED) + led_classdev_resume(&rt2x00dev->led_qual.led_dev); +} diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.h b/drivers/net/wireless/rt2x00/rt2x00leds.h new file mode 100644 index 00000000000..9df4a49bdca --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00leds.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + <http://rt2x00.serialmonkey.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 led datastructures and routines + */ + +#ifndef RT2X00LEDS_H +#define RT2X00LEDS_H + +enum led_type { + LED_TYPE_RADIO, + LED_TYPE_ASSOC, + LED_TYPE_ACTIVITY, + LED_TYPE_QUALITY, +}; + +#ifdef CONFIG_RT2X00_LIB_LEDS + +struct rt2x00_led { + struct rt2x00_dev *rt2x00dev; + struct led_classdev led_dev; + + enum led_type type; + unsigned int flags; +#define LED_INITIALIZED ( 1 << 0 ) +#define LED_REGISTERED ( 1 << 1 ) +}; + +#endif /* CONFIG_RT2X00_LIB_LEDS */ + +#endif /* RT2X00LEDS_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index ce58c654ade..5be32fffc74 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -34,6 +34,40 @@ #define RFKILL_POLL_INTERVAL ( 1000 ) /* + * rt2x00_rate: Per rate device information + */ +struct rt2x00_rate { + unsigned short flags; +#define DEV_RATE_CCK 0x0001 +#define DEV_RATE_OFDM 0x0002 +#define DEV_RATE_SHORT_PREAMBLE 0x0004 +#define DEV_RATE_BASIC 0x0008 + + unsigned short bitrate; /* In 100kbit/s */ + unsigned short ratemask; + + unsigned short plcp; +}; + +extern const struct rt2x00_rate rt2x00_supported_rates[12]; + +static inline u16 rt2x00_create_rate_hw_value(const u16 index, + const u16 short_preamble) +{ + return (short_preamble << 8) | (index & 0xff); +} + +static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value) +{ + return &rt2x00_supported_rates[hw_value & 0xff]; +} + +static inline int rt2x00_get_rate_preamble(const u16 hw_value) +{ + return (hw_value & 0xff00); +} + +/* * Radio control handlers. */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev); @@ -50,15 +84,29 @@ 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_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct ieee80211_bss_conf *conf); void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, enum antenna rx, enum antenna tx); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config); /* + * Queue handlers. + */ +void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev); +void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev); +int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev); +int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev); +void rt2x00queue_free(struct rt2x00_dev *rt2x00dev); + +/* * Firmware handlers. */ #ifdef CONFIG_RT2X00_LIB_FIRMWARE @@ -132,4 +180,48 @@ static inline void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev) } #endif /* CONFIG_RT2X00_LIB_RFKILL */ +/* + * LED handlers + */ +#ifdef CONFIG_RT2X00_LIB_LEDS +void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi); +void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled); +void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled); +void rt2x00leds_register(struct rt2x00_dev *rt2x00dev); +void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev); +void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev); +void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev); +#else +static inline void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, + int rssi) +{ +} + +static inline void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, + bool enabled) +{ +} + +static inline void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, + bool enabled) +{ +} + +static inline void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_LEDS */ + #endif /* RT2X00LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e3f15e518c7..c206b509207 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -30,10 +30,11 @@ #include "rt2x00lib.h" static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, + struct data_queue *queue, struct sk_buff *frag_skb, struct ieee80211_tx_control *control) { + struct skb_frame_desc *skbdesc; struct sk_buff *skb; int size; @@ -52,15 +53,22 @@ 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)); - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { + /* + * Initialize skb descriptor + */ + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; + + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); return NETDEV_TX_BUSY; } @@ -73,7 +81,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - struct data_ring *ring; + struct data_queue *queue; + struct skb_frame_desc *skbdesc; u16 frame_control; /* @@ -88,10 +97,14 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } /* - * Determine which ring to put packet on. + * Determine which queue to put packet on. */ - ring = rt2x00lib_get_ring(rt2x00dev, control->queue); - if (unlikely(!ring)) { + if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM && + test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) + queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM); + else + queue = rt2x00queue_get_queue(rt2x00dev, control->queue); + if (unlikely(!queue)) { ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", @@ -110,23 +123,29 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT))) { - if (rt2x00_ring_free(ring) <= 1) { + if (rt2x00queue_available(queue) <= 1) { ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; } - if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) { + if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; } } - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { + /* + * Initialize skb descriptor + */ + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; } - if (rt2x00_ring_full(ring)) + if (rt2x00queue_full(queue)) ieee80211_stop_queue(rt2x00dev->hw, control->queue); if (rt2x00dev->ops->lib->kick_tx_queue) @@ -162,27 +181,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; - - /* FIXME: Beaconing is broken in rt2x00. */ - if (conf->type == IEEE80211_IF_TYPE_IBSS || - conf->type == IEEE80211_IF_TYPE_AP) { - ERROR(rt2x00dev, - "rt2x00 does not support Adhoc or Master mode"); - return -EOPNOTSUPP; - } + struct rt2x00_intf *intf = vif_to_intf(conf->vif); + struct data_queue *queue = + rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_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; - intf->id = conf->vif; - intf->type = conf->type; + /* + * 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; + + /* + * 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); @@ -192,8 +251,14 @@ 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); + + /* + * Some filters depend on the current working mode. We can force + * an update during the next configure_filter() run by mac80211 by + * resetting the current packet_filter state. + */ + rt2x00dev->packet_filter = 0; return 0; } @@ -203,7 +268,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 @@ -211,21 +276,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 = 0; - 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); @@ -270,7 +341,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; /* @@ -280,12 +351,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, @@ -294,7 +360,16 @@ 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); + + spin_unlock(&intf->lock); + + /* + * Call rt2x00_config_intf() outside of the spinlock context since + * the call will sleep for USB drivers. By using the ieee80211_if_conf + * values as arguments we make keep access to rt2x00_intf thread safe + * even without the lock. + */ + rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid); /* * We only need to initialize the beacon when master mode is enabled. @@ -312,6 +387,50 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); +void rt2x00mac_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Mask off any flags we are going to ignore + * from the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Multicast filter seems to kill broadcast traffic so never use it. + */ + *total_flags |= FIF_ALLMULTI; + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + + /* + * Check if there is any work left for us. + */ + if (rt2x00dev->packet_filter == *total_flags) + return; + rt2x00dev->packet_filter = *total_flags; + + if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) + rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); + else + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); +} +EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); + int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { @@ -334,9 +453,11 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; unsigned int i; - for (i = 0; i < hw->queues; i++) - memcpy(&stats->data[i], &rt2x00dev->tx[i].stats, - sizeof(rt2x00dev->tx[i].stats)); + for (i = 0; i < hw->queues; i++) { + stats->data[i].len = rt2x00dev->tx[i].length; + stats->data[i].limit = rt2x00dev->tx[i].limit; + stats->data[i].count = rt2x00dev->tx[i].count; + } return 0; } @@ -348,71 +469,83 @@ 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); + unsigned int delayed = 0; /* - * 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); + if (bss_conf->assoc) + rt2x00dev->intf_associated++; + else + rt2x00dev->intf_associated--; - ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) + rt2x00leds_led_assoc(rt2x00dev, + !!rt2x00dev->intf_associated); + else + delayed |= DELAYED_LED_ASSOC; + } - if (short_preamble) - __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); - else - __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + /* + * When the erp information has changed, we should perform + * additional configuration steps. For all other changes we are done. + */ + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) + rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); + else + delayed |= DELAYED_CONFIG_ERP; + } - 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)); + if (delayed) { + intf->delayed_flags |= delayed; + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); + } + spin_unlock(&intf->lock); } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct data_ring *ring; + struct data_queue *queue; - ring = rt2x00lib_get_ring(rt2x00dev, queue); - if (unlikely(!ring)) + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + if (unlikely(!queue)) return -EINVAL; /* * The passed variables are stored as real value ((2^n)-1). * Ralink registers require to know the bit number 'n'. */ - if (params->cw_min) - ring->tx_params.cw_min = fls(params->cw_min); + if (params->cw_min > 0) + queue->cw_min = fls(params->cw_min); else - ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */ + queue->cw_min = 5; /* cw_min: 2^5 = 32. */ - if (params->cw_max) - ring->tx_params.cw_max = fls(params->cw_max); + if (params->cw_max > 0) + queue->cw_max = fls(params->cw_max); else - ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */ + queue->cw_max = 10; /* cw_min: 2^10 = 1024. */ - if (params->aifs) - ring->tx_params.aifs = params->aifs; + if (params->aifs >= 0) + queue->aifs = params->aifs; else - ring->tx_params.aifs = 2; + queue->aifs = 2; INFO(rt2x00dev, - "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", - queue, ring->tx_params.cw_min, ring->tx_params.cw_max, - ring->tx_params.aifs); + "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", + queue_idx, queue->cw_min, queue->cw_max, queue->aifs); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 804a9980055..7867ec64bd2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -32,64 +32,21 @@ #include "rt2x00pci.h" /* - * Beacon handlers. - */ -int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct skb_desc *desc; - struct data_ring *ring; - struct data_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; - ring = rt2x00lib_get_ring(rt2x00dev, control->queue); - entry = rt2x00_get_data_entry(ring); - - /* - * Fill in skb descriptor - */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len; - desc->desc = entry->priv; - desc->data = skb->data; - desc->ring = ring; - desc->entry = entry; - - memcpy(entry->data_addr, skb->data, skb->len); - rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - - /* - * Enable beacon generation. - */ - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); - - return 0; -} -EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update); - -/* * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *skb, + struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct data_entry *entry = rt2x00_get_data_entry(ring); - __le32 *txd = entry->priv; - struct skb_desc *desc; + struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; + struct skb_frame_desc *skbdesc; u32 word; - if (rt2x00_ring_full(ring)) + if (rt2x00queue_full(queue)) return -EINVAL; - rt2x00_desc_read(txd, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || rt2x00_get_field32(word, TXD_ENTRY_VALID)) { @@ -103,18 +60,18 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Fill in skb descriptor */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len; - desc->desc = entry->priv; - desc->data = skb->data; - desc->ring = ring; - desc->entry = entry; - - memcpy(entry->data_addr, skb->data, skb->len); + skbdesc = get_skb_frame_desc(skb); + skbdesc->data = skb->data; + skbdesc->data_len = skb->len; + skbdesc->desc = priv_tx->desc; + skbdesc->desc_len = queue->desc_size; + skbdesc->entry = entry; + + memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); + memcpy(priv_tx->data, skb->data, skb->len); rt2x00lib_write_tx_desc(rt2x00dev, skb, control); - rt2x00_ring_index_inc(ring); + rt2x00queue_index_inc(queue, Q_INDEX); return 0; } @@ -125,29 +82,28 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); */ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring = rt2x00dev->rx; - struct data_entry *entry; - struct sk_buff *skb; + struct data_queue *queue = rt2x00dev->rx; + struct queue_entry *entry; + struct queue_entry_priv_pci_rx *priv_rx; struct ieee80211_hdr *hdr; - struct skb_desc *skbdesc; - struct rxdata_entry_desc desc; + struct skb_frame_desc *skbdesc; + struct rxdone_entry_desc rxdesc; int header_size; - __le32 *rxd; int align; u32 word; while (1) { - entry = rt2x00_get_data_entry(ring); - rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &word); + entry = rt2x00queue_get_entry(queue, Q_INDEX); + priv_rx = entry->priv_data; + rt2x00_desc_read(priv_rx->desc, 0, &word); if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - memset(&desc, 0, sizeof(desc)); - rt2x00dev->ops->lib->fill_rxdone(entry, &desc); + memset(&rxdesc, 0, sizeof(rxdesc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); - hdr = (struct ieee80211_hdr *)entry->data_addr; + hdr = (struct ieee80211_hdr *)priv_rx->data; header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); @@ -161,66 +117,68 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) * Allocate the sk_buffer, initialize it and copy * all data into it. */ - skb = dev_alloc_skb(desc.size + align); - if (!skb) + entry->skb = dev_alloc_skb(rxdesc.size + align); + if (!entry->skb) return; - skb_reserve(skb, align); - memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size); + skb_reserve(entry->skb, align); + memcpy(skb_put(entry->skb, rxdesc.size), + priv_rx->data, rxdesc.size); /* * Fill in skb descriptor */ - skbdesc = get_skb_desc(skb); - skbdesc->desc_len = entry->ring->desc_size; - skbdesc->data_len = skb->len; - skbdesc->desc = entry->priv; - skbdesc->data = skb->data; - skbdesc->ring = ring; + skbdesc = get_skb_frame_desc(entry->skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->data = entry->skb->data; + skbdesc->data_len = entry->skb->len; + skbdesc->desc = priv_rx->desc; + skbdesc->desc_len = queue->desc_size; skbdesc->entry = entry; /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, skb, &desc); + rt2x00lib_rxdone(entry, &rxdesc); - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { + if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) { rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); + rt2x00_desc_write(priv_rx->desc, 0, word); } - rt2x00_ring_index_inc(ring); + rt2x00queue_index_inc(queue, Q_INDEX); } } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); -void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry, - const int tx_status, const int retry) +void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, + struct txdone_entry_desc *txdesc) { + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00lib_txdone(entry, tx_status, retry); + txdesc->control = &priv_tx->control; + rt2x00lib_txdone(entry, txdesc); /* * Make this entry available for reuse. */ entry->flags = 0; - rt2x00_desc_read(entry->priv, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); - rt2x00_desc_write(entry->priv, 0, word); + rt2x00_desc_write(priv_tx->desc, 0, word); - rt2x00_ring_index_done_inc(entry->ring); + rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* - * If the data ring was full before the txdone handler + * If the data queue was full before the txdone handler * we must make sure the packet queue in the mac80211 stack * is reenabled when the txdone handler has finished. */ - if (!rt2x00_ring_full(entry->ring)) - ieee80211_wake_queue(rt2x00dev->hw, - entry->tx_status.control.queue); + if (!rt2x00queue_full(entry->queue)) + ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); @@ -228,73 +186,122 @@ EXPORT_SYMBOL_GPL(rt2x00pci_txdone); /* * Device initialization handlers. */ -#define priv_offset(__ring, __i) \ -({ \ - ring->data_addr + (i * ring->desc_size); \ +#define desc_size(__queue) \ +({ \ + ((__queue)->limit * (__queue)->desc_size);\ +}) + +#define data_size(__queue) \ +({ \ + ((__queue)->limit * (__queue)->data_size);\ }) -#define data_addr_offset(__ring, __i) \ -({ \ - (__ring)->data_addr + \ - ((__ring)->stats.limit * (__ring)->desc_size) + \ - ((__i) * (__ring)->data_size); \ +#define dma_size(__queue) \ +({ \ + data_size(__queue) + desc_size(__queue);\ }) -#define data_dma_offset(__ring, __i) \ -({ \ - (__ring)->data_dma + \ - ((__ring)->stats.limit * (__ring)->desc_size) + \ - ((__i) * (__ring)->data_size); \ +#define desc_offset(__queue, __base, __i) \ +({ \ + (__base) + data_size(__queue) + \ + ((__i) * (__queue)->desc_size); \ }) -static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring) +#define data_offset(__queue, __base, __i) \ +({ \ + (__base) + \ + ((__i) * (__queue)->data_size); \ +}) + +static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue) { + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci_tx *priv_tx; + void *addr; + dma_addr_t dma; + void *desc_addr; + dma_addr_t desc_dma; + void *data_addr; + dma_addr_t data_dma; unsigned int i; /* * Allocate DMA memory for descriptor and buffer. */ - ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev), - rt2x00_get_ring_size(ring), - &ring->data_dma); - if (!ring->data_addr) + addr = pci_alloc_consistent(pci_dev, dma_size(queue), &dma); + if (!addr) return -ENOMEM; + memset(addr, 0, dma_size(queue)); + /* - * Initialize all ring entries to contain valid - * addresses. + * Initialize all queue entries to contain valid addresses. */ - for (i = 0; i < ring->stats.limit; i++) { - ring->entry[i].priv = priv_offset(ring, i); - ring->entry[i].data_addr = data_addr_offset(ring, i); - ring->entry[i].data_dma = data_dma_offset(ring, i); + for (i = 0; i < queue->limit; i++) { + desc_addr = desc_offset(queue, addr, i); + desc_dma = desc_offset(queue, dma, i); + data_addr = data_offset(queue, addr, i); + data_dma = data_offset(queue, dma, i); + + if (queue->qid == QID_RX) { + priv_rx = queue->entries[i].priv_data; + priv_rx->desc = desc_addr; + priv_rx->desc_dma = desc_dma; + priv_rx->data = data_addr; + priv_rx->data_dma = data_dma; + } else { + priv_tx = queue->entries[i].priv_data; + priv_tx->desc = desc_addr; + priv_tx->desc_dma = desc_dma; + priv_tx->data = data_addr; + priv_tx->data_dma = data_dma; + } } return 0; } -static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring) +static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue) { - if (ring->data_addr) - pci_free_consistent(rt2x00dev_pci(rt2x00dev), - rt2x00_get_ring_size(ring), - ring->data_addr, ring->data_dma); - ring->data_addr = NULL; + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci_tx *priv_tx; + void *data_addr; + dma_addr_t data_dma; + + if (queue->qid == QID_RX) { + priv_rx = queue->entries[0].priv_data; + data_addr = priv_rx->data; + data_dma = priv_rx->data_dma; + + priv_rx->data = NULL; + } else { + priv_tx = queue->entries[0].priv_data; + data_addr = priv_tx->data; + data_dma = priv_tx->data_dma; + + priv_tx->data = NULL; + } + + if (data_addr) + pci_free_consistent(pci_dev, dma_size(queue), + data_addr, data_dma); } int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - struct data_ring *ring; + struct data_queue *queue; int status; /* * Allocate DMA */ - ring_for_each(rt2x00dev, ring) { - status = rt2x00pci_alloc_dma(rt2x00dev, ring); + queue_for_each(rt2x00dev, queue) { + status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue); if (status) goto exit; } @@ -321,7 +328,7 @@ EXPORT_SYMBOL_GPL(rt2x00pci_initialize); void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; + struct data_queue *queue; /* * Free irq line. @@ -331,8 +338,8 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) /* * Free DMA */ - ring_for_each(rt2x00dev, ring) - rt2x00pci_free_dma(rt2x00dev, ring); + queue_for_each(rt2x00dev, queue) + rt2x00pci_free_queue_dma(rt2x00dev, queue); } EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); @@ -347,9 +354,9 @@ static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) kfree(rt2x00dev->eeprom); rt2x00dev->eeprom = NULL; - if (rt2x00dev->csr_addr) { - iounmap(rt2x00dev->csr_addr); - rt2x00dev->csr_addr = NULL; + if (rt2x00dev->csr.base) { + iounmap(rt2x00dev->csr.base); + rt2x00dev->csr.base = NULL; } } @@ -357,9 +364,9 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) { struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); - rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0), + rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); - if (!rt2x00dev->csr_addr) + if (!rt2x00dev->csr.base) goto exit; rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); @@ -530,5 +537,5 @@ EXPORT_SYMBOL_GPL(rt2x00pci_resume); */ MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); -MODULE_DESCRIPTION("rt2x00 library"); +MODULE_DESCRIPTION("rt2x00 pci library"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 2d1eb8144da..9d1cdb99431 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -61,7 +61,7 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, const unsigned long offset, u32 *value) { - *value = readl(rt2x00dev->csr_addr + offset); + *value = readl(rt2x00dev->csr.base + offset); } static inline void @@ -69,14 +69,14 @@ rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned long offset, void *value, const u16 length) { - memcpy_fromio(value, rt2x00dev->csr_addr + offset, length); + memcpy_fromio(value, rt2x00dev->csr.base + offset, length); } static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, const unsigned long offset, u32 value) { - writel(value, rt2x00dev->csr_addr + offset); + writel(value, rt2x00dev->csr.base + offset); } static inline void @@ -84,28 +84,63 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned long offset, void *value, const u16 length) { - memcpy_toio(rt2x00dev->csr_addr + offset, value, length); + memcpy_toio(rt2x00dev->csr.base + offset, value, length); } /* - * Beacon handlers. - */ -int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *control); - -/* * TX data handlers. */ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *skb, + struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control); -/* - * RX/TX data handlers. +/** + * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information + * + * @desc: Pointer to device descriptor. + * @data: Pointer to device's entry memory. + * @dma: DMA pointer to &data. + */ +struct queue_entry_priv_pci_rx { + __le32 *desc; + dma_addr_t desc_dma; + + void *data; + dma_addr_t data_dma; +}; + +/** + * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information + * + * @desc: Pointer to device descriptor + * @data: Pointer to device's entry memory. + * @dma: DMA pointer to &data. + * @control: mac80211 control structure used to transmit data. + */ +struct queue_entry_priv_pci_tx { + __le32 *desc; + dma_addr_t desc_dma; + + void *data; + dma_addr_t data_dma; + + struct ieee80211_tx_control control; +}; + +/** + * rt2x00pci_rxdone - Handle RX done events + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. */ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); -void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry, - const int tx_status, const int retry); + +/** + * rt2x00pci_txdone - Handle TX done events + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @entry: Entry which has completed the transmission of a frame. + * @desc: TX done descriptor + */ +void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, + struct txdone_entry_desc *desc); /* * Device initialization handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c new file mode 100644 index 00000000000..659e9f44c40 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -0,0 +1,304 @@ +/* + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + <http://rt2x00.serialmonkey.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 queue specific routines. + */ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include "rt2x00.h" +#include "rt2x00lib.h" + +struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, + const unsigned int queue) +{ + int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + + if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + return &rt2x00dev->tx[queue]; + + if (!rt2x00dev->bcn) + return NULL; + + if (queue == RT2X00_BCN_QUEUE_BEACON) + return &rt2x00dev->bcn[0]; + else if (queue == RT2X00_BCN_QUEUE_ATIM && atim) + return &rt2x00dev->bcn[1]; + + return NULL; +} +EXPORT_SYMBOL_GPL(rt2x00queue_get_queue); + +struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, + enum queue_index index) +{ + struct queue_entry *entry; + unsigned long irqflags; + + if (unlikely(index >= Q_INDEX_MAX)) { + ERROR(queue->rt2x00dev, + "Entry requested from invalid index type (%d)\n", index); + return NULL; + } + + spin_lock_irqsave(&queue->lock, irqflags); + + entry = &queue->entries[queue->index[index]]; + + spin_unlock_irqrestore(&queue->lock, irqflags); + + return entry; +} +EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); + +void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) +{ + unsigned long irqflags; + + if (unlikely(index >= Q_INDEX_MAX)) { + ERROR(queue->rt2x00dev, + "Index change on invalid index type (%d)\n", index); + return; + } + + spin_lock_irqsave(&queue->lock, irqflags); + + queue->index[index]++; + if (queue->index[index] >= queue->limit) + queue->index[index] = 0; + + if (index == Q_INDEX) { + queue->length++; + } else if (index == Q_INDEX_DONE) { + queue->length--; + queue->count ++; + } + + spin_unlock_irqrestore(&queue->lock, irqflags); +} +EXPORT_SYMBOL_GPL(rt2x00queue_index_inc); + +static void rt2x00queue_reset(struct data_queue *queue) +{ + unsigned long irqflags; + + spin_lock_irqsave(&queue->lock, irqflags); + + queue->count = 0; + queue->length = 0; + memset(queue->index, 0, sizeof(queue->index)); + + spin_unlock_irqrestore(&queue->lock, irqflags); +} + +void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue = rt2x00dev->rx; + unsigned int i; + + rt2x00queue_reset(queue); + + if (!rt2x00dev->ops->lib->init_rxentry) + return; + + for (i = 0; i < queue->limit; i++) + rt2x00dev->ops->lib->init_rxentry(rt2x00dev, + &queue->entries[i]); +} + +void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + unsigned int i; + + txall_queue_for_each(rt2x00dev, queue) { + rt2x00queue_reset(queue); + + if (!rt2x00dev->ops->lib->init_txentry) + continue; + + for (i = 0; i < queue->limit; i++) + rt2x00dev->ops->lib->init_txentry(rt2x00dev, + &queue->entries[i]); + } +} + +static int rt2x00queue_alloc_entries(struct data_queue *queue, + const struct data_queue_desc *qdesc) +{ + struct queue_entry *entries; + unsigned int entry_size; + unsigned int i; + + rt2x00queue_reset(queue); + + queue->limit = qdesc->entry_num; + queue->data_size = qdesc->data_size; + queue->desc_size = qdesc->desc_size; + + /* + * Allocate all queue entries. + */ + entry_size = sizeof(*entries) + qdesc->priv_size; + entries = kzalloc(queue->limit * entry_size, GFP_KERNEL); + if (!entries) + return -ENOMEM; + +#define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \ + ( ((char *)(__base)) + ((__limit) * (__esize)) + \ + ((__index) * (__psize)) ) + + for (i = 0; i < queue->limit; i++) { + entries[i].flags = 0; + entries[i].queue = queue; + entries[i].skb = NULL; + entries[i].entry_idx = i; + entries[i].priv_data = + QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit, + sizeof(*entries), qdesc->priv_size); + } + +#undef QUEUE_ENTRY_PRIV_OFFSET + + queue->entries = entries; + + return 0; +} + +int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + int status; + + + status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx); + if (status) + goto exit; + + tx_queue_for_each(rt2x00dev, queue) { + status = rt2x00queue_alloc_entries(queue, rt2x00dev->ops->tx); + if (status) + goto exit; + } + + status = rt2x00queue_alloc_entries(rt2x00dev->bcn, rt2x00dev->ops->bcn); + if (status) + goto exit; + + if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) + return 0; + + status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1], + rt2x00dev->ops->atim); + if (status) + goto exit; + + return 0; + +exit: + ERROR(rt2x00dev, "Queue entries allocation failed.\n"); + + rt2x00queue_uninitialize(rt2x00dev); + + return status; +} + +void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + + queue_for_each(rt2x00dev, queue) { + kfree(queue->entries); + queue->entries = NULL; + } +} + +static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, + struct data_queue *queue, enum data_queue_qid qid) +{ + spin_lock_init(&queue->lock); + + queue->rt2x00dev = rt2x00dev; + queue->qid = qid; + queue->aifs = 2; + queue->cw_min = 5; + queue->cw_max = 10; +} + +int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + enum data_queue_qid qid; + unsigned int req_atim = + !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + + /* + * We need the following queues: + * RX: 1 + * TX: hw->queues + * Beacon: 1 + * Atim: 1 (if required) + */ + rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim; + + queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); + if (!queue) { + ERROR(rt2x00dev, "Queue allocation failed.\n"); + return -ENOMEM; + } + + /* + * Initialize pointers + */ + rt2x00dev->rx = queue; + rt2x00dev->tx = &queue[1]; + rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; + + /* + * Initialize queue parameters. + * RX: qid = QID_RX + * TX: qid = QID_AC_BE + index + * TX: cw_min: 2^5 = 32. + * TX: cw_max: 2^10 = 1024. + * BCN & Atim: qid = QID_MGMT + */ + rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX); + + qid = QID_AC_BE; + tx_queue_for_each(rt2x00dev, queue) + rt2x00queue_init(rt2x00dev, queue, qid++); + + rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[0], QID_MGMT); + if (req_atim) + rt2x00queue_init(rt2x00dev, &rt2x00dev->bcn[1], QID_MGMT); + + return 0; +} + +void rt2x00queue_free(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rx); + rt2x00dev->rx = NULL; + rt2x00dev->tx = NULL; + rt2x00dev->bcn = NULL; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h new file mode 100644 index 00000000000..7027c9f47d3 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -0,0 +1,468 @@ +/* + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + <http://rt2x00.serialmonkey.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00 + Abstract: rt2x00 queue datastructures and routines + */ + +#ifndef RT2X00QUEUE_H +#define RT2X00QUEUE_H + +#include <linux/prefetch.h> + +/** + * DOC: Entrie frame size + * + * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes, + * for USB devices this restriction does not apply, but the value of + * 2432 makes sense since it is big enough to contain the maximum fragment + * size according to the ieee802.11 specs. + */ +#define DATA_FRAME_SIZE 2432 +#define MGMT_FRAME_SIZE 256 + +/** + * DOC: Number of entries per queue + * + * After research it was concluded that 12 entries in a RX and TX + * 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. + */ +#define RX_ENTRIES 12 +#define TX_ENTRIES 12 +#define BEACON_ENTRIES 1 +#define ATIM_ENTRIES 1 + +/** + * enum data_queue_qid: Queue identification + */ +enum data_queue_qid { + QID_AC_BE = 0, + QID_AC_BK = 1, + QID_AC_VI = 2, + QID_AC_VO = 3, + QID_HCCA = 4, + QID_MGMT = 13, + QID_RX = 14, + QID_OTHER = 15, +}; + +/** + * enum rt2x00_bcn_queue: Beacon queue index + * + * Start counting with a high offset, this because this enumeration + * supplements &enum ieee80211_tx_queue and we should prevent value + * conflicts. + * + * @RT2X00_BCN_QUEUE_BEACON: Beacon queue + * @RT2X00_BCN_QUEUE_ATIM: Atim queue (sends frame after beacon) + */ +enum rt2x00_bcn_queue { + RT2X00_BCN_QUEUE_BEACON = 100, + RT2X00_BCN_QUEUE_ATIM = 101, +}; + +/** + * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc + * + * @FRAME_DESC_DRIVER_GENERATED: Frame was generated inside driver + * and should not be reported back to mac80211 during txdone. + */ +enum skb_frame_desc_flags { + FRAME_DESC_DRIVER_GENERATED = 1 << 0, +}; + +/** + * struct skb_frame_desc: Descriptor information for the skb buffer + * + * This structure is placed over the skb->cb array, this means that + * this structure should not exceed the size of that array (48 bytes). + * + * @flags: Frame flags, see &enum skb_frame_desc_flags. + * @frame_type: Frame type, see &enum rt2x00_dump_type. + * @data: Pointer to data part of frame (Start of ieee80211 header). + * @desc: Pointer to descriptor part of the frame. + * Note that this pointer could point to something outside + * of the scope of the skb->data pointer. + * @data_len: Length of the frame data. + * @desc_len: Length of the frame descriptor. + + * @entry: The entry to which this sk buffer belongs. + */ +struct skb_frame_desc { + unsigned int flags; + + unsigned int frame_type; + + void *data; + void *desc; + + unsigned int data_len; + unsigned int desc_len; + + struct queue_entry *entry; +}; + +static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb)); + return (struct skb_frame_desc *)&skb->cb[0]; +} + +/** + * enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc + * + * @RXDONE_SIGNAL_PLCP: Does the signal field contain the plcp value, + * or does it contain the bitrate itself. + * @RXDONE_MY_BSS: Does this frame originate from device's BSS. + */ +enum rxdone_entry_desc_flags { + RXDONE_SIGNAL_PLCP = 1 << 0, + RXDONE_MY_BSS = 1 << 1, +}; + +/** + * struct rxdone_entry_desc: RX Entry descriptor + * + * Summary of information that has been read from the RX frame descriptor. + * + * @signal: Signal of the received frame. + * @rssi: RSSI of the received frame. + * @size: Data size of the received frame. + * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). + * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). + + */ +struct rxdone_entry_desc { + int signal; + int rssi; + int size; + int flags; + int dev_flags; +}; + +/** + * struct txdone_entry_desc: TX done entry descriptor + * + * Summary of information that has been read from the TX frame descriptor + * after the device is done with transmission. + * + * @control: Control structure which was used to transmit the frame. + * @status: TX status (See &enum tx_status). + * @retry: Retry count. + */ +struct txdone_entry_desc { + struct ieee80211_tx_control *control; + int status; + int retry; +}; + +/** + * enum txentry_desc_flags: Status flags for TX entry descriptor + * + * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. + * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. + * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. + * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. + * @ENTRY_TXD_BURST: This frame belongs to the same burst event. + * @ENTRY_TXD_ACK: An ACK is required for this frame. + */ +enum txentry_desc_flags { + ENTRY_TXD_RTS_FRAME, + ENTRY_TXD_OFDM_RATE, + ENTRY_TXD_MORE_FRAG, + ENTRY_TXD_REQ_TIMESTAMP, + ENTRY_TXD_BURST, + ENTRY_TXD_ACK, +}; + +/** + * struct txentry_desc: TX Entry descriptor + * + * Summary of information for the frame descriptor before sending a TX frame. + * + * @flags: Descriptor flags (See &enum queue_entry_flags). + * @queue: Queue identification (See &enum data_queue_qid). + * @length_high: PLCP length high word. + * @length_low: PLCP length low word. + * @signal: PLCP signal. + * @service: PLCP service. + * @aifs: AIFS value. + * @ifs: IFS value. + * @cw_min: cwmin value. + * @cw_max: cwmax value. + */ +struct txentry_desc { + unsigned long flags; + + enum data_queue_qid queue; + + u16 length_high; + u16 length_low; + u16 signal; + u16 service; + + int aifs; + int ifs; + int cw_min; + int cw_max; +}; + +/** + * enum queue_entry_flags: Status flags for queue entry + * + * @ENTRY_BCN_ASSIGNED: This entry has been assigned to an interface. + * As long as this bit is set, this entry may only be touched + * through the interface structure. + * @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data + * transfer (either TX or RX depending on the queue). The entry should + * only be touched after the device has signaled it is done with it. + * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data + * encryption or decryption. The entry should only be touched after + * the device has signaled it is done with it. + */ + +enum queue_entry_flags { + ENTRY_BCN_ASSIGNED, + ENTRY_OWNER_DEVICE_DATA, + ENTRY_OWNER_DEVICE_CRYPTO, +}; + +/** + * struct queue_entry: Entry inside the &struct data_queue + * + * @flags: Entry flags, see &enum queue_entry_flags. + * @queue: The data queue (&struct data_queue) to which this entry belongs. + * @skb: The buffer which is currently being transmitted (for TX queue), + * or used to directly recieve data in (for RX queue). + * @entry_idx: The entry index number. + * @priv_data: Private data belonging to this queue entry. The pointer + * points to data specific to a particular driver and queue type. + */ +struct queue_entry { + unsigned long flags; + + struct data_queue *queue; + + struct sk_buff *skb; + + unsigned int entry_idx; + + void *priv_data; +}; + +/** + * enum queue_index: Queue index type + * + * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is + * owned by the hardware then the queue is considered to be full. + * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by + * the hardware and for which we need to run the txdone handler. If this + * entry is not owned by the hardware the queue is considered to be empty. + * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription + * will be completed by the hardware next. + * @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size + * of the index array. + */ +enum queue_index { + Q_INDEX, + Q_INDEX_DONE, + Q_INDEX_CRYPTO, + Q_INDEX_MAX, +}; + +/** + * struct data_queue: Data queue + * + * @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to. + * @entries: Base address of the &struct queue_entry which are + * part of this queue. + * @qid: The queue identification, see &enum data_queue_qid. + * @lock: Spinlock to protect index handling. Whenever @index, @index_done or + * @index_crypt needs to be changed this lock should be grabbed to prevent + * index corruption due to concurrency. + * @count: Number of frames handled in the queue. + * @limit: Maximum number of entries in the queue. + * @length: Number of frames in queue. + * @index: Index pointers to entry positions in the queue, + * use &enum queue_index to get a specific index field. + * @aifs: The aifs value for outgoing frames (field ignored in RX queue). + * @cw_min: The cw min value for outgoing frames (field ignored in RX queue). + * @cw_max: The cw max value for outgoing frames (field ignored in RX queue). + * @data_size: Maximum data size for the frames in this queue. + * @desc_size: Hardware descriptor size for the data in this queue. + */ +struct data_queue { + struct rt2x00_dev *rt2x00dev; + struct queue_entry *entries; + + enum data_queue_qid qid; + + spinlock_t lock; + unsigned int count; + unsigned short limit; + unsigned short length; + unsigned short index[Q_INDEX_MAX]; + + unsigned short aifs; + unsigned short cw_min; + unsigned short cw_max; + + unsigned short data_size; + unsigned short desc_size; +}; + +/** + * struct data_queue_desc: Data queue description + * + * The information in this structure is used by drivers + * to inform rt2x00lib about the creation of the data queue. + * + * @entry_num: Maximum number of entries for a queue. + * @data_size: Maximum data size for the frames in this queue. + * @desc_size: Hardware descriptor size for the data in this queue. + * @priv_size: Size of per-queue_entry private data. + */ +struct data_queue_desc { + unsigned short entry_num; + unsigned short data_size; + unsigned short desc_size; + unsigned short priv_size; +}; + +/** + * queue_end - Return pointer to the last queue (HELPER MACRO). + * @__dev: Pointer to &struct rt2x00_dev + * + * Using the base rx pointer and the maximum number of available queues, + * this macro will return the address of 1 position beyond the end of the + * queues array. + */ +#define queue_end(__dev) \ + &(__dev)->rx[(__dev)->data_queues] + +/** + * tx_queue_end - Return pointer to the last TX queue (HELPER MACRO). + * @__dev: Pointer to &struct rt2x00_dev + * + * Using the base tx pointer and the maximum number of available TX + * queues, this macro will return the address of 1 position beyond + * the end of the TX queue array. + */ +#define tx_queue_end(__dev) \ + &(__dev)->tx[(__dev)->hw->queues] + +/** + * queue_loop - Loop through the queues within a specific range (HELPER MACRO). + * @__entry: Pointer where the current queue entry will be stored in. + * @__start: Start queue pointer. + * @__end: End queue pointer. + * + * This macro will loop through all queues between &__start and &__end. + */ +#define queue_loop(__entry, __start, __end) \ + for ((__entry) = (__start); \ + prefetch(&(__entry)[1]), (__entry) != (__end); \ + (__entry) = &(__entry)[1]) + +/** + * queue_for_each - Loop through all queues + * @__dev: Pointer to &struct rt2x00_dev + * @__entry: Pointer where the current queue entry will be stored in. + * + * This macro will loop through all available queues. + */ +#define queue_for_each(__dev, __entry) \ + queue_loop(__entry, (__dev)->rx, queue_end(__dev)) + +/** + * tx_queue_for_each - Loop through the TX queues + * @__dev: Pointer to &struct rt2x00_dev + * @__entry: Pointer where the current queue entry will be stored in. + * + * This macro will loop through all TX related queues excluding + * the Beacon and Atim queues. + */ +#define tx_queue_for_each(__dev, __entry) \ + queue_loop(__entry, (__dev)->tx, tx_queue_end(__dev)) + +/** + * txall_queue_for_each - Loop through all TX related queues + * @__dev: Pointer to &struct rt2x00_dev + * @__entry: Pointer where the current queue entry will be stored in. + * + * This macro will loop through all TX related queues including + * the Beacon and Atim queues. + */ +#define txall_queue_for_each(__dev, __entry) \ + queue_loop(__entry, (__dev)->tx, queue_end(__dev)) + +/** + * rt2x00queue_empty - Check if the queue is empty. + * @queue: Queue to check if empty. + */ +static inline int rt2x00queue_empty(struct data_queue *queue) +{ + return queue->length == 0; +} + +/** + * rt2x00queue_full - Check if the queue is full. + * @queue: Queue to check if full. + */ +static inline int rt2x00queue_full(struct data_queue *queue) +{ + return queue->length == queue->limit; +} + +/** + * rt2x00queue_free - Check the number of available entries in queue. + * @queue: Queue to check. + */ +static inline int rt2x00queue_available(struct data_queue *queue) +{ + return queue->limit - queue->length; +} + +/** + * rt2x00_desc_read - Read a word from the hardware descriptor. + * @desc: Base descriptor address + * @word: Word index from where the descriptor should be read. + * @value: Address where the descriptor value should be written into. + */ +static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) +{ + *value = le32_to_cpu(desc[word]); +} + +/** + * rt2x00_desc_write - wrote a word to the hardware descriptor. + * @desc: Base descriptor address + * @word: Word index from where the descriptor should be written. + * @value: Value that should be written into the descriptor. + */ +static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value) +{ + desc[word] = cpu_to_le32(value); +} + +#endif /* RT2X00QUEUE_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index b1915dc7dda..0325bed2fbf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -29,7 +29,7 @@ /* * TX result flags. */ -enum TX_STATUS { +enum tx_status { TX_SUCCESS = 0, TX_SUCCESS_RETRY = 1, TX_FAIL_RETRY = 2, @@ -220,75 +220,4 @@ static inline u8 rt2x00_get_field8(const u8 reg, return (reg & field.bit_mask) >> field.bit_offset; } -/* - * Device specific rate value. - * We will have to create the device specific rate value - * passed to the ieee80211 kernel. We need to make it a consist of - * multiple fields because we want to store more then 1 device specific - * values inside the value. - * 1 - rate, stored as 100 kbit/s. - * 2 - preamble, short_preamble enabled flag. - * 3 - MASK_RATE, which rates are enabled in this mode, this mask - * corresponds with the TX register format for the current device. - * 4 - plcp, 802.11b rates are device specific, - * 802.11g rates are set according to the ieee802.11a-1999 p.14. - * The bit to enable preamble is set in a seperate define. - */ -#define DEV_RATE FIELD32(0x000007ff) -#define DEV_PREAMBLE FIELD32(0x00000800) -#define DEV_RATEMASK FIELD32(0x00fff000) -#define DEV_PLCP FIELD32(0xff000000) - -/* - * Bitfields - */ -#define DEV_RATEBIT_1MB ( 1 << 0 ) -#define DEV_RATEBIT_2MB ( 1 << 1 ) -#define DEV_RATEBIT_5_5MB ( 1 << 2 ) -#define DEV_RATEBIT_11MB ( 1 << 3 ) -#define DEV_RATEBIT_6MB ( 1 << 4 ) -#define DEV_RATEBIT_9MB ( 1 << 5 ) -#define DEV_RATEBIT_12MB ( 1 << 6 ) -#define DEV_RATEBIT_18MB ( 1 << 7 ) -#define DEV_RATEBIT_24MB ( 1 << 8 ) -#define DEV_RATEBIT_36MB ( 1 << 9 ) -#define DEV_RATEBIT_48MB ( 1 << 10 ) -#define DEV_RATEBIT_54MB ( 1 << 11 ) - -/* - * Bitmasks for DEV_RATEMASK - */ -#define DEV_RATEMASK_1MB ( (DEV_RATEBIT_1MB << 1) -1 ) -#define DEV_RATEMASK_2MB ( (DEV_RATEBIT_2MB << 1) -1 ) -#define DEV_RATEMASK_5_5MB ( (DEV_RATEBIT_5_5MB << 1) -1 ) -#define DEV_RATEMASK_11MB ( (DEV_RATEBIT_11MB << 1) -1 ) -#define DEV_RATEMASK_6MB ( (DEV_RATEBIT_6MB << 1) -1 ) -#define DEV_RATEMASK_9MB ( (DEV_RATEBIT_9MB << 1) -1 ) -#define DEV_RATEMASK_12MB ( (DEV_RATEBIT_12MB << 1) -1 ) -#define DEV_RATEMASK_18MB ( (DEV_RATEBIT_18MB << 1) -1 ) -#define DEV_RATEMASK_24MB ( (DEV_RATEBIT_24MB << 1) -1 ) -#define DEV_RATEMASK_36MB ( (DEV_RATEBIT_36MB << 1) -1 ) -#define DEV_RATEMASK_48MB ( (DEV_RATEBIT_48MB << 1) -1 ) -#define DEV_RATEMASK_54MB ( (DEV_RATEBIT_54MB << 1) -1 ) - -/* - * Bitmask groups of bitrates - */ -#define DEV_BASIC_RATEMASK \ - ( DEV_RATEMASK_11MB | \ - DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB ) - -#define DEV_CCK_RATEMASK ( DEV_RATEMASK_11MB ) -#define DEV_OFDM_RATEMASK ( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK ) - -/* - * Macro's to set and get specific fields from the device specific val and val2 - * fields inside the ieee80211_rate entry. - */ -#define DEVICE_SET_RATE_FIELD(__value, __mask) \ - (int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask ) - -#define DEVICE_GET_RATE_FIELD(__value, __mask) \ - (int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset ) - #endif /* RT2X00REG_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index f9557759620..fcef9885ab5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h deleted file mode 100644 index 1caa6d688c4..00000000000 --- a/drivers/net/wireless/rt2x00/rt2x00ring.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project - <http://rt2x00.serialmonkey.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - Module: rt2x00 - Abstract: rt2x00 ring datastructures and routines - */ - -#ifndef RT2X00RING_H -#define RT2X00RING_H - -/* - * skb_desc - * Descriptor information for the skb buffer - */ -struct skb_desc { - unsigned int frame_type; - - unsigned int desc_len; - unsigned int data_len; - - void *desc; - void *data; - - struct data_ring *ring; - struct data_entry *entry; -}; - -static inline struct skb_desc* get_skb_desc(struct sk_buff *skb) -{ - return (struct skb_desc*)&skb->cb[0]; -} - -/* - * rxdata_entry_desc - * Summary of information that has been read from the - * RX frame descriptor. - */ -struct rxdata_entry_desc { - int signal; - int rssi; - int ofdm; - int size; - int flags; - int my_bss; -}; - -/* - * txdata_entry_desc - * Summary of information that should be written into the - * descriptor for sending a TX frame. - */ -struct txdata_entry_desc { - unsigned long flags; -#define ENTRY_TXDONE 1 -#define ENTRY_TXD_RTS_FRAME 2 -#define ENTRY_TXD_OFDM_RATE 3 -#define ENTRY_TXD_MORE_FRAG 4 -#define ENTRY_TXD_REQ_TIMESTAMP 5 -#define ENTRY_TXD_BURST 6 -#define ENTRY_TXD_ACK 7 - -/* - * Queue ID. ID's 0-4 are data TX rings - */ - int queue; -#define QUEUE_MGMT 13 -#define QUEUE_RX 14 -#define QUEUE_OTHER 15 - - /* - * PLCP values. - */ - u16 length_high; - u16 length_low; - u16 signal; - u16 service; - - /* - * Timing information - */ - int aifs; - int ifs; - int cw_min; - int cw_max; -}; - -/* - * data_entry - * The data ring is a list of data entries. - * Each entry holds a reference to the descriptor - * and the data buffer. For TX rings the reference to the - * sk_buff of the packet being transmitted is also stored here. - */ -struct data_entry { - /* - * Status flags - */ - unsigned long flags; -#define ENTRY_OWNER_NIC 1 - - /* - * Ring we belong to. - */ - struct data_ring *ring; - - /* - * sk_buff for the packet which is being transmitted - * in this entry (Only used with TX related rings). - */ - struct sk_buff *skb; - - /* - * Store a ieee80211_tx_status structure in each - * ring entry, this will optimize the txdone - * handler. - */ - struct ieee80211_tx_status tx_status; - - /* - * private pointer specific to driver. - */ - void *priv; - - /* - * Data address for this entry. - */ - void *data_addr; - dma_addr_t data_dma; - - /* - * Entry identification number (index). - */ - unsigned int entry_idx; -}; - -/* - * data_ring - * Data rings are used by the device to send and receive packets. - * The data_addr is the base address of the data memory. - * To determine at which point in the ring we are, - * have to use the rt2x00_ring_index_*() functions. - */ -struct data_ring { - /* - * Pointer to main rt2x00dev structure where this - * ring belongs to. - */ - struct rt2x00_dev *rt2x00dev; - - /* - * Base address for the device specific data entries. - */ - struct data_entry *entry; - - /* - * TX queue statistic info. - */ - struct ieee80211_tx_queue_stats_data stats; - - /* - * TX Queue parameters. - */ - struct ieee80211_tx_queue_params tx_params; - - /* - * Base address for data ring. - */ - dma_addr_t data_dma; - void *data_addr; - - /* - * Queue identification number: - * RX: 0 - * TX: IEEE80211_TX_* - */ - unsigned int queue_idx; - - /* - * Index variables. - */ - u16 index; - u16 index_done; - - /* - * Size of packet and descriptor in bytes. - */ - u16 data_size; - u16 desc_size; -}; - -/* - * Handlers to determine the address of the current device specific - * data entry, where either index or index_done points to. - */ -static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring) -{ - return &ring->entry[ring->index]; -} - -static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring - *ring) -{ - return &ring->entry[ring->index_done]; -} - -/* - * Total ring memory - */ -static inline int rt2x00_get_ring_size(struct data_ring *ring) -{ - return ring->stats.limit * (ring->desc_size + ring->data_size); -} - -/* - * Ring index manipulation functions. - */ -static inline void rt2x00_ring_index_inc(struct data_ring *ring) -{ - ring->index++; - if (ring->index >= ring->stats.limit) - ring->index = 0; - ring->stats.len++; -} - -static inline void rt2x00_ring_index_done_inc(struct data_ring *ring) -{ - ring->index_done++; - if (ring->index_done >= ring->stats.limit) - ring->index_done = 0; - ring->stats.len--; - ring->stats.count++; -} - -static inline void rt2x00_ring_index_clear(struct data_ring *ring) -{ - ring->index = 0; - ring->index_done = 0; - ring->stats.len = 0; - ring->stats.count = 0; -} - -static inline int rt2x00_ring_empty(struct data_ring *ring) -{ - return ring->stats.len == 0; -} - -static inline int rt2x00_ring_full(struct data_ring *ring) -{ - return ring->stats.len == ring->stats.limit; -} - -static inline int rt2x00_ring_free(struct data_ring *ring) -{ - return ring->stats.limit - ring->stats.len; -} - -/* - * TX/RX Descriptor access functions. - */ -static inline void rt2x00_desc_read(__le32 *desc, - const u8 word, u32 *value) -{ - *value = le32_to_cpu(desc[word]); -} - -static inline void rt2x00_desc_write(__le32 *desc, - const u8 word, const u32 value) -{ - desc[word] = cpu_to_le32(value); -} - -#endif /* RT2X00RING_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 84e9bdb7391..5a331674dcb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -40,8 +40,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, void *buffer, const u16 buffer_length, const int timeout) { - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); int status; unsigned int i; unsigned int pipe = @@ -85,20 +84,20 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, /* * Check for Cache availability. */ - if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) { + if (unlikely(!rt2x00dev->csr.cache || buffer_length > CSR_CACHE_SIZE)) { ERROR(rt2x00dev, "CSR cache not available.\n"); return -ENOMEM; } if (requesttype == USB_VENDOR_REQUEST_OUT) - memcpy(rt2x00dev->csr_cache, buffer, buffer_length); + memcpy(rt2x00dev->csr.cache, buffer, buffer_length); status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype, - offset, 0, rt2x00dev->csr_cache, + offset, 0, rt2x00dev->csr.cache, buffer_length, timeout); if (!status && requesttype == USB_VENDOR_REQUEST_IN) - memcpy(buffer, rt2x00dev->csr_cache, buffer_length); + memcpy(buffer, rt2x00dev->csr.cache, buffer_length); return status; } @@ -128,15 +127,15 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); */ static void rt2x00usb_interrupt_txdone(struct urb *urb) { - struct data_entry *entry = (struct data_entry *)urb->context; - struct data_ring *ring = entry->ring; - struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; + struct queue_entry *entry = (struct queue_entry *)urb->context; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct txdone_entry_desc txdesc; __le32 *txd = (__le32 *)entry->skb->data; u32 word; - int tx_status; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) + !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; rt2x00_desc_read(txd, 0, &word); @@ -144,45 +143,46 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) /* * Remove the descriptor data from the buffer. */ - skb_pull(entry->skb, ring->desc_size); + skb_pull(entry->skb, entry->queue->desc_size); /* * Obtain the status about this packet. */ - tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + txdesc.retry = 0; + txdesc.control = &priv_tx->control; - rt2x00lib_txdone(entry, tx_status, 0); + rt2x00lib_txdone(entry, &txdesc); /* * Make this entry available for reuse. */ entry->flags = 0; - rt2x00_ring_index_done_inc(entry->ring); + rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* - * If the data ring was full before the txdone handler + * If the data queue was full before the txdone handler * we must make sure the packet queue in the mac80211 stack * is reenabled when the txdone handler has finished. */ - if (!rt2x00_ring_full(ring)) - ieee80211_wake_queue(rt2x00dev->hw, - entry->tx_status.control.queue); + if (!rt2x00queue_full(entry->queue)) + ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); } int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *skb, + struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - struct data_entry *entry = rt2x00_get_data_entry(ring); - struct skb_desc *desc; + struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); + struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); + struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; + struct skb_frame_desc *skbdesc; u32 length; - if (rt2x00_ring_full(ring)) + if (rt2x00queue_full(queue)) return -EINVAL; - if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) { + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", @@ -193,20 +193,20 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Add the descriptor in front of the skb. */ - skb_push(skb, ring->desc_size); - memset(skb->data, 0, ring->desc_size); + skb_push(skb, queue->desc_size); + memset(skb->data, 0, queue->desc_size); /* * Fill in skb descriptor */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len - ring->desc_size; - desc->desc = skb->data; - desc->data = skb->data + ring->desc_size; - desc->ring = ring; - desc->entry = entry; + skbdesc = get_skb_frame_desc(skb); + skbdesc->data = skb->data + queue->desc_size; + skbdesc->data_len = skb->len - queue->desc_size; + skbdesc->desc = skb->data; + skbdesc->desc_len = queue->desc_size; + skbdesc->entry = entry; + memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* @@ -219,12 +219,12 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Initialize URB and send the frame to the device. */ - __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_fill_bulk_urb(entry->priv, usb_dev, usb_sndbulkpipe(usb_dev, 1), + __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), skb->data, length, rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(entry->priv, GFP_ATOMIC); + usb_submit_urb(priv_tx->urb, GFP_ATOMIC); - rt2x00_ring_index_inc(ring); + rt2x00queue_index_inc(queue, Q_INDEX); return 0; } @@ -233,20 +233,42 @@ EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); /* * RX data handlers. */ +static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue) +{ + struct sk_buff *skb; + unsigned int frame_size; + + /* + * As alignment we use 2 and not NET_IP_ALIGN because we need + * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN + * can be 0 on some hardware). We use these 2 bytes for frame + * alignment later, we assume that the chance that + * header_size % 4 == 2 is bigger then header_size % 2 == 0 + * and thus optimize alignment by reserving the 2 bytes in + * advance. + */ + frame_size = queue->data_size + queue->desc_size; + skb = dev_alloc_skb(queue->desc_size + frame_size + 2); + if (!skb) + return NULL; + + skb_reserve(skb, queue->desc_size + 2); + skb_put(skb, frame_size); + + return skb; +} + static void rt2x00usb_interrupt_rxdone(struct urb *urb) { - struct data_entry *entry = (struct data_entry *)urb->context; - struct data_ring *ring = entry->ring; - struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; + struct queue_entry *entry = (struct queue_entry *)urb->context; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct skb_desc *skbdesc; - struct rxdata_entry_desc desc; + struct skb_frame_desc *skbdesc; + struct rxdone_entry_desc rxdesc; int header_size; - int frame_size; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) + !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -254,67 +276,45 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * to be actually valid, or if the urb is signaling * a problem. */ - if (urb->actual_length < entry->ring->desc_size || urb->status) + if (urb->actual_length < entry->queue->desc_size || urb->status) goto skip_entry; /* * Fill in skb descriptor */ - skbdesc = get_skb_desc(entry->skb); - skbdesc->ring = ring; + skbdesc = get_skb_frame_desc(entry->skb); + memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; - memset(&desc, 0, sizeof(desc)); - rt2x00dev->ops->lib->fill_rxdone(entry, &desc); - - /* - * Allocate a new sk buffer to replace the current one. - * If allocation fails, we should drop the current frame - * so we can recycle the existing sk buffer for the new frame. - * As alignment we use 2 and not NET_IP_ALIGN because we need - * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN - * can be 0 on some hardware). We use these 2 bytes for frame - * alignment later, we assume that the chance that - * header_size % 4 == 2 is bigger then header_size % 2 == 0 - * and thus optimize alignment by reserving the 2 bytes in - * advance. - */ - frame_size = entry->ring->data_size + entry->ring->desc_size; - skb = dev_alloc_skb(frame_size + 2); - if (!skb) - goto skip_entry; - - skb_reserve(skb, 2); - skb_put(skb, frame_size); + memset(&rxdesc, 0, sizeof(rxdesc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ - hdr = (struct ieee80211_hdr *)entry->skb->data; - header_size = - ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - + header_size = ieee80211_get_hdrlen_from_skb(entry->skb); if (header_size % 4 == 0) { skb_push(entry->skb, 2); - memmove(entry->skb->data, entry->skb->data + 2, skb->len - 2); + memmove(entry->skb->data, entry->skb->data + 2, + entry->skb->len - 2); + skbdesc->data = entry->skb->data; + skb_trim(entry->skb,entry->skb->len - 2); } /* - * Trim the entire buffer down to only contain the valid frame data - * excluding the device descriptor. The position of the descriptor - * varies. This means that we should check where the descriptor is - * and decide if we need to pull the data pointer to exclude the - * device descriptor. + * Allocate a new sk buffer to replace the current one. + * If allocation fails, we should drop the current frame + * so we can recycle the existing sk buffer for the new frame. */ - if (skbdesc->data > skbdesc->desc) - skb_pull(entry->skb, skbdesc->desc_len); - skb_trim(entry->skb, desc.size); + skb = rt2x00usb_alloc_rxskb(entry->queue); + if (!skb) + goto skip_entry; /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, entry->skb, &desc); + rt2x00lib_rxdone(entry, &rxdesc); /* * Replace current entry's skb with the newly allocated one, @@ -325,12 +325,12 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) urb->transfer_buffer_length = entry->skb->len; skip_entry: - if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - __set_bit(ENTRY_OWNER_NIC, &entry->flags); + if (test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) { + __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(urb, GFP_ATOMIC); } - rt2x00_ring_index_inc(ring); + rt2x00queue_index_inc(entry->queue, Q_INDEX); } /* @@ -338,18 +338,44 @@ skip_entry: */ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; + struct queue_entry_priv_usb_rx *priv_rx; + struct queue_entry_priv_usb_tx *priv_tx; + struct queue_entry_priv_usb_bcn *priv_bcn; + struct data_queue *queue; unsigned int i; rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000, REGISTER_TIMEOUT); /* - * Cancel all rings. + * Cancel all queues. */ - ring_for_each(rt2x00dev, ring) { - for (i = 0; i < ring->stats.limit; i++) - usb_kill_urb(ring->entry[i].priv); + for (i = 0; i < rt2x00dev->rx->limit; i++) { + priv_rx = rt2x00dev->rx->entries[i].priv_data; + usb_kill_urb(priv_rx->urb); + } + + tx_queue_for_each(rt2x00dev, queue) { + for (i = 0; i < queue->limit; i++) { + priv_tx = queue->entries[i].priv_data; + usb_kill_urb(priv_tx->urb); + } + } + + for (i = 0; i < rt2x00dev->bcn->limit; i++) { + priv_bcn = rt2x00dev->bcn->entries[i].priv_data; + usb_kill_urb(priv_bcn->urb); + + if (priv_bcn->guardian_urb) + usb_kill_urb(priv_bcn->guardian_urb); + } + + if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) + return; + + for (i = 0; i < rt2x00dev->bcn[1].limit; i++) { + priv_tx = rt2x00dev->bcn[1].entries[i].priv_data; + usb_kill_urb(priv_tx->urb); } } EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); @@ -358,64 +384,108 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); * Device initialization handlers. */ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); + struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; - usb_fill_bulk_urb(entry->priv, usb_dev, + usb_fill_bulk_urb(priv_rx->urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1), entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); - __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_submit_urb(entry->priv, GFP_ATOMIC); + __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(priv_rx->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { entry->flags = 0; } EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring) + struct data_queue *queue) { + struct queue_entry_priv_usb_rx *priv_rx; + struct queue_entry_priv_usb_tx *priv_tx; + struct queue_entry_priv_usb_bcn *priv_bcn; + struct urb *urb; + unsigned int guardian = + test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); unsigned int i; /* * Allocate the URB's */ - for (i = 0; i < ring->stats.limit; i++) { - ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL); - if (!ring->entry[i].priv) + for (i = 0; i < queue->limit; i++) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) return -ENOMEM; + + if (queue->qid == QID_RX) { + priv_rx = queue->entries[i].priv_data; + priv_rx->urb = urb; + } else if (queue->qid == QID_MGMT && guardian) { + priv_bcn = queue->entries[i].priv_data; + priv_bcn->urb = urb; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + + priv_bcn->guardian_urb = urb; + } else { + priv_tx = queue->entries[i].priv_data; + priv_tx->urb = urb; + } } return 0; } static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring) + struct data_queue *queue) { + struct queue_entry_priv_usb_rx *priv_rx; + struct queue_entry_priv_usb_tx *priv_tx; + struct queue_entry_priv_usb_bcn *priv_bcn; + struct urb *urb; + unsigned int guardian = + test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); unsigned int i; - if (!ring->entry) + if (!queue->entries) return; - for (i = 0; i < ring->stats.limit; i++) { - usb_kill_urb(ring->entry[i].priv); - usb_free_urb(ring->entry[i].priv); - if (ring->entry[i].skb) - kfree_skb(ring->entry[i].skb); + for (i = 0; i < queue->limit; i++) { + if (queue->qid == QID_RX) { + priv_rx = queue->entries[i].priv_data; + urb = priv_rx->urb; + } else if (queue->qid == QID_MGMT && guardian) { + priv_bcn = queue->entries[i].priv_data; + + usb_kill_urb(priv_bcn->guardian_urb); + usb_free_urb(priv_bcn->guardian_urb); + + urb = priv_bcn->urb; + } else { + priv_tx = queue->entries[i].priv_data; + urb = priv_tx->urb; + } + + usb_kill_urb(urb); + usb_free_urb(urb); + if (queue->entries[i].skb) + kfree_skb(queue->entries[i].skb); } } int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; + struct data_queue *queue; struct sk_buff *skb; unsigned int entry_size; unsigned int i; @@ -424,25 +494,22 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) /* * Allocate DMA */ - ring_for_each(rt2x00dev, ring) { - status = rt2x00usb_alloc_urb(rt2x00dev, ring); + queue_for_each(rt2x00dev, queue) { + status = rt2x00usb_alloc_urb(rt2x00dev, queue); if (status) goto exit; } /* - * For the RX ring, skb's should be allocated. + * For the RX queue, skb's should be allocated. */ entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size; - for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { - skb = dev_alloc_skb(NET_IP_ALIGN + entry_size); + for (i = 0; i < rt2x00dev->rx->limit; i++) { + skb = rt2x00usb_alloc_rxskb(rt2x00dev->rx); if (!skb) goto exit; - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, entry_size); - - rt2x00dev->rx->entry[i].skb = skb; + rt2x00dev->rx->entries[i].skb = skb; } return 0; @@ -456,10 +523,10 @@ EXPORT_SYMBOL_GPL(rt2x00usb_initialize); void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; + struct data_queue *queue; - ring_for_each(rt2x00dev, ring) - rt2x00usb_free_urb(rt2x00dev, ring); + queue_for_each(rt2x00dev, queue) + rt2x00usb_free_urb(rt2x00dev, queue); } EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize); @@ -474,14 +541,14 @@ static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev) kfree(rt2x00dev->eeprom); rt2x00dev->eeprom = NULL; - kfree(rt2x00dev->csr_cache); - rt2x00dev->csr_cache = NULL; + kfree(rt2x00dev->csr.cache); + rt2x00dev->csr.cache = NULL; } static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev) { - rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL); - if (!rt2x00dev->csr_cache) + rt2x00dev->csr.cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL); + if (!rt2x00dev->csr.cache) goto exit; rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); @@ -627,9 +694,9 @@ EXPORT_SYMBOL_GPL(rt2x00usb_resume); #endif /* CONFIG_PM */ /* - * rt2x00pci module information. + * rt2x00usb module information. */ MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); -MODULE_DESCRIPTION("rt2x00 library"); +MODULE_DESCRIPTION("rt2x00 usb library"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index e40df4050cd..11e55180cba 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -60,34 +60,47 @@ #define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST ) #define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST ) -/* - * USB vendor commands. - */ -#define USB_DEVICE_MODE 0x01 -#define USB_SINGLE_WRITE 0x02 -#define USB_SINGLE_READ 0x03 -#define USB_MULTI_WRITE 0x06 -#define USB_MULTI_READ 0x07 -#define USB_EEPROM_WRITE 0x08 -#define USB_EEPROM_READ 0x09 -#define USB_LED_CONTROL 0x0a /* RT73USB */ -#define USB_RX_CONTROL 0x0c +/** + * enum rt2x00usb_vendor_request: USB vendor commands. + */ +enum rt2x00usb_vendor_request { + USB_DEVICE_MODE = 1, + USB_SINGLE_WRITE = 2, + USB_SINGLE_READ = 3, + USB_MULTI_WRITE = 6, + USB_MULTI_READ = 7, + USB_EEPROM_WRITE = 8, + USB_EEPROM_READ = 9, + USB_LED_CONTROL = 10, /* RT73USB */ + USB_RX_CONTROL = 12, +}; -/* - * Device modes offset +/** + * enum rt2x00usb_mode_offset: Device modes offset. */ -#define USB_MODE_RESET 0x01 -#define USB_MODE_UNPLUG 0x02 -#define USB_MODE_FUNCTION 0x03 -#define USB_MODE_TEST 0x04 -#define USB_MODE_SLEEP 0x07 /* RT73USB */ -#define USB_MODE_FIRMWARE 0x08 /* RT73USB */ -#define USB_MODE_WAKEUP 0x09 /* RT73USB */ +enum rt2x00usb_mode_offset { + USB_MODE_RESET = 1, + USB_MODE_UNPLUG = 2, + USB_MODE_FUNCTION = 3, + USB_MODE_TEST = 4, + USB_MODE_SLEEP = 7, /* RT73USB */ + USB_MODE_FIRMWARE = 8, /* RT73USB */ + USB_MODE_WAKEUP = 9, /* RT73USB */ +}; -/* - * Used to read/write from/to the device. +/** + * rt2x00usb_vendor_request - Send register command to device + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @request: USB vendor command (See &enum rt2x00usb_vendor_request) + * @requesttype: Request type &USB_VENDOR_REQUEST_* + * @offset: Register offset to perform action on + * @value: Value to write to device + * @buffer: Buffer where information will be read/written to by device + * @buffer_length: Size of &buffer + * @timeout: Operation timeout + * * This is the main function to communicate with the device, - * the buffer argument _must_ either be NULL or point to + * the &buffer argument _must_ either be NULL or point to * a buffer allocated by kmalloc. Failure to do so can lead * to unexpected behavior depending on the architecture. */ @@ -97,13 +110,21 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, void *buffer, const u16 buffer_length, const int timeout); -/* - * Used to read/write from/to the device. +/** + * rt2x00usb_vendor_request_buff - Send register command to device (buffered) + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @request: USB vendor command (See &enum rt2x00usb_vendor_request) + * @requesttype: Request type &USB_VENDOR_REQUEST_* + * @offset: Register offset to perform action on + * @buffer: Buffer where information will be read/written to by device + * @buffer_length: Size of &buffer + * @timeout: Operation timeout + * * This function will use a previously with kmalloc allocated cache * to communicate with the device. The contents of the buffer pointer * will be copied to this cache when writing, or read from the cache * when reading. - * Buffers send to rt2x00usb_vendor_request _must_ be allocated with + * Buffers send to &rt2x00usb_vendor_request _must_ be allocated with * kmalloc. Hence the reason for using a previously allocated cache * which has been allocated properly. */ @@ -112,15 +133,32 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, const u16 offset, void *buffer, const u16 buffer_length, const int timeout); -/* - * A version of rt2x00usb_vendor_request_buff which must be called - * if the usb_cache_mutex is already held. */ +/** + * rt2x00usb_vendor_request_buff - Send register command to device (buffered) + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @request: USB vendor command (See &enum rt2x00usb_vendor_request) + * @requesttype: Request type &USB_VENDOR_REQUEST_* + * @offset: Register offset to perform action on + * @buffer: Buffer where information will be read/written to by device + * @buffer_length: Size of &buffer + * @timeout: Operation timeout + * + * A version of &rt2x00usb_vendor_request_buff which must be called + * if the usb_cache_mutex is already held. + */ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, const u16 buffer_length, const int timeout); -/* +/** + * rt2x00usb_vendor_request_sw - Send single register command to device + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @request: USB vendor command (See &enum rt2x00usb_vendor_request) + * @offset: Register offset to perform action on + * @value: Value to write to device + * @timeout: Operation timeout + * * Simple wrapper around rt2x00usb_vendor_request to write a single * command to the device. Since we don't use the buffer argument we * don't have to worry about kmalloc here. @@ -136,7 +174,12 @@ static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev, value, NULL, 0, timeout); } -/* +/** + * rt2x00usb_eeprom_read - Read eeprom from device + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @eeprom: Pointer to eeprom array to store the information in + * @length: Number of bytes to read from the eeprom + * * Simple wrapper around rt2x00usb_vendor_request to read the eeprom * from the device. Note that the eeprom argument _must_ be allocated using * kmalloc for correct handling inside the kernel USB layer. @@ -147,8 +190,8 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, - USB_VENDOR_REQUEST_IN, 0x0000, - 0x0000, eeprom, lenght, timeout); + USB_VENDOR_REQUEST_IN, 0, 0, + eeprom, lenght, timeout); } /* @@ -160,16 +203,58 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); * TX data handlers. */ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, - struct data_ring *ring, struct sk_buff *skb, + struct data_queue *queue, struct sk_buff *skb, struct ieee80211_tx_control *control); +/** + * struct queue_entry_priv_usb_rx: Per RX entry USB specific information + * + * @urb: Urb structure used for device communication. + */ +struct queue_entry_priv_usb_rx { + struct urb *urb; +}; + +/** + * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * + * @urb: Urb structure used for device communication. + * @control: mac80211 control structure used to transmit data. + */ +struct queue_entry_priv_usb_tx { + struct urb *urb; + + struct ieee80211_tx_control control; +}; + +/** + * struct queue_entry_priv_usb_tx: Per TX entry USB specific information + * + * The first section should match &struct queue_entry_priv_usb_tx exactly. + * rt2500usb can use this structure to send a guardian byte when working + * with beacons. + * + * @urb: Urb structure used for device communication. + * @control: mac80211 control structure used to transmit data. + * @guardian_data: Set to 0, used for sending the guardian data. + * @guardian_urb: Urb structure used to send the guardian data. + */ +struct queue_entry_priv_usb_bcn { + struct urb *urb; + + struct ieee80211_tx_control control; + + unsigned int guardian_data; + struct urb *guardian_urb; +}; + /* * Device initialization handlers. */ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry); + struct queue_entry *entry); void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry); + struct queue_entry *entry); int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ad2e7d53b3d..468a31c8c11 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ Supported chipsets: RT2561, RT2561s, RT2661. */ +#include <linux/crc-itu-t.h> #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -155,6 +156,12 @@ rf_write: rt2x00_rf_write(rt2x00dev, word, value); } +#ifdef CONFIG_RT61PCI_LEDS +/* + * This function is only called from rt61pci_led_brightness() + * make gcc happy by placing this function inside the + * same ifdef statement as the caller. + */ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1) @@ -181,6 +188,7 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } +#endif /* CONFIG_RT61PCI_LEDS */ static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) { @@ -262,82 +270,162 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) u32 reg; rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); - return rt2x00_get_field32(reg, MAC_CSR13_BIT5);; + return rt2x00_get_field32(reg, MAC_CSR13_BIT5); } #else #define rt61pci_rfkill_poll NULL #endif /* CONFIG_RT61PCI_RFKILL */ -/* - * Configuration handlers. - */ -static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) +#ifdef CONFIG_RT61PCI_LEDS +static void rt61pci_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - 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))); + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + unsigned int a_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_5GHZ); + unsigned int bg_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); + + if (led->type == LED_TYPE_RADIO) { + rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, + MCU_LEDCS_RADIO_STATUS, enabled); + + rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, + (led->rt2x00dev->led_mcu_reg & 0xff), + ((led->rt2x00dev->led_mcu_reg >> 8))); + } else if (led->type == LED_TYPE_ASSOC) { + rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, + MCU_LEDCS_LINK_BG_STATUS, bg_mode); + rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, + MCU_LEDCS_LINK_A_STATUS, a_mode); + + rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, + (led->rt2x00dev->led_mcu_reg & 0xff), + ((led->rt2x00dev->led_mcu_reg >> 8))); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * this means we need to convert the brightness + * argument into the matching level within that range. + */ + rt61pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + brightness / (LED_FULL / 6), 0); + } } -static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) +static int rt61pci_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { - u32 tmp; + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; - tmp = le32_to_cpu(bssid[1]); - rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - bssid[1] = cpu_to_le32(tmp); + rt2x00pci_register_read(led->rt2x00dev, MAC_CSR14, ®); + rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); + rt2x00pci_register_write(led->rt2x00dev, MAC_CSR14, reg); - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, - (2 * sizeof(__le32))); + return 0; } +#endif /* CONFIG_RT61PCI_LEDS */ -static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +/* + * Configuration handlers. + */ +static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) { u32 reg; /* - * 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. + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. */ - 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); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(filter_flags & FIF_PROMISC_IN_BSS) && + !rt2x00dev->intf_ap_count); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, + !(filter_flags & FIF_CONTROL)); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, 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); +static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) +{ + unsigned int beacon_base; + u32 reg; + + 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, beacon_base, 0); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + } + + 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); + + 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(®, 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, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) { u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - !!short_preamble); + !!erp->short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } @@ -427,27 +515,21 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - (rt2x00dev->curr_hwmode != HWMODE_A)); + (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ)); break; case ANTENNA_A: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); @@ -486,14 +568,8 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); break; @@ -531,10 +607,6 @@ static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 4, &r4); rt61pci_bbp_read(rt2x00dev, 77, &r77); - /* FIXME: Antenna selection for the rf 2529 is very confusing in the - * legacy driver. The code below should be ok for non-diversity setups. - */ - /* * Configure the RX antenna. */ @@ -544,15 +616,14 @@ static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); break; - case ANTENNA_SW_DIVERSITY: case ANTENNA_HW_DIVERSITY: /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. + * FIXME: Antenna selection for the rf 2529 is very confusing + * in the legacy driver. Just default to antenna B until the + * legacy code can be properly translated into rt2x00 code. */ case ANTENNA_B: + default: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); @@ -603,7 +674,14 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, unsigned int i; u32 reg; - if (rt2x00dev->curr_hwmode == HWMODE_A) { + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); } else { @@ -617,10 +695,9 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, - (rt2x00dev->curr_hwmode == HWMODE_B || - rt2x00dev->curr_hwmode == HWMODE_G)); + rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, - (rt2x00dev->curr_hwmode == HWMODE_A)); + rt2x00dev->curr_band == IEEE80211_BAND_5GHZ); rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); @@ -667,8 +744,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); @@ -684,78 +761,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, } /* - * LED functions. - */ -static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - u8 arg0; - u8 arg1; - - rt2x00pci_register_read(rt2x00dev, MAC_CSR14, ®); - rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70); - rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); - rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg); - - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, - (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, - (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); - - arg0 = rt2x00dev->led_reg & 0xff; - arg1 = (rt2x00dev->led_reg >> 8) & 0xff; - - rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); -} - -static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev) -{ - u16 led_reg; - u8 arg0; - u8 arg1; - - led_reg = rt2x00dev->led_reg; - rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0); - rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0); - rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0); - - arg0 = led_reg & 0xff; - arg1 = (led_reg >> 8) & 0xff; - - rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); -} - -static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) -{ - u8 led; - - if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) - return; - - /* - * Led handling requires a positive value for the rssi, - * to do that correctly we need to add the correction. - */ - rssi += rt2x00dev->rssi_offset; - - if (rssi <= 30) - led = 0; - else if (rssi <= 39) - led = 1; - else if (rssi <= 49) - led = 2; - else if (rssi <= 53) - led = 3; - else if (rssi <= 63) - led = 4; - else - led = 5; - - rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0); -} - -/* * Link tuning */ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, @@ -789,17 +794,12 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) u8 up_bound; u8 low_bound; - /* - * Update Led strength - */ - rt61pci_activity_led(rt2x00dev, rssi); - rt61pci_bbp_read(rt2x00dev, 17, &r17); /* * Determine r17 bounds. */ - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { @@ -816,6 +816,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 +873,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. @@ -882,7 +891,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) } /* - * Firmware name function. + * Firmware functions */ static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) { @@ -906,9 +915,23 @@ static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) return fw_name; } -/* - * Initialization functions. - */ +static u16 rt61pci_get_firmware_crc(void *data, const size_t len) +{ + u16 crc; + + /* + * Use the crc itu-t algorithm. + * The last 2 bytes in the firmware array are the crc checksum itself, + * this means that we should never pass those 2 bytes to the crc + * algorithm. + */ + crc = crc_itu_t(0, data, len - 2); + crc = crc_itu_t_byte(crc, 0); + crc = crc_itu_t_byte(crc, 0); + + return crc; +} + static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, const size_t len) { @@ -989,50 +1012,55 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, return 0; } +/* + * Initialization functions. + */ static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - __le32 *rxd = entry->priv; + struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; u32 word; - rt2x00_desc_read(rxd, 5, &word); + rt2x00_desc_read(priv_rx->desc, 5, &word); rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - entry->data_dma); - rt2x00_desc_write(rxd, 5, word); + priv_rx->data_dma); + rt2x00_desc_write(priv_rx->desc, 5, word); - rt2x00_desc_read(rxd, 0, &word); + rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); + rt2x00_desc_write(priv_rx->desc, 0, word); } static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry) + struct queue_entry *entry) { - __le32 *txd = entry->priv; + struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; u32 word; - rt2x00_desc_read(txd, 1, &word); + rt2x00_desc_read(priv_tx->desc, 1, &word); rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); - rt2x00_desc_write(txd, 1, word); + rt2x00_desc_write(priv_tx->desc, 1, word); - rt2x00_desc_read(txd, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->ring->queue_idx); + rt2x00_desc_read(priv_tx->desc, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); - rt2x00_desc_write(txd, 5, word); + rt2x00_desc_write(priv_tx->desc, 5, word); - rt2x00_desc_read(txd, 6, &word); + rt2x00_desc_read(priv_tx->desc, 6, &word); rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, - entry->data_dma); - rt2x00_desc_write(txd, 6, word); + priv_tx->data_dma); + rt2x00_desc_write(priv_tx->desc, 6, word); - rt2x00_desc_read(txd, 0, &word); + rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(txd, 0, word); + rt2x00_desc_write(priv_tx->desc, 0, word); } -static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) +static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) { + struct queue_entry_priv_pci_rx *priv_rx; + struct queue_entry_priv_pci_tx *priv_tx; u32 reg; /* @@ -1040,59 +1068,55 @@ static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) */ rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, ®); rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00dev->tx[0].limit); rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00dev->tx[1].limit); rt2x00_set_field32(®, TX_RING_CSR0_AC2_RING_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit); + rt2x00dev->tx[2].limit); rt2x00_set_field32(®, TX_RING_CSR0_AC3_RING_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit); + rt2x00dev->tx[3].limit); rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, ®); - rt2x00_set_field32(®, TX_RING_CSR1_MGMT_RING_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit); rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size / - 4); + rt2x00dev->tx[0].desc_size / 4); rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); + priv_tx = rt2x00dev->tx[0].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®); rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); + priv_tx = rt2x00dev->tx[1].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®); rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); + priv_tx = rt2x00dev->tx[2].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®); rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); + priv_tx = rt2x00dev->tx[3].entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®); rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma); + priv_tx->desc_dma); rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); - rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, ®); - rt2x00_set_field32(®, MGMT_BASE_CSR_RING_REGISTER, - rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma); - rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg); - rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®); - rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, - rt2x00dev->rx->stats.limit); + rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit); rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, rt2x00dev->rx->desc_size / 4); rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); + priv_rx = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®); rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, - rt2x00dev->rx->data_dma); + priv_rx->desc_dma); rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); @@ -1100,7 +1124,6 @@ static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); - rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_MGMT, 0); rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, ®); @@ -1108,7 +1131,6 @@ static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); - rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1); rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, ®); @@ -1224,6 +1246,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. @@ -1296,19 +1329,15 @@ continue_csr_init: rt61pci_bbp_write(rt2x00dev, 102, 0x16); rt61pci_bbp_write(rt2x00dev, 107, 0x04); - DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); for (i = 0; i < EEPROM_BBP_SIZE; i++) { rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", - reg_id, value); rt61pci_bbp_write(rt2x00dev, reg_id, value); } } - DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); return 0; } @@ -1375,7 +1404,7 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (rt61pci_init_rings(rt2x00dev) || + if (rt61pci_init_queues(rt2x00dev) || rt61pci_init_registers(rt2x00dev) || rt61pci_init_bbp(rt2x00dev)) { ERROR(rt2x00dev, "Register initialization failed.\n"); @@ -1394,11 +1423,6 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg); - /* - * Enable LED - */ - rt61pci_enable_led(rt2x00dev); - return 0; } @@ -1406,11 +1430,6 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - /* - * Disable LED - */ - rt61pci_disable_led(rt2x00dev); - rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818); /* @@ -1426,7 +1445,6 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_MGMT, 1); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); /* @@ -1508,10 +1526,10 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txdata_entry_desc *desc, + struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { - struct skb_desc *skbdesc = get_skb_desc(skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; u32 word; @@ -1519,50 +1537,52 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue); - rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs); - rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); - rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue); + rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); - rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, - TXPOWER_TO_DEV(control->power_level)); + TXPOWER_TO_DEV(rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); - rt2x00_desc_read(txd, 11, &word); - rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len); - rt2x00_desc_write(txd, 11, word); + if (skbdesc->desc_len > TXINFO_SIZE) { + rt2x00_desc_read(txd, 11, &word); + rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len); + rt2x00_desc_write(txd, 11, word); + } rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, - test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - test_bit(ENTRY_TXD_ACK, &desc->flags)); + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, - test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, - test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); - rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST, - test_bit(ENTRY_TXD_BURST, &desc->flags)); + test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } @@ -1571,11 +1591,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - unsigned int queue) + const unsigned int queue) { u32 reg; - if (queue == IEEE80211_TX_QUEUE_BEACON) { + if (queue == RT2X00_BCN_QUEUE_BEACON) { /* * For Wi-Fi faily generated beacons between participating * stations. Set TBTT phase adaptive adjustment step to 8us. @@ -1584,6 +1604,8 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1599,8 +1621,6 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, (queue == IEEE80211_TX_QUEUE_DATA2)); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue == IEEE80211_TX_QUEUE_DATA3)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, - (queue == IEEE80211_TX_QUEUE_DATA4)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } @@ -1628,7 +1648,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return 0; } - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) offset += 14; @@ -1648,28 +1668,35 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static void rt61pci_fill_rxdone(struct data_entry *entry, - struct rxdata_entry_desc *desc) +static void rt61pci_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) { - __le32 *rxd = entry->priv; + struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; u32 word0; u32 word1; - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 1, &word1); + rt2x00_desc_read(priv_rx->desc, 0, &word0); + rt2x00_desc_read(priv_rx->desc, 1, &word1); - desc->flags = 0; + rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) - desc->flags |= RX_FLAG_FAILED_FCS_CRC; + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. - */ - desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); - desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 100kbit/s. + */ + rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + rxdesc->dev_flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_OFDM)) + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; } /* @@ -1677,17 +1704,16 @@ static void rt61pci_fill_rxdone(struct data_entry *entry, */ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) { - struct data_ring *ring; - struct data_entry *entry; - struct data_entry *entry_done; - __le32 *txd; + struct data_queue *queue; + struct queue_entry *entry; + struct queue_entry *entry_done; + struct queue_entry_priv_pci_tx *priv_tx; + struct txdone_entry_desc txdesc; u32 word; u32 reg; u32 old_reg; int type; int index; - int tx_status; - int retry; /* * During each loop we will compare the freshly read @@ -1710,11 +1736,11 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) /* * Skip this entry when it contains an invalid - * ring identication number. + * queue identication number. */ type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); - ring = rt2x00lib_get_ring(rt2x00dev, type); - if (unlikely(!ring)) + queue = rt2x00queue_get_queue(rt2x00dev, type); + if (unlikely(!queue)) continue; /* @@ -1722,36 +1748,40 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) * index number. */ index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE); - if (unlikely(index >= ring->stats.limit)) + if (unlikely(index >= queue->limit)) continue; - entry = &ring->entry[index]; - txd = entry->priv; - rt2x00_desc_read(txd, 0, &word); + entry = &queue->entries[index]; + priv_tx = entry->priv_data; + rt2x00_desc_read(priv_tx->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) return; - entry_done = rt2x00_get_data_entry_done(ring); + entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); while (entry != entry_done) { - /* Catch up. Just report any entries we missed as - * failed. */ + /* Catch up. + * Just report any entries we missed as failed. + */ WARNING(rt2x00dev, - "TX status report missed for entry %p\n", - entry_done); - rt2x00pci_txdone(rt2x00dev, entry_done, TX_FAIL_OTHER, - 0); - entry_done = rt2x00_get_data_entry_done(ring); + "TX status report missed for entry %d\n", + entry_done->entry_idx); + + txdesc.status = TX_FAIL_OTHER; + txdesc.retry = 0; + + rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); + entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); } /* * Obtain the status about this packet. */ - tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); - retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); + txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); + txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); - rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry); + rt2x00pci_txdone(rt2x00dev, entry, &txdesc); } } @@ -1906,7 +1936,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); - EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + EEPROM(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word); } else { value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); if (value < -10 || value > 10) @@ -2035,35 +2065,61 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * If the eeprom value is invalid, * switch to default led mode. */ +#ifdef CONFIG_RT61PCI_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); + + rt2x00dev->led_radio.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_RADIO; + rt2x00dev->led_radio.led_dev.brightness_set = + rt61pci_brightness_set; + rt2x00dev->led_radio.led_dev.blink_set = + rt61pci_blink_set; + rt2x00dev->led_radio.flags = LED_INITIALIZED; + + rt2x00dev->led_assoc.rt2x00dev = rt2x00dev; + rt2x00dev->led_assoc.type = LED_TYPE_ASSOC; + rt2x00dev->led_assoc.led_dev.brightness_set = + rt61pci_brightness_set; + rt2x00dev->led_assoc.led_dev.blink_set = + rt61pci_blink_set; + rt2x00dev->led_assoc.flags = LED_INITIALIZED; + + if (value == LED_MODE_SIGNAL_STRENGTH) { + rt2x00dev->led_qual.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_QUALITY; + rt2x00dev->led_qual.led_dev.brightness_set = + rt61pci_brightness_set; + rt2x00dev->led_qual.led_dev.blink_set = + rt61pci_blink_set; + rt2x00dev->led_qual.flags = LED_INITIALIZED; + } - rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); - - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE, - rt2x00dev->led_mode); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value); + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_0)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_1)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_2)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_3)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_4)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_G)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); +#endif /* CONFIG_RT61PCI_LEDS */ return 0; } @@ -2197,7 +2253,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 5; + rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2214,8 +2270,8 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->num_modes = 2; - spec->num_rates = 12; + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; spec->tx_power_a = NULL; spec->tx_power_bg = txpower; spec->tx_power_default = DEFAULT_TXPOWER; @@ -2230,7 +2286,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) if (rt2x00_rf(&rt2x00dev->chip, RF5225) || rt2x00_rf(&rt2x00dev->chip, RF5325)) { - spec->num_modes = 3; + spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_seq); txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); @@ -2262,7 +2318,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) rt61pci_probe_hw_mode(rt2x00dev); /* - * This device requires firmware + * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); @@ -2277,70 +2333,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static void rt61pci_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - /* - * Mask off any flags we are going to ignore from - * the total_flags field. - */ - *total_flags &= - FIF_ALLMULTI | - FIF_FCSFAIL | - FIF_PLCPFAIL | - FIF_CONTROL | - FIF_OTHER_BSS | - FIF_PROMISC_IN_BSS; - - /* - * Apply some rules to the filters: - * - Some filters imply different filters to be set. - * - Some things we can't filter out at all. - * - Multicast filter seems to kill broadcast traffic so never use it. - */ - *total_flags |= FIF_ALLMULTI; - if (*total_flags & FIF_OTHER_BSS || - *total_flags & FIF_PROMISC_IN_BSS) - *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - - /* - * Check if there is any work left for us. - */ - if (rt2x00dev->packet_filter == *total_flags) - return; - rt2x00dev->packet_filter = *total_flags; - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * and broadcast frames will always be accepted since - * there is no filter for it at this time. - */ - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, - !(*total_flags & FIF_FCSFAIL)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, - !(*total_flags & FIF_PLCPFAIL)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, - !(*total_flags & FIF_CONTROL)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, - !(*total_flags & FIF_ALLMULTI)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -2369,66 +2361,72 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void rt61pci_reset_tsf(struct ieee80211_hw *hw) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0); -} - 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 skb_desc *desc; - struct data_ring *ring; - struct data_entry *entry; + struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct skb_frame_desc *skbdesc; + unsigned int beacon_base; + u32 reg; - /* - * 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; - ring = rt2x00lib_get_ring(rt2x00dev, control->queue); - entry = rt2x00_get_data_entry(ring); + if (unlikely(!intf->beacon)) + return -ENOBUFS; /* * We need to append the descriptor in front of the * beacon frame. */ - if (skb_headroom(skb) < TXD_DESC_SIZE) { - if (pskb_expand_head(skb, TXD_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)) return -ENOMEM; } /* * Add the descriptor in front of the skb. */ - skb_push(skb, ring->desc_size); - memset(skb->data, 0, ring->desc_size); + skb_push(skb, intf->beacon->queue->desc_size); + memset(skb->data, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len - ring->desc_size; - desc->desc = skb->data; - desc->data = skb->data + ring->desc_size; - desc->ring = ring; - desc->entry = entry; + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; + 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 = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + /* + * mac80211 doesn't provide the control->queue variable + * for beacons. Set our own queue identification so + * it can be used during descriptor initialization. + */ + control->queue = RT2X00_BCN_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; } @@ -2441,14 +2439,13 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .configure_filter = rt61pci_configure_filter, + .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, - .reset_tsf = rt61pci_reset_tsf, .beacon_update = rt61pci_beacon_update, }; @@ -2456,6 +2453,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .irq_handler = rt61pci_interrupt, .probe_hw = rt61pci_probe_hw, .get_firmware_name = rt61pci_get_firmware_name, + .get_firmware_crc = rt61pci_get_firmware_crc, .load_firmware = rt61pci_load_firmware, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, @@ -2470,19 +2468,42 @@ 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_preamble = rt61pci_config_preamble, + .config_filter = rt61pci_config_filter, + .config_intf = rt61pci_config_intf, + .config_erp = rt61pci_config_erp, .config = rt61pci_config, }; +static const struct data_queue_desc rt61pci_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = RXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_rx), +}; + +static const struct data_queue_desc rt61pci_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + +static const struct data_queue_desc rt61pci_queue_bcn = { + .entry_num = 4 * BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXINFO_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci_tx), +}; + static const struct rt2x00_ops rt61pci_ops = { .name = KBUILD_MODNAME, - .rxd_size = RXD_DESC_SIZE, - .txd_size = TXD_DESC_SIZE, + .max_sta_intf = 1, + .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .rx = &rt61pci_queue_rx, + .tx = &rt61pci_queue_tx, + .bcn = &rt61pci_queue_bcn, .lib = &rt61pci_rt2x00_ops, .hw = &rt61pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 4c6524eedad..3511bba7ff6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -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) @@ -391,7 +405,7 @@ struct hw_pairwise_ta_entry { #define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) #define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) #define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) -#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000) #define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) #define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) @@ -866,7 +880,7 @@ struct hw_pairwise_ta_entry { #define TX_CNTL_CSR_ABORT_TX_MGMT FIELD32(0x00100000) /* - * LOAD_TX_RING_CSR: Load RX de + * LOAD_TX_RING_CSR: Load RX desriptor */ #define LOAD_TX_RING_CSR 0x3434 #define LOAD_TX_RING_CSR_LOAD_TXD_AC0 FIELD32(0x00000001) @@ -1116,10 +1130,10 @@ struct hw_pairwise_ta_entry { #define EEPROM_MAC_ADDR_0 0x0002 #define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) #define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) -#define EEPROM_MAC_ADDR1 0x0004 +#define EEPROM_MAC_ADDR1 0x0003 #define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) #define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_2 0x0006 +#define EEPROM_MAC_ADDR_2 0x0004 #define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) #define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) @@ -1247,6 +1261,7 @@ struct hw_pairwise_ta_entry { * DMA descriptor defines. */ #define TXD_DESC_SIZE ( 16 * sizeof(__le32) ) +#define TXINFO_SIZE ( 6 * sizeof(__le32) ) #define RXD_DESC_SIZE ( 16 * sizeof(__le32) ) /* @@ -1440,8 +1455,8 @@ struct hw_pairwise_ta_entry { #define RXD_W15_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to dscape value - * and from dscape value to register value. + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 #define MAX_TXPOWER 31 diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3909cf42f47..a9efe25f1ea 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ Supported chipsets: rt2571W & rt2671. */ +#include <linux/crc-itu-t.h> #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -278,85 +279,158 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -/* - * Configuration handlers. - */ -static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) +#ifdef CONFIG_RT73USB_LEDS +static void rt73usb_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - 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))); + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + unsigned int a_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_5GHZ); + unsigned int bg_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); + + if (led->type == LED_TYPE_RADIO) { + rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, + MCU_LEDCS_RADIO_STATUS, enabled); + + rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL, + 0, led->rt2x00dev->led_mcu_reg, + REGISTER_TIMEOUT); + } else if (led->type == LED_TYPE_ASSOC) { + rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, + MCU_LEDCS_LINK_BG_STATUS, bg_mode); + rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, + MCU_LEDCS_LINK_A_STATUS, a_mode); + + rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL, + 0, led->rt2x00dev->led_mcu_reg, + REGISTER_TIMEOUT); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * this means we need to convert the brightness + * argument into the matching level within that range. + */ + rt2x00usb_vendor_request_sw(led->rt2x00dev, USB_LED_CONTROL, + brightness / (LED_FULL / 6), + led->rt2x00dev->led_mcu_reg, + REGISTER_TIMEOUT); + } } -static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) +static int rt73usb_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { - u32 tmp; + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; - tmp = le32_to_cpu(bssid[1]); - rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - bssid[1] = cpu_to_le32(tmp); + rt73usb_register_read(led->rt2x00dev, MAC_CSR14, ®); + rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); + rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, - (2 * sizeof(__le32))); + return 0; } +#endif /* CONFIG_RT73USB_LEDS */ -static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, - const int tsf_sync) +/* + * Configuration handlers. + */ +static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) { u32 reg; /* - * 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); - - /* - * Enable synchronisation. + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. */ - 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_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(filter_flags & FIF_PROMISC_IN_BSS) && + !rt2x00dev->intf_ap_count); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, + !(filter_flags & FIF_CONTROL)); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); } -static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) { + unsigned int beacon_base; u32 reg; - /* - * When in atomic context, reschedule and let rt2x00lib - * call this function again. - */ - if (in_atomic()) { - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); - return; + 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, beacon_base, 0); + + /* + * Enable synchronisation. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } + 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); + + 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(®, 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_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) +{ + u32 reg; + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - !!short_preamble); + !!erp->short_preamble); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } @@ -442,28 +516,22 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags) - && (rt2x00dev->curr_hwmode != HWMODE_A); + && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp); break; case ANTENNA_A: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); @@ -501,14 +569,8 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); break; - case ANTENNA_SW_DIVERSITY: - /* - * NOTE: We should never come here because rt2x00lib is - * supposed to catch this and send us the correct antenna - * explicitely. However we are nog going to bug about this. - * Instead, just default to antenna B. - */ case ANTENNA_B: + default: rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); break; @@ -558,7 +620,14 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, unsigned int i; u32 reg; - if (rt2x00dev->curr_hwmode == HWMODE_A) { + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); } else { @@ -572,10 +641,9 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, - (rt2x00dev->curr_hwmode == HWMODE_B || - rt2x00dev->curr_hwmode == HWMODE_G)); + (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, - (rt2x00dev->curr_hwmode == HWMODE_A)); + (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)); rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); @@ -617,8 +685,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); @@ -634,68 +702,6 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, } /* - * LED functions. - */ -static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt73usb_register_read(rt2x00dev, MAC_CSR14, ®); - rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70); - rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); - rt73usb_register_write(rt2x00dev, MAC_CSR14, reg); - - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, - (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, - (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); - - rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, - rt2x00dev->led_reg, REGISTER_TIMEOUT); -} - -static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev) -{ - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0); - - rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, - rt2x00dev->led_reg, REGISTER_TIMEOUT); -} - -static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) -{ - u32 led; - - if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) - return; - - /* - * Led handling requires a positive value for the rssi, - * to do that correctly we need to add the correction. - */ - rssi += rt2x00dev->rssi_offset; - - if (rssi <= 30) - led = 0; - else if (rssi <= 39) - led = 1; - else if (rssi <= 49) - led = 2; - else if (rssi <= 53) - led = 3; - else if (rssi <= 63) - led = 4; - else - led = 5; - - rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led, - rt2x00dev->led_reg, REGISTER_TIMEOUT); -} - -/* * Link tuning */ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, @@ -729,17 +735,12 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) u8 up_bound; u8 low_bound; - /* - * Update Led strength - */ - rt73usb_activity_led(rt2x00dev, rssi); - rt73usb_bbp_read(rt2x00dev, 17, &r17); /* * Determine r17 bounds. */ - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; @@ -766,6 +767,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 +823,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. @@ -833,16 +843,30 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) } /* - * Firmware name function. + * Firmware functions */ static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) { return FIRMWARE_RT2571; } -/* - * Initialization functions. - */ +static u16 rt73usb_get_firmware_crc(void *data, const size_t len) +{ + u16 crc; + + /* + * Use the crc itu-t algorithm. + * The last 2 bytes in the firmware array are the crc checksum itself, + * this means that we should never pass those 2 bytes to the crc + * algorithm. + */ + crc = crc_itu_t(0, data, len - 2); + crc = crc_itu_t_byte(crc, 0); + crc = crc_itu_t_byte(crc, 0); + + return crc; +} + static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, const size_t len) { @@ -889,7 +913,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, - FIRMWARE_IMAGE_BASE + i, 0x0000, + FIRMWARE_IMAGE_BASE + i, 0, cache, buflen, timeout); ptr += buflen; @@ -902,18 +926,19 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, * we need to specify a long timeout time. */ status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, - 0x0000, USB_MODE_FIRMWARE, + 0, USB_MODE_FIRMWARE, REGISTER_TIMEOUT_FIRMWARE); if (status < 0) { ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); return status; } - rt73usb_disable_led(rt2x00dev); - return 0; } +/* + * Initialization functions. + */ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -1021,6 +1046,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. @@ -1094,19 +1130,15 @@ continue_csr_init: rt73usb_bbp_write(rt2x00dev, 102, 0x16); rt73usb_bbp_write(rt2x00dev, 107, 0x04); - DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); for (i = 0; i < EEPROM_BBP_SIZE; i++) { rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", - reg_id, value); rt73usb_bbp_write(rt2x00dev, reg_id, value); } } - DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); return 0; } @@ -1136,21 +1168,11 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) return -EIO; } - /* - * Enable LED - */ - rt73usb_enable_led(rt2x00dev); - return 0; } static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - /* - * Disable LED - */ - rt73usb_disable_led(rt2x00dev); - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); /* @@ -1234,10 +1256,10 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, - struct txdata_entry_desc *desc, + struct txentry_desc *txdesc, struct ieee80211_tx_control *control) { - struct skb_desc *skbdesc = get_skb_desc(skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; u32 word; @@ -1245,47 +1267,47 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue); - rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs); - rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); - rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue); + rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); - rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, - TXPOWER_TO_DEV(control->power_level)); + TXPOWER_TO_DEV(rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_BURST, - test_bit(ENTRY_TXD_BURST, &desc->flags)); + test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, - test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - test_bit(ENTRY_TXD_ACK, &desc->flags)); + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, - test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, - test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); - rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST2, - test_bit(ENTRY_TXD_BURST, &desc->flags)); + test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } @@ -1309,11 +1331,11 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * TX data initialization */ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - unsigned int queue) + const unsigned int queue) { u32 reg; - if (queue != IEEE80211_TX_QUEUE_BEACON) + if (queue != RT2X00_BCN_QUEUE_BEACON) return; /* @@ -1324,6 +1346,8 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1353,7 +1377,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return 0; } - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { if (lna == 3 || lna == 2) offset += 10; @@ -1377,37 +1401,62 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static void rt73usb_fill_rxdone(struct data_entry *entry, - struct rxdata_entry_desc *desc) +static void rt73usb_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) { - struct skb_desc *skbdesc = get_skb_desc(entry->skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; + unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; + /* + * Copy descriptor to the available headroom inside the skbuffer. + */ + skb_push(entry->skb, offset); + memcpy(entry->skb->data, rxd, entry->queue->desc_size); + rxd = (__le32 *)entry->skb->data; + + /* + * The descriptor is now aligned to 4 bytes and thus it is + * now safe to read it on all architectures. + */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - desc->flags = 0; + rxdesc->flags = 0; if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) - desc->flags |= RX_FLAG_FAILED_FCS_CRC; + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 100kbit/s. */ - desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); - desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); + rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + rxdesc->dev_flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_OFDM)) + rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; + + /* + * Adjust the skb memory window to the frame boundaries. + */ + skb_pull(entry->skb, offset + entry->queue->desc_size); + skb_trim(entry->skb, rxdesc->size); /* * Set descriptor and data pointer. */ - skbdesc->desc = entry->skb->data; - skbdesc->desc_len = entry->ring->desc_size; - skbdesc->data = entry->skb->data + entry->ring->desc_size; - skbdesc->data_len = desc->size; + skbdesc->data = entry->skb->data; + skbdesc->data_len = rxdesc->size; + skbdesc->desc = rxd; + skbdesc->desc_len = entry->queue->desc_size; } /* @@ -1499,7 +1548,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); - EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + EEPROM(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word); } else { value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); if (value < -10 || value > 10) @@ -1577,33 +1626,60 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led settings, for correct led behaviour. */ +#ifdef CONFIG_RT73USB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE, - rt2x00dev->led_mode); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0, + rt2x00dev->led_radio.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_RADIO; + rt2x00dev->led_radio.led_dev.brightness_set = + rt73usb_brightness_set; + rt2x00dev->led_radio.led_dev.blink_set = + rt73usb_blink_set; + rt2x00dev->led_radio.flags = LED_INITIALIZED; + + rt2x00dev->led_assoc.rt2x00dev = rt2x00dev; + rt2x00dev->led_assoc.type = LED_TYPE_ASSOC; + rt2x00dev->led_assoc.led_dev.brightness_set = + rt73usb_brightness_set; + rt2x00dev->led_assoc.led_dev.blink_set = + rt73usb_blink_set; + rt2x00dev->led_assoc.flags = LED_INITIALIZED; + + if (value == LED_MODE_SIGNAL_STRENGTH) { + rt2x00dev->led_qual.rt2x00dev = rt2x00dev; + rt2x00dev->led_radio.type = LED_TYPE_QUALITY; + rt2x00dev->led_qual.led_dev.brightness_set = + rt73usb_brightness_set; + rt2x00dev->led_qual.led_dev.blink_set = + rt73usb_blink_set; + rt2x00dev->led_qual.flags = LED_INITIALIZED; + } + + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value); + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_0)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_1)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_2)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_3)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_GPIO_4)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_G)); - rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A, + rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); +#endif /* CONFIG_RT73USB_LEDS */ return 0; } @@ -1759,7 +1835,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; - rt2x00dev->hw->queues = 5; + rt2x00dev->hw->queues = 4; SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1776,8 +1852,8 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize hw_mode information. */ - spec->num_modes = 2; - spec->num_rates = 12; + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; spec->tx_power_a = NULL; spec->tx_power_bg = txpower; spec->tx_power_default = DEFAULT_TXPOWER; @@ -1786,20 +1862,20 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); spec->channels = rf_vals_bg_2528; } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5226); spec->channels = rf_vals_5226; } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) { spec->num_channels = 14; spec->channels = rf_vals_5225_2527; } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527); spec->channels = rf_vals_5225_2527; } if (rt2x00_rf(&rt2x00dev->chip, RF5225) || rt2x00_rf(&rt2x00dev->chip, RF5226)) { - spec->num_modes = 3; - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); for (i = 0; i < 14; i++) txpower[i] = TXPOWER_FROM_DEV(txpower[i]); @@ -1829,9 +1905,10 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt73usb_probe_hw_mode(rt2x00dev); /* - * This device requires firmware + * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1844,79 +1921,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static void rt73usb_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - /* - * Mask off any flags we are going to ignore from - * the total_flags field. - */ - *total_flags &= - FIF_ALLMULTI | - FIF_FCSFAIL | - FIF_PLCPFAIL | - FIF_CONTROL | - FIF_OTHER_BSS | - FIF_PROMISC_IN_BSS; - - /* - * Apply some rules to the filters: - * - Some filters imply different filters to be set. - * - Some things we can't filter out at all. - * - Multicast filter seems to kill broadcast traffic so never use it. - */ - *total_flags |= FIF_ALLMULTI; - if (*total_flags & FIF_OTHER_BSS || - *total_flags & FIF_PROMISC_IN_BSS) - *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - - /* - * Check if there is any work left for us. - */ - if (rt2x00dev->packet_filter == *total_flags) - return; - rt2x00dev->packet_filter = *total_flags; - - /* - * When in atomic context, reschedule and let rt2x00lib - * call this function again. - */ - if (in_atomic()) { - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); - return; - } - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * and broadcast frames will always be accepted since - * there is no filter for it at this time. - */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, - !(*total_flags & FIF_FCSFAIL)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, - !(*total_flags & FIF_PLCPFAIL)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, - !(*total_flags & FIF_CONTROL)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, - !(*total_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, - !(*total_flags & FIF_ALLMULTI)); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1955,61 +1959,65 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) #define rt73usb_get_tsf NULL #endif -static void rt73usb_reset_tsf(struct ieee80211_hw *hw) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0); -} - 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 skb_desc *desc; - struct data_ring *ring; - struct data_entry *entry; - int timeout; + struct rt2x00_intf *intf = vif_to_intf(control->vif); + struct skb_frame_desc *skbdesc; + unsigned int beacon_base; + unsigned int timeout; + u32 reg; - /* - * 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; - ring = rt2x00lib_get_ring(rt2x00dev, control->queue); - entry = rt2x00_get_data_entry(ring); + if (unlikely(!intf->beacon)) + return -ENOBUFS; /* * Add the descriptor in front of the skb. */ - skb_push(skb, ring->desc_size); - memset(skb->data, 0, ring->desc_size); + skb_push(skb, intf->beacon->queue->desc_size); + memset(skb->data, 0, intf->beacon->queue->desc_size); /* * Fill in skb descriptor */ - desc = get_skb_desc(skb); - desc->desc_len = ring->desc_size; - desc->data_len = skb->len - ring->desc_size; - desc->desc = skb->data; - desc->data = skb->data + ring->desc_size; - desc->ring = ring; - desc->entry = entry; + skbdesc = get_skb_frame_desc(skb); + memset(skbdesc, 0, sizeof(*skbdesc)); + skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; + 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 = intf->beacon->queue->desc_size; + skbdesc->entry = intf->beacon; + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * mac80211 doesn't provide the control->queue variable + * for beacons. Set our own queue identification so + * it can be used during descriptor initialization. + */ + control->queue = RT2X00_BCN_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; } @@ -2022,20 +2030,20 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .configure_filter = rt73usb_configure_filter, + .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, - .reset_tsf = rt73usb_reset_tsf, .beacon_update = rt73usb_beacon_update, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .probe_hw = rt73usb_probe_hw, .get_firmware_name = rt73usb_get_firmware_name, + .get_firmware_crc = rt73usb_get_firmware_crc, .load_firmware = rt73usb_load_firmware, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, @@ -2050,19 +2058,42 @@ 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_preamble = rt73usb_config_preamble, + .config_filter = rt73usb_config_filter, + .config_intf = rt73usb_config_intf, + .config_erp = rt73usb_config_erp, .config = rt73usb_config, }; +static const struct data_queue_desc rt73usb_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = RXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_rx), +}; + +static const struct data_queue_desc rt73usb_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = DATA_FRAME_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_tx), +}; + +static const struct data_queue_desc rt73usb_queue_bcn = { + .entry_num = 4 * BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXINFO_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb_tx), +}; + static const struct rt2x00_ops rt73usb_ops = { .name = KBUILD_MODNAME, - .rxd_size = RXD_DESC_SIZE, - .txd_size = TXD_DESC_SIZE, + .max_sta_intf = 1, + .max_ap_intf = 4, .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, + .rx = &rt73usb_queue_rx, + .tx = &rt73usb_queue_tx, + .bcn = &rt73usb_queue_bcn, .lib = &rt73usb_rt2x00_ops, .hw = &rt73usb_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index d49dcaacece..06d687425fe 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -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) @@ -867,6 +882,7 @@ struct hw_pairwise_ta_entry { * DMA descriptor defines. */ #define TXD_DESC_SIZE ( 6 * sizeof(__le32) ) +#define TXINFO_SIZE ( 6 * sizeof(__le32) ) #define RXD_DESC_SIZE ( 6 * sizeof(__le32) ) /* @@ -1007,8 +1023,8 @@ struct hw_pairwise_ta_entry { #define RXD_W5_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to dscape value - * and from dscape value to register value. + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 #define MAX_TXPOWER 31 diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h index 2cbfe3c8081..082a11f93be 100644 --- a/drivers/net/wireless/rtl8180.h +++ b/drivers/net/wireless/rtl8180.h @@ -102,7 +102,7 @@ struct rtl8180_priv { struct rtl8180_tx_ring tx_ring[4]; struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; + struct ieee80211_supported_band band; struct pci_dev *pdev; u32 rx_conf; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 5e9a8ace0d8..c181f23e930 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -49,6 +49,41 @@ static struct pci_device_id rtl8180_table[] __devinitdata = { MODULE_DEVICE_TABLE(pci, rtl8180_table); +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + + + + void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8180_priv *priv = dev->priv; @@ -99,10 +134,10 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) /* TODO: improve signal/rssi reporting */ rx_status.signal = flags2 & 0xFF; rx_status.ssi = (flags2 >> 8) & 0x7F; - rx_status.rate = (flags >> 20) & 0xF; - rx_status.freq = dev->conf.freq; - rx_status.channel = dev->conf.channel; - rx_status.phymode = dev->conf.phymode; + /* XXX: is this correct? */ + rx_status.rate_idx = (flags >> 20) & 0xF; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(entry->tsft); rx_status.flag |= RX_FLAG_TSFT; if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR) @@ -222,18 +257,25 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + BUG_ON(!control->tx_rate); + tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | - RTL8180_TX_DESC_FLAG_LS | (control->tx_rate << 24) | - (control->rts_cts_rate << 19) | skb->len; + RTL8180_TX_DESC_FLAG_LS | + (control->tx_rate->hw_value << 24) | skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; - if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + tx_flags |= control->rts_cts_rate->hw_value << 19; + } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_CTS; + tx_flags |= control->rts_cts_rate->hw_value << 19; + } *((struct ieee80211_tx_control **) skb->cb) = kmemdup(control, sizeof(*control), GFP_ATOMIC); @@ -246,9 +288,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (control->rate->rate * 2) / 10); + (control->tx_rate->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((control->rate->rate * 2) / 10); + ((control->tx_rate->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -261,8 +303,8 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate != -1 ? - control->alt_retry_rate << 4 : 0; + entry->flags2 = control->alt_retry_rate != NULL ? + control->alt_retry_rate->bitrate << 4 : 0; entry->retry_limit = control->retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); @@ -646,9 +688,9 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], - cpu_to_le32(*(u32 *)conf->mac_addr)); + le32_to_cpu(*(__le32 *)conf->mac_addr)); rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], - cpu_to_le16(*(u16 *)(conf->mac_addr + 4))); + le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; @@ -838,19 +880,19 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, goto err_free_dev; } + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); - priv->modes[0].mode = MODE_IEEE80211G; - priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates); - priv->modes[0].rates = priv->rates; - priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[0].channels = priv->channels; - priv->modes[1].mode = MODE_IEEE80211B; - priv->modes[1].num_rates = 4; - priv->modes[1].rates = priv->rates; - priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[1].channels = priv->channels; - priv->mode = IEEE80211_IF_TYPE_INVALID; + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = 4; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; dev->queues = 1; @@ -879,15 +921,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; if (priv->r8185) { - if ((err = ieee80211_register_hwmode(dev, &priv->modes[0]))) - goto err_iounmap; - + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); pci_try_set_mwi(pdev); } - if ((err = ieee80211_register_hwmode(dev, &priv->modes[1]))) - goto err_iounmap; - eeprom.data = dev; eeprom.register_read = rtl8180_eeprom_register_read; eeprom.register_write = rtl8180_eeprom_register_write; @@ -950,8 +987,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, for (i = 0; i < 14; i += 2) { u16 txpwr; eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); - priv->channels[i].val = txpwr & 0xFF; - priv->channels[i + 1].val = txpwr >> 8; + priv->channels[i].hw_value = txpwr & 0xFF; + priv->channels[i + 1].hw_value = txpwr >> 8; } /* OFDM TX power */ @@ -959,8 +996,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, for (i = 0; i < 14; i += 2) { u16 txpwr; eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); - priv->channels[i].val |= (txpwr & 0xFF) << 8; - priv->channels[i + 1].val |= txpwr & 0xFF00; + priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; + priv->channels[i + 1].hw_value |= txpwr & 0xFF00; } } diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c index 8293e19c4c5..5d47935dbac 100644 --- a/drivers/net/wireless/rtl8180_grf5101.c +++ b/drivers/net/wireless/rtl8180_grf5101.c @@ -73,8 +73,9 @@ static void grf5101_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - u32 txpw = priv->channels[conf->channel - 1].val & 0xFF; - u32 chan = conf->channel - 1; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = channel - 1; /* set TX power */ write_grf5101(dev, 0x15, 0x0); diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c index 98fe9fd6496..a34dfd382b6 100644 --- a/drivers/net/wireless/rtl8180_max2820.c +++ b/drivers/net/wireless/rtl8180_max2820.c @@ -78,8 +78,9 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - unsigned int chan_idx = conf ? conf->channel - 1 : 0; - u32 txpw = priv->channels[chan_idx].val & 0xFF; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + unsigned int chan_idx = channel - 1; + u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; u32 chan = max2820_chan[chan_idx]; /* While philips SA2400 drive the PA bias from diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl8180_rtl8225.c index ef3832bee85..cd22781728a 100644 --- a/drivers/net/wireless/rtl8180_rtl8225.c +++ b/drivers/net/wireless/rtl8180_rtl8225.c @@ -261,8 +261,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) u32 reg; int i; - cck_power = priv->channels[channel - 1].val & 0xFF; - ofdm_power = priv->channels[channel - 1].val >> 8; + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; cck_power = min(cck_power, (u8)35); ofdm_power = min(ofdm_power, (u8)35); @@ -476,8 +476,8 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) const u8 *tmp; int i; - cck_power = priv->channels[channel - 1].val & 0xFF; - ofdm_power = priv->channels[channel - 1].val >> 8; + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; if (channel == 14) tmp = rtl8225z2_tx_power_cck_ch14; @@ -716,13 +716,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, conf->channel); + rtl8225_rf_set_tx_power(dev, chan); else - rtl8225z2_rf_set_tx_power(dev, conf->channel); + rtl8225z2_rf_set_tx_power(dev, chan); - rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]); + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c index e08ace7b1cb..0311b4ea124 100644 --- a/drivers/net/wireless/rtl8180_sa2400.c +++ b/drivers/net/wireless/rtl8180_sa2400.c @@ -80,8 +80,9 @@ static void sa2400_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - u32 txpw = priv->channels[conf->channel - 1].val & 0xFF; - u32 chan = sa2400_chan[conf->channel - 1]; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = sa2400_chan[channel - 1]; write_sa2400(dev, 7, txpw); diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 8680a0b6433..076d88b6db0 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -71,7 +71,7 @@ struct rtl8187_priv { /* rtl8187 specific */ struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; + struct ieee80211_supported_band band; struct usb_device *udev; u32 rx_conf; u16 txpwr_base; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index f44505994a0..c03834d5cb0 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -45,6 +45,38 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, rtl8187_table); +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + static void rtl8187_iowrite_async_cb(struct urb *urb) { kfree(urb->context); @@ -146,17 +178,23 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - flags |= control->rts_cts_rate << 19; - flags |= control->tx_rate << 24; + + BUG_ON(!control->tx_rate); + + flags |= control->tx_rate->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_RTS; + flags |= control->rts_cts_rate->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, control); - } - if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_CTS; + flags |= control->rts_cts_rate->hw_value << 19; + } hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); @@ -225,10 +263,9 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.antenna = (hdr->signal >> 7) & 1; rx_status.signal = 64 - min(hdr->noise, (u8)64); rx_status.ssi = signal; - rx_status.rate = rate; - rx_status.freq = dev->conf.freq; - rx_status.channel = dev->conf.channel; - rx_status.phymode = dev->conf.phymode; + rx_status.rate_idx = rate; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(hdr->mac_time); rx_status.flag |= RX_FLAG_TSFT; if (flags & (1 << 13)) @@ -682,19 +719,22 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, usb_get_dev(udev); skb_queue_head_init(&priv->rx_queue); + + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); priv->map = (struct rtl818x_csr *)0xFF00; - priv->modes[0].mode = MODE_IEEE80211G; - priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates); - priv->modes[0].rates = priv->rates; - priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[0].channels = priv->channels; - priv->modes[1].mode = MODE_IEEE80211B; - priv->modes[1].num_rates = 4; - priv->modes[1].rates = priv->rates; - priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[1].channels = priv->channels; + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; @@ -703,10 +743,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->max_rssi = 65; dev->max_signal = 64; - for (i = 0; i < 2; i++) - if ((err = ieee80211_register_hwmode(dev, &priv->modes[i]))) - goto err_free_dev; - eeprom.data = dev; eeprom.register_read = rtl8187_eeprom_register_read; eeprom.register_write = rtl8187_eeprom_register_write; @@ -730,20 +766,20 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, for (i = 0; i < 3; i++) { eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, &txpwr); - (*channel++).val = txpwr & 0xFF; - (*channel++).val = txpwr >> 8; + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; } for (i = 0; i < 2; i++) { eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, &txpwr); - (*channel++).val = txpwr & 0xFF; - (*channel++).val = txpwr >> 8; + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; } for (i = 0; i < 2; i++) { eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i, &txpwr); - (*channel++).val = txpwr & 0xFF; - (*channel++).val = txpwr >> 8; + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; } eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index b713de17ba0..9146387b4c5 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -283,8 +283,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) u32 reg; int i; - cck_power = priv->channels[channel - 1].val & 0xF; - ofdm_power = priv->channels[channel - 1].val >> 4; + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; cck_power = min(cck_power, (u8)11); ofdm_power = min(ofdm_power, (u8)35); @@ -500,8 +500,8 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) u32 reg; int i; - cck_power = priv->channels[channel - 1].val & 0xF; - ofdm_power = priv->channels[channel - 1].val >> 4; + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; cck_power = min(cck_power, (u8)15); cck_power += priv->txpwr_base & 0xF; @@ -735,13 +735,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8187_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, conf->channel); + rtl8225_rf_set_tx_power(dev, chan); else - rtl8225z2_rf_set_tx_power(dev, conf->channel); + rtl8225z2_rf_set_tx_power(dev, chan); - rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]); + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); } diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 1e7d6f8278d..4f7d38f506e 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -175,74 +175,4 @@ struct rtl818x_rf_ops { void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); }; -static const struct ieee80211_rate rtl818x_rates[] = { - { .rate = 10, - .val = 0, - .flags = IEEE80211_RATE_CCK }, - { .rate = 20, - .val = 1, - .flags = IEEE80211_RATE_CCK }, - { .rate = 55, - .val = 2, - .flags = IEEE80211_RATE_CCK }, - { .rate = 110, - .val = 3, - .flags = IEEE80211_RATE_CCK }, - { .rate = 60, - .val = 4, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 90, - .val = 5, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 120, - .val = 6, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 180, - .val = 7, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 240, - .val = 8, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 360, - .val = 9, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 480, - .val = 10, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 540, - .val = 11, - .flags = IEEE80211_RATE_OFDM }, -}; - -static const struct ieee80211_channel rtl818x_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484} -}; - #endif /* RTL818X_H */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 88efe1bae58..bced3fe1cf8 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -962,12 +962,12 @@ static char *time_delta(char buffer[], long time) /* get Nth element of the linked list */ static struct strip *strip_get_idx(loff_t pos) { - struct list_head *l; + struct strip *str; int i = 0; - list_for_each_rcu(l, &strip_list) { + list_for_each_entry_rcu(str, &strip_list, list) { if (pos == i) - return list_entry(l, struct strip, list); + return str; ++i; } return NULL; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 06eea6ab7bf..baf74015751 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -102,7 +102,7 @@ hacr_write(u_long base, * Write to card's Host Adapter Command Register. Include a delay for * those times when it is needed. */ -static inline void +static void hacr_write_slow(u_long base, u_char hacr) { @@ -255,7 +255,7 @@ update_psa_checksum(struct net_device * dev) /* * Write 1 byte to the MMC. */ -static inline void +static void mmc_out(u_long base, u_short o, u_char d) @@ -275,7 +275,7 @@ mmc_out(u_long base, * Routine to write bytes to the Modem Management Controller. * We start by the end because it is the way it should be ! */ -static inline void +static void mmc_write(u_long base, u_char o, u_char * b, @@ -293,7 +293,7 @@ mmc_write(u_long base, * Read 1 byte from the MMC. * Optimised version for 1 byte, avoid using memory... */ -static inline u_char +static u_char mmc_in(u_long base, u_short o) { @@ -318,7 +318,7 @@ mmc_in(u_long base, * (code has just been moved in the above function) * We start by the end because it is the way it should be ! */ -static inline void +static void mmc_read(u_long base, u_char o, u_char * b, @@ -350,9 +350,8 @@ mmc_encr(u_long base) /* i/o port of the card */ /*------------------------------------------------------------------*/ /* * Wait for the frequency EEprom to complete a command... - * I hope this one will be optimally inlined... */ -static inline void +static void fee_wait(u_long base, /* i/o port of the card */ int delay, /* Base delay to wait for */ int number) /* Number of time to wait */ @@ -738,9 +737,9 @@ static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) } /* Called when a WavePoint beacon is received */ -static inline void wl_roam_gather(struct net_device * dev, - u_char * hdr, /* Beacon header */ - u_char * stats) /* SNR, Signal quality +static void wl_roam_gather(struct net_device * dev, + u_char * hdr, /* Beacon header */ + u_char * stats) /* SNR, Signal quality of packet */ { wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ @@ -794,7 +793,7 @@ out: static inline int WAVELAN_BEACON(unsigned char *data) { wavepoint_beacon *beacon= (wavepoint_beacon *)data; - static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; + static const wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; if(memcmp(beacon,&beacon_template,9)==0) return 1; @@ -980,7 +979,7 @@ read_ringbuf(struct net_device * dev, * wavelan_interrupt is not an option...), so you may experience * some delay sometime... */ -static inline void +static void wv_82593_reconfig(struct net_device * dev) { net_local * lp = netdev_priv(dev); @@ -1233,7 +1232,7 @@ wv_local_show(struct net_device * dev) /* * Dump packet header (and content if necessary) on the screen */ -static inline void +static void wv_packet_info(u_char * p, /* Packet to dump */ int length, /* Length of the packet */ char * msg1, /* Name of the device */ @@ -1272,7 +1271,7 @@ wv_packet_info(u_char * p, /* Packet to dump */ * This is the information which is displayed by the driver at startup * There is a lot of flag to configure it at your will... */ -static inline void +static void wv_init_info(struct net_device * dev) { unsigned int base = dev->base_addr; @@ -1509,7 +1508,7 @@ wavelan_set_mac_address(struct net_device * dev, * Frequency setting (for hardware able of it) * It's a bit complicated and you don't really want to look into it... */ -static inline int +static int wv_set_frequency(u_long base, /* i/o port of the card */ iw_freq * frequency) { @@ -1706,7 +1705,7 @@ wv_set_frequency(u_long base, /* i/o port of the card */ /* * Give the list of available frequencies */ -static inline int +static int wv_frequency_list(u_long base, /* i/o port of the card */ iw_freq * list, /* List of frequency to fill */ int max) /* Maximum number of frequencies */ @@ -2759,7 +2758,7 @@ wavelan_get_wireless_stats(struct net_device * dev) * frame pointer and verify that the frame seem correct * (called by wv_packet_rcv()) */ -static inline int +static int wv_start_of_frame(struct net_device * dev, int rfp, /* end of frame */ int wrap) /* start of buffer */ @@ -2821,7 +2820,7 @@ wv_start_of_frame(struct net_device * dev, * Note: if any errors occur, the packet is "dropped on the floor" * (called by wv_packet_rcv()) */ -static inline void +static void wv_packet_read(struct net_device * dev, int fd_p, int sksize) @@ -2922,7 +2921,7 @@ wv_packet_read(struct net_device * dev, * (called by wavelan_interrupt()) * Note : the spinlock is already grabbed for us and irq are disabled. */ -static inline void +static void wv_packet_rcv(struct net_device * dev) { unsigned int base = dev->base_addr; @@ -3056,7 +3055,7 @@ wv_packet_rcv(struct net_device * dev) * the transmit. * (called in wavelan_packet_xmit()) */ -static inline void +static void wv_packet_write(struct net_device * dev, void * buf, short length) @@ -3180,7 +3179,7 @@ wavelan_packet_xmit(struct sk_buff * skb, * Routine to initialize the Modem Management Controller. * (called by wv_hw_config()) */ -static inline int +static int wv_mmc_init(struct net_device * dev) { unsigned int base = dev->base_addr; @@ -3699,7 +3698,7 @@ wv_82593_config(struct net_device * dev) * wavelan. * (called by wv_config()) */ -static inline int +static int wv_pcmcia_reset(struct net_device * dev) { int i; @@ -3864,7 +3863,7 @@ wv_hw_config(struct net_device * dev) * 2. Start the LAN controller's receive unit * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) */ -static inline void +static void wv_hw_reset(struct net_device * dev) { net_local * lp = netdev_priv(dev); @@ -3895,7 +3894,7 @@ wv_hw_reset(struct net_device * dev) * device available to the system. * (called by wavelan_event()) */ -static inline int +static int wv_pcmcia_config(struct pcmcia_device * link) { struct net_device * dev = (struct net_device *) link->priv; diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 33dd9709422..628192d7248 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -637,7 +637,7 @@ struct net_local /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ static inline u_char /* data */ hasr_read(u_long); /* Read the host interface : base address */ -static inline void +static void hacr_write(u_long, /* Write to host interface : base address */ u_char), /* data */ hacr_write_slow(u_long, @@ -651,7 +651,7 @@ static void int, /* Offset in psa */ u_char *, /* Buffer in memory */ int); /* Length of buffer */ -static inline void +static void mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ u_short, u_char), @@ -659,10 +659,10 @@ static inline void u_char, u_char *, int); -static inline u_char /* Read 1 byte from the MMC */ +static u_char /* Read 1 byte from the MMC */ mmc_in(u_long, u_short); -static inline void +static void mmc_read(u_long, /* Read n bytes from the MMC */ u_char, u_char *, @@ -688,10 +688,10 @@ static int int, char *, int); -static inline void +static void wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ -static inline void +static void wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * @@ -699,17 +699,17 @@ static en_stats * static iw_stats * wavelan_get_wireless_stats(struct net_device *); /* ----------------------- PACKET RECEPTION ----------------------- */ -static inline int +static int wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ int, /* end of frame */ int); /* start of buffer */ -static inline void +static void wv_packet_read(struct net_device *, /* Read a packet from a frame */ int, int), wv_packet_rcv(struct net_device *); /* Read all packets waiting */ /* --------------------- PACKET TRANSMISSION --------------------- */ -static inline void +static void wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ void *, short); @@ -717,20 +717,20 @@ static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ -static inline int +static int wv_mmc_init(struct net_device *); /* Initialize the modem */ static int wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ static int wv_82593_config(struct net_device *); /* Configure the i82593 */ -static inline int +static int wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ static int wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ -static inline void +static void wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ -static inline int +static int wv_pcmcia_config(struct pcmcia_device *); /* Configure the pcmcia interface */ static void wv_pcmcia_release(struct pcmcia_device *);/* Remove a device */ diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 99e5b03b3f5..0acb5c34573 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -771,10 +771,10 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { { CR_ZD1211B_RETRY_MAX, 0x02020202 }, - { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f }, - { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f }, - { CR_ZD1211B_TX_PWR_CTL2, 0x003f001f }, - { CR_ZD1211B_TX_PWR_CTL1, 0x001f000f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC3, 0x001f000f }, { CR_ZD1211B_AIFS_CTL1, 0x00280028 }, { CR_ZD1211B_AIFS_CTL2, 0x008C003C }, { CR_ZD1211B_TXOP, 0x01800824 }, @@ -809,6 +809,7 @@ static int hw_init_hmac(struct zd_chip *chip) { CR_AFTER_PNP, 0x1 }, { CR_WEP_PROTECT, 0x114 }, { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, + { CR_CAM_MODE, MODE_AP_WDS}, }; ZD_ASSERT(mutex_is_locked(&chip->mutex)); @@ -986,7 +987,7 @@ static int print_fw_version(struct zd_chip *chip) return 0; } -static int set_mandatory_rates(struct zd_chip *chip, int mode) +static int set_mandatory_rates(struct zd_chip *chip, int gmode) { u32 rates; ZD_ASSERT(mutex_is_locked(&chip->mutex)); @@ -994,17 +995,12 @@ static int set_mandatory_rates(struct zd_chip *chip, int mode) * that the device is supporting. Until further notice we should try * to support 802.11g also for full speed USB. */ - switch (mode) { - case MODE_IEEE80211B: + if (!gmode) rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M; - break; - case MODE_IEEE80211G: + else rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M| CR_RATE_6M|CR_RATE_12M|CR_RATE_24M; - break; - default: - return -EINVAL; - } + return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL); } @@ -1108,7 +1104,7 @@ int zd_chip_init_hw(struct zd_chip *chip) * It might be discussed, whether we should suppport pure b mode for * full speed USB. */ - r = set_mandatory_rates(chip, MODE_IEEE80211G); + r = set_mandatory_rates(chip, 1); if (r) goto out; /* Disabling interrupts is certainly a smart thing here. diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 009c03777a3..f8c061a9b6e 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -489,6 +489,7 @@ enum { #define CR_RX_OFFSET CTL_REG(0x065c) +#define CR_BCN_LENGTH CTL_REG(0x0664) #define CR_PHY_DELAY CTL_REG(0x066C) #define CR_BCN_FIFO CTL_REG(0x0670) #define CR_SNIFFER_ON CTL_REG(0x0674) @@ -545,6 +546,8 @@ enum { #define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ RX_FILTER_CFEND | RX_FILTER_CFACK) +#define BCN_MODE_IBSS 0x2000000 + /* Monitor mode sets filter to 0xfffff */ #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) @@ -578,6 +581,11 @@ enum { /* CAM: Continuous Access Mode (power management) */ #define CR_CAM_MODE CTL_REG(0x0700) +#define MODE_IBSS 0x0 +#define MODE_AP 0x1 +#define MODE_STA 0x2 +#define MODE_AP_WDS 0x3 + #define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704) #define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708) #define CR_CAM_ADDRESS CTL_REG(0x070C) @@ -625,11 +633,10 @@ enum { #define CR_S_MD CTL_REG(0x0830) #define CR_USB_DEBUG_PORT CTL_REG(0x0888) - -#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00) -#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04) -#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08) -#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c) +#define CR_ZD1211B_CWIN_MAX_MIN_AC0 CTL_REG(0x0b00) +#define CR_ZD1211B_CWIN_MAX_MIN_AC1 CTL_REG(0x0b04) +#define CR_ZD1211B_CWIN_MAX_MIN_AC2 CTL_REG(0x0b08) +#define CR_ZD1211B_CWIN_MAX_MIN_AC3 CTL_REG(0x0b0c) #define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10) #define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14) #define CR_ZD1211B_TXOP CTL_REG(0x0b20) diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c index 7c277ec43f7..d8dc41ec0e5 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c @@ -65,16 +65,14 @@ static const struct channel_range *zd_channel_range(u8 regdomain) static void unmask_bg_channels(struct ieee80211_hw *hw, const struct channel_range *range, - struct ieee80211_hw_mode *mode) + struct ieee80211_supported_band *sband) { u8 channel; for (channel = range->start; channel < range->end; channel++) { struct ieee80211_channel *chan = - &mode->channels[CHAN_TO_IDX(channel)]; - chan->flag |= IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; + &sband->channels[CHAN_TO_IDX(channel)]; + chan->flags = 0; } } @@ -97,7 +95,6 @@ void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain) range = zd_channel_range(ZD_REGDOMAIN_FCC); } - unmask_bg_channels(hw, range, &mac->modes[0]); - unmask_bg_channels(hw, range, &mac->modes[1]); + unmask_bg_channels(hw, range, &mac->band); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 76ef2d83919..69c45ca9905 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -34,76 +34,61 @@ /* This table contains the hardware specific values for the modulation rates. */ static const struct ieee80211_rate zd_rates[] = { - { .rate = 10, - .val = ZD_CCK_RATE_1M, - .flags = IEEE80211_RATE_CCK }, - { .rate = 20, - .val = ZD_CCK_RATE_2M, - .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 55, - .val = ZD_CCK_RATE_5_5M, - .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 110, - .val = ZD_CCK_RATE_11M, - .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 60, - .val = ZD_OFDM_RATE_6M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 90, - .val = ZD_OFDM_RATE_9M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 120, - .val = ZD_OFDM_RATE_12M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 180, - .val = ZD_OFDM_RATE_18M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 240, - .val = ZD_OFDM_RATE_24M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 360, - .val = ZD_OFDM_RATE_36M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 480, - .val = ZD_OFDM_RATE_48M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 540, - .val = ZD_OFDM_RATE_54M, - .flags = IEEE80211_RATE_OFDM }, + { .bitrate = 10, + .hw_value = ZD_CCK_RATE_1M, }, + { .bitrate = 20, + .hw_value = ZD_CCK_RATE_2M, + .hw_value_short = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = ZD_CCK_RATE_5_5M, + .hw_value_short = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = ZD_CCK_RATE_11M, + .hw_value_short = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = ZD_OFDM_RATE_6M, + .flags = 0 }, + { .bitrate = 90, + .hw_value = ZD_OFDM_RATE_9M, + .flags = 0 }, + { .bitrate = 120, + .hw_value = ZD_OFDM_RATE_12M, + .flags = 0 }, + { .bitrate = 180, + .hw_value = ZD_OFDM_RATE_18M, + .flags = 0 }, + { .bitrate = 240, + .hw_value = ZD_OFDM_RATE_24M, + .flags = 0 }, + { .bitrate = 360, + .hw_value = ZD_OFDM_RATE_36M, + .flags = 0 }, + { .bitrate = 480, + .hw_value = ZD_OFDM_RATE_48M, + .flags = 0 }, + { .bitrate = 540, + .hw_value = ZD_OFDM_RATE_54M, + .flags = 0 }, }; static const struct ieee80211_channel zd_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484} + { .center_freq = 2412, .hw_value = 1 }, + { .center_freq = 2417, .hw_value = 2 }, + { .center_freq = 2422, .hw_value = 3 }, + { .center_freq = 2427, .hw_value = 4 }, + { .center_freq = 2432, .hw_value = 5 }, + { .center_freq = 2437, .hw_value = 6 }, + { .center_freq = 2442, .hw_value = 7 }, + { .center_freq = 2447, .hw_value = 8 }, + { .center_freq = 2452, .hw_value = 9 }, + { .center_freq = 2457, .hw_value = 10 }, + { .center_freq = 2462, .hw_value = 11 }, + { .center_freq = 2467, .hw_value = 12 }, + { .center_freq = 2472, .hw_value = 13 }, + { .center_freq = 2484, .hw_value = 14 }, }; static void housekeeping_init(struct zd_mac *mac); @@ -490,6 +475,46 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, /* FIXME: Management frame? */ } +void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) +{ + struct zd_mac *mac = zd_hw_mac(hw); + u32 tmp, j = 0; + /* 4 more bytes for tail CRC */ + u32 full_len = beacon->len + 4; + zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); + zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + while (tmp & 0x2) { + zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + if ((++j % 100) == 0) { + printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n"); + if (j >= 500) { + printk(KERN_ERR "Giving up beacon config.\n"); + return; + } + } + msleep(1); + } + + zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); + if (zd_chip_is_zd1211b(&mac->chip)) + zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); + + for (j = 0 ; j < beacon->len; j++) + zd_iowrite32(&mac->chip, CR_BCN_FIFO, + *((u8 *)(beacon->data + j))); + + for (j = 0; j < 4; j++) + zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); + + zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); + /* 802.11b/g 2.4G CCK 1Mb + * 802.11a, not yet implemented, uses different values (see GPL vendor + * driver) + */ + zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | + (full_len << 19)); +} + static int fill_ctrlset(struct zd_mac *mac, struct sk_buff *skb, struct ieee80211_tx_control *control) @@ -503,7 +528,9 @@ static int fill_ctrlset(struct zd_mac *mac, ZD_ASSERT(frag_len <= 0xffff); - cs->modulation = control->tx_rate; + cs->modulation = control->tx_rate->hw_value; + if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + cs->modulation = control->tx_rate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); @@ -631,6 +658,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) int bad_frame = 0; u16 fc; bool is_qos, is_4addr, need_padding; + int i; + u8 rate; if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ + FCS_LEN + sizeof(struct rx_status)) @@ -660,14 +689,19 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) } } - stats.channel = _zd_chip_get_channel(&mac->chip); - stats.freq = zd_channels[stats.channel - 1].freq; - stats.phymode = MODE_IEEE80211G; + stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; + stats.band = IEEE80211_BAND_2GHZ; stats.ssi = status->signal_strength; stats.signal = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); - stats.rate = zd_rx_rate(buffer, status); + + rate = zd_rx_rate(buffer, status); + + /* todo: return index in the big switches in zd_rx_rate instead */ + for (i = 0; i < mac->band.n_bitrates; i++) + if (rate == mac->band.bitrates[i].hw_value) + stats.rate_idx = i; length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status); buffer += ZD_PLCP_HEADER_SIZE; @@ -715,6 +749,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, switch (conf->type) { case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: mac->type = conf->type; break; @@ -736,7 +771,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); - return zd_chip_set_channel(&mac->chip, conf->channel); + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } static int zd_op_config_interface(struct ieee80211_hw *hw, @@ -744,15 +779,43 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); + int associated; + + if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) { + associated = true; + if (conf->beacon) { + zd_mac_config_beacon(hw, conf->beacon); + kfree_skb(conf->beacon); + zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | + hw->conf.beacon_int); + } + } else + associated = is_valid_ether_addr(conf->bssid); spin_lock_irq(&mac->lock); - mac->associated = is_valid_ether_addr(conf->bssid); + mac->associated = associated; spin_unlock_irq(&mac->lock); /* TODO: do hardware bssid filtering */ return 0; } +void zd_process_intr(struct work_struct *work) +{ + u16 int_status; + struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); + + int_status = le16_to_cpu(*(u16 *)(mac->intr_buffer+4)); + if (int_status & INT_CFG_NEXT_BCN) { + if (net_ratelimit()) + dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n"); + } else + dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); + + zd_chip_enable_hwint(&mac->chip); +} + + static void set_multicast_hash_handler(struct work_struct *work) { struct zd_mac *mac = @@ -780,7 +843,7 @@ static void set_rx_filter_handler(struct work_struct *work) #define SUPPORTED_FIF_FLAGS \ (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ - FIF_OTHER_BSS) + FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) static void zd_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, @@ -894,7 +957,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) { struct zd_mac *mac; struct ieee80211_hw *hw; - int i; hw = ieee80211_alloc_hw(sizeof(struct zd_mac), &zd_ops); if (!hw) { @@ -912,19 +974,15 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) memcpy(mac->channels, zd_channels, sizeof(zd_channels)); memcpy(mac->rates, zd_rates, sizeof(zd_rates)); - mac->modes[0].mode = MODE_IEEE80211G; - mac->modes[0].num_rates = ARRAY_SIZE(zd_rates); - mac->modes[0].rates = mac->rates; - mac->modes[0].num_channels = ARRAY_SIZE(zd_channels); - mac->modes[0].channels = mac->channels; - mac->modes[1].mode = MODE_IEEE80211B; - mac->modes[1].num_rates = 4; - mac->modes[1].rates = mac->rates; - mac->modes[1].num_channels = ARRAY_SIZE(zd_channels); - mac->modes[1].channels = mac->channels; + mac->band.n_bitrates = ARRAY_SIZE(zd_rates); + mac->band.bitrates = mac->rates; + mac->band.n_channels = ARRAY_SIZE(zd_channels); + mac->band.channels = mac->channels; + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; hw->max_rssi = 100; hw->max_signal = 100; @@ -933,19 +991,12 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) skb_queue_head_init(&mac->ack_wait_queue); - for (i = 0; i < 2; i++) { - if (ieee80211_register_hwmode(hw, &mac->modes[i])) { - dev_dbg_f(&intf->dev, "cannot register hwmode\n"); - ieee80211_free_hw(hw); - return NULL; - } - } - zd_chip_init(&mac->chip, hw, intf); housekeeping_init(mac); INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); + INIT_WORK(&mac->process_intr, zd_process_intr); SET_IEEE80211_DEV(hw, &intf->dev); return hw; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 2dde108df76..71170244d2c 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -172,12 +172,15 @@ struct zd_tx_skb_control_block { struct zd_mac { struct zd_chip chip; spinlock_t lock; + spinlock_t intr_lock; struct ieee80211_hw *hw; struct housekeeping housekeeping; struct work_struct set_multicast_hash_work; struct work_struct set_rts_cts_work; struct work_struct set_rx_filter_work; + struct work_struct process_intr; struct zd_mc_hash multicast_hash; + u8 intr_buffer[USB_MAX_EP_INT_BUFFER]; u8 regdomain; u8 default_regdomain; int type; @@ -185,7 +188,7 @@ struct zd_mac { struct sk_buff_head ack_wait_queue; struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; + struct ieee80211_supported_band band; /* Short preamble (used for RTS/CTS) */ unsigned int short_preamble:1; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 7942b15acfe..e34675c2f8f 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -97,6 +97,7 @@ MODULE_DEVICE_TABLE(usb, usb_ids); #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" /* USB device initialization */ +static void int_urb_complete(struct urb *urb); static int request_fw_file( const struct firmware **fw, const char *name, struct device *device) @@ -336,11 +337,18 @@ static inline void handle_regs_int(struct urb *urb) struct zd_usb *usb = urb->context; struct zd_usb_interrupt *intr = &usb->intr; int len; + u16 int_num; ZD_ASSERT(in_interrupt()); spin_lock(&intr->lock); - if (intr->read_regs_enabled) { + int_num = le16_to_cpu(*(u16 *)(urb->transfer_buffer+2)); + if (int_num == CR_INTERRUPT) { + struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); + memcpy(&mac->intr_buffer, urb->transfer_buffer, + USB_MAX_EP_INT_BUFFER); + schedule_work(&mac->process_intr); + } else if (intr->read_regs_enabled) { intr->read_regs.length = len = urb->actual_length; if (len > sizeof(intr->read_regs.buffer)) @@ -351,7 +359,6 @@ static inline void handle_regs_int(struct urb *urb) goto out; } - dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n"); out: spin_unlock(&intr->lock); } |