diff --git a/[refs] b/[refs] index 17d2dee4b16f..4e083ca88298 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 8457703f1e86aaf0f134402dd1e09e1f13e65222 +refs/heads/master: aa5a1b8e68c95151fd249a3b5ec444c6b0aa2f1c diff --git a/trunk/arch/arm/mach-omap2/board-omap3evm.c b/trunk/arch/arm/mach-omap2/board-omap3evm.c index a4ca63ba7faa..3985f35aee06 100644 --- a/trunk/arch/arm/mach-omap2/board-omap3evm.c +++ b/trunk/arch/arm/mach-omap2/board-omap3evm.c @@ -309,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] = { .gpio_wp = 63, .deferred = true, }, -#ifdef CONFIG_WILINK_PLATFORM_DATA +#ifdef CONFIG_WL12XX_PLATFORM_DATA { .name = "wl1271", .mmc = 2, @@ -450,7 +450,7 @@ static struct regulator_init_data omap3evm_vio = { .consumer_supplies = omap3evm_vio_supply, }; -#ifdef CONFIG_WILINK_PLATFORM_DATA +#ifdef CONFIG_WL12XX_PLATFORM_DATA #define OMAP3EVM_WLAN_PMENA_GPIO (150) #define OMAP3EVM_WLAN_IRQ_GPIO (149) @@ -563,7 +563,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = { OMAP_PIN_OFF_NONE), OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_NONE), -#ifdef CONFIG_WILINK_PLATFORM_DATA +#ifdef CONFIG_WL12XX_PLATFORM_DATA /* WLAN IRQ - GPIO 149 */ OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), @@ -601,7 +601,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = { OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), -#ifdef CONFIG_WILINK_PLATFORM_DATA +#ifdef CONFIG_WL12XX_PLATFORM_DATA /* WLAN IRQ - GPIO 149 */ OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), @@ -637,7 +637,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = { static void __init omap3_evm_wl12xx_init(void) { -#ifdef CONFIG_WILINK_PLATFORM_DATA +#ifdef CONFIG_WL12XX_PLATFORM_DATA int ret; /* WL12xx WLAN Init */ diff --git a/trunk/drivers/bcma/bcma_private.h b/trunk/drivers/bcma/bcma_private.h index 16c1dddfda00..d35294e81d15 100644 --- a/trunk/drivers/bcma/bcma_private.h +++ b/trunk/drivers/bcma/bcma_private.h @@ -47,7 +47,6 @@ int bcma_sprom_get(struct bcma_bus *bus); /* driver_chipcommon.c */ #ifdef CONFIG_BCMA_DRIVER_MIPS void bcma_chipco_serial_init(struct bcma_drv_cc *cc); -extern struct platform_device bcma_pflash_dev; #endif /* CONFIG_BCMA_DRIVER_MIPS */ /* driver_chipcommon_pmu.c */ diff --git a/trunk/drivers/bcma/driver_chipcommon_nflash.c b/trunk/drivers/bcma/driver_chipcommon_nflash.c index 19fafcf78840..dbda91e4dff5 100644 --- a/trunk/drivers/bcma/driver_chipcommon_nflash.c +++ b/trunk/drivers/bcma/driver_chipcommon_nflash.c @@ -5,11 +5,11 @@ * Licensed under the GNU/GPL. See COPYING for details. */ -#include "bcma_private.h" - #include #include +#include "bcma_private.h" + struct platform_device bcma_nflash_dev = { .name = "bcma_nflash", .num_resources = 0, diff --git a/trunk/drivers/bcma/driver_chipcommon_sflash.c b/trunk/drivers/bcma/driver_chipcommon_sflash.c index e6ed4fe5dced..1e694db4532d 100644 --- a/trunk/drivers/bcma/driver_chipcommon_sflash.c +++ b/trunk/drivers/bcma/driver_chipcommon_sflash.c @@ -5,11 +5,11 @@ * Licensed under the GNU/GPL. See COPYING for details. */ -#include "bcma_private.h" - #include #include +#include "bcma_private.h" + static struct resource bcma_sflash_resource = { .name = "bcma_sflash", .start = BCMA_SOC_FLASH2, diff --git a/trunk/drivers/bcma/driver_gpio.c b/trunk/drivers/bcma/driver_gpio.c index 0b5df538dfd9..9a6f585da2d9 100644 --- a/trunk/drivers/bcma/driver_gpio.c +++ b/trunk/drivers/bcma/driver_gpio.c @@ -73,16 +73,6 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio) bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); } -static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) -{ - struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); - - if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) - return bcma_core_irq(cc->core); - else - return -EINVAL; -} - int bcma_gpio_init(struct bcma_drv_cc *cc) { struct gpio_chip *chip = &cc->gpio; @@ -95,7 +85,6 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) chip->set = bcma_gpio_set_value; chip->direction_input = bcma_gpio_direction_input; chip->direction_output = bcma_gpio_direction_output; - chip->to_irq = bcma_gpio_to_irq; chip->ngpio = 16; /* There is just one SoC in one device and its GPIO addresses should be * deterministic to address them more easily. The other buses could get diff --git a/trunk/drivers/bcma/driver_mips.c b/trunk/drivers/bcma/driver_mips.c index 9a7f0e3ab5a3..9fe86ee16c66 100644 --- a/trunk/drivers/bcma/driver_mips.c +++ b/trunk/drivers/bcma/driver_mips.c @@ -14,33 +14,11 @@ #include -#include -#include #include #include #include #include -static const char *part_probes[] = { "bcm47xxpart", NULL }; - -static struct physmap_flash_data bcma_pflash_data = { - .part_probe_types = part_probes, -}; - -static struct resource bcma_pflash_resource = { - .name = "bcma_pflash", - .flags = IORESOURCE_MEM, -}; - -struct platform_device bcma_pflash_dev = { - .name = "physmap-flash", - .dev = { - .platform_data = &bcma_pflash_data, - }, - .resource = &bcma_pflash_resource, - .num_resources = 1, -}; - /* The 47162a0 hangs when reading MIPS DMP registers registers */ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) { @@ -233,7 +211,6 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) { struct bcma_bus *bus = mcore->core->bus; struct bcma_drv_cc *cc = &bus->drv_cc; - struct bcma_pflash *pflash = &cc->pflash; switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { case BCMA_CC_FLASHT_STSER: @@ -243,20 +220,15 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) break; case BCMA_CC_FLASHT_PARA: bcma_debug(bus, "Found parallel flash\n"); - pflash->present = true; - pflash->window = BCMA_SOC_FLASH2; - pflash->window_size = BCMA_SOC_FLASH2_SZ; + cc->pflash.present = true; + cc->pflash.window = BCMA_SOC_FLASH2; + cc->pflash.window_size = BCMA_SOC_FLASH2_SZ; if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS) == 0) - pflash->buswidth = 1; + cc->pflash.buswidth = 1; else - pflash->buswidth = 2; - - bcma_pflash_data.width = pflash->buswidth; - bcma_pflash_resource.start = pflash->window; - bcma_pflash_resource.end = pflash->window + pflash->window_size; - + cc->pflash.buswidth = 2; break; default: bcma_err(bus, "Flash type not supported\n"); diff --git a/trunk/drivers/bcma/main.c b/trunk/drivers/bcma/main.c index 95ba5756c67e..d12b7da556e1 100644 --- a/trunk/drivers/bcma/main.c +++ b/trunk/drivers/bcma/main.c @@ -149,14 +149,6 @@ static int bcma_register_cores(struct bcma_bus *bus) dev_id++; } -#ifdef CONFIG_BCMA_DRIVER_MIPS - if (bus->drv_cc.pflash.present) { - err = platform_device_register(&bcma_pflash_dev); - if (err) - bcma_err(bus, "Error registering parallel flash\n"); - } -#endif - #ifdef CONFIG_BCMA_SFLASH if (bus->drv_cc.sflash.present) { err = platform_device_register(&bcma_sflash_dev); diff --git a/trunk/drivers/net/wireless/ath/ath5k/phy.c b/trunk/drivers/net/wireless/ath/ath5k/phy.c index a78afa98c650..ab363f34b4df 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/phy.c +++ b/trunk/drivers/net/wireless/ath/ath5k/phy.c @@ -1613,10 +1613,6 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah) ah->ah_cal_mask |= AR5K_CALIBRATION_NF; ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); - if (WARN_ON(ee_mode < 0)) { - ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF; - return; - } /* completed NF calibration, test threshold */ nf = ath5k_hw_read_measured_noise_floor(ah); diff --git a/trunk/drivers/net/wireless/ath/ath5k/reset.c b/trunk/drivers/net/wireless/ath/ath5k/reset.c index e2d8b2cf19eb..4084b1076286 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/reset.c +++ b/trunk/drivers/net/wireless/ath/ath5k/reset.c @@ -985,8 +985,6 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, return; ee_mode = ath5k_eeprom_mode_from_channel(channel); - if (WARN_ON(ee_mode < 0)) - return; /* Adjust power delta for channel 14 */ if (channel->center_freq == 2484) diff --git a/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c b/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c index 259c43332fb8..4225cca0f198 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1778,14 +1778,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, if (vif->target_stats.rx_byte) { sinfo->rx_bytes = vif->target_stats.rx_byte; - sinfo->filled |= STATION_INFO_RX_BYTES64; + sinfo->filled |= STATION_INFO_RX_BYTES; sinfo->rx_packets = vif->target_stats.rx_pkt; sinfo->filled |= STATION_INFO_RX_PACKETS; } if (vif->target_stats.tx_byte) { sinfo->tx_bytes = vif->target_stats.tx_byte; - sinfo->filled |= STATION_INFO_TX_BYTES64; + sinfo->filled |= STATION_INFO_TX_BYTES; sinfo->tx_packets = vif->target_stats.tx_pkt; sinfo->filled |= STATION_INFO_TX_PACKETS; } diff --git a/trunk/drivers/net/wireless/ath/ath9k/Kconfig b/trunk/drivers/net/wireless/ath/ath9k/Kconfig index 17507dc8a1e7..7647ed6b73d7 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/Kconfig +++ b/trunk/drivers/net/wireless/ath/ath9k/Kconfig @@ -58,7 +58,6 @@ config ATH9K_DEBUGFS bool "Atheros ath9k debugging" depends on ATH9K select MAC80211_DEBUGFS - select RELAY ---help--- Say Y, if you need access to ath9k's statistics for interrupts, rate control, etc. diff --git a/trunk/drivers/net/wireless/ath/ath9k/ath9k.h b/trunk/drivers/net/wireless/ath/ath9k/ath9k.h index a56b2416e2f9..b2d6c18d1678 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ath9k.h @@ -319,8 +319,6 @@ struct ath_rx { struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; struct sk_buff *frag; - - u32 ampdu_ref; }; int ath_startrecv(struct ath_softc *sc); @@ -389,7 +387,6 @@ struct ath_beacon_config { u16 bmiss_timeout; u8 dtim_count; bool enable_beacon; - bool ibss_creator; }; struct ath_beacon { @@ -757,7 +754,6 @@ struct ath_softc { /* relay(fs) channel for spectral scan */ struct rchan *rfs_chan_spec_scan; enum spectral_mode spectral_mode; - struct ath_spec_scan spec_config; int scanning; #ifdef CONFIG_PM_SLEEP @@ -867,31 +863,31 @@ static inline u8 spectral_bitmap_weight(u8 *bins) * interface. */ enum ath_fft_sample_type { - ATH_FFT_SAMPLE_HT20 = 1, + ATH_FFT_SAMPLE_HT20 = 0, }; struct fft_sample_tlv { u8 type; /* see ath_fft_sample */ - __be16 length; + u16 length; /* type dependent data follows */ } __packed; struct fft_sample_ht20 { struct fft_sample_tlv tlv; - u8 max_exp; + u8 __alignment; - __be16 freq; + u16 freq; s8 rssi; s8 noise; - __be16 max_magnitude; + u16 max_magnitude; u8 max_index; u8 bitmap_weight; - __be64 tsf; + u64 tsf; - u8 data[SPECTRAL_HT20_NUM_BINS]; + u16 data[SPECTRAL_HT20_NUM_BINS]; } __packed; void ath9k_tasklet(unsigned long data); diff --git a/trunk/drivers/net/wireless/ath/ath9k/beacon.c b/trunk/drivers/net/wireless/ath/ath9k/beacon.c index 5f05c26d1ec4..dd3771954bd7 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/beacon.c +++ b/trunk/drivers/net/wireless/ath/ath9k/beacon.c @@ -407,17 +407,12 @@ void ath9k_beacon_tasklet(unsigned long data) } } -/* - * Both nexttbtt and intval have to be in usecs. - */ -static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, - u32 intval, bool reset_tsf) +static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval) { struct ath_hw *ah = sc->sc_ah; ath9k_hw_disable_interrupts(ah); - if (reset_tsf) - ath9k_hw_reset_tsf(ah); + ath9k_hw_reset_tsf(ah); ath9k_beaconq_config(sc); ath9k_hw_beaconinit(ah, nexttbtt, intval); sc->beacon.bmisscnt = 0; @@ -447,12 +442,10 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, else ah->imask &= ~ATH9K_INT_SWBA; - ath_dbg(common, BEACON, - "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", + ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n", nexttbtt, intval, conf->beacon_interval); - ath9k_beacon_init(sc, nexttbtt, intval, true); + ath9k_beacon_init(sc, nexttbtt, intval); } /* @@ -593,45 +586,17 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, ath9k_reset_beacon_status(sc); intval = TU_TO_USEC(conf->beacon_interval); - - if (conf->ibss_creator) { - nexttbtt = intval; - } else { - u32 tbtt, offset, tsftu; - u64 tsf; - - /* - * Pull nexttbtt forward to reflect the current - * sync'd TSF. - */ - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - offset = tsftu % conf->beacon_interval; - tbtt = tsftu - offset; - if (offset) - tbtt += conf->beacon_interval; - - nexttbtt = TU_TO_USEC(tbtt); - } + nexttbtt = intval; if (conf->enable_beacon) ah->imask |= ATH9K_INT_SWBA; else ah->imask &= ~ATH9K_INT_SWBA; - ath_dbg(common, BEACON, - "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", + ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n", nexttbtt, intval, conf->beacon_interval); - ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); - - /* - * Set the global 'beacon has been configured' flag for the - * joiner case in IBSS mode. - */ - if (!conf->ibss_creator && conf->enable_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + ath9k_beacon_init(sc, nexttbtt, intval); } bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) @@ -674,7 +639,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; - cur_conf->ibss_creator = bss_conf->ibss_creator; cur_conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; @@ -702,59 +666,34 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; - unsigned long flags; - bool skip_beacon = false; if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { ath9k_cache_beacon_config(sc, bss_conf); ath9k_set_beacon(sc); set_bit(SC_OP_BEACONS, &sc->sc_flags); - return; - - } - - /* - * Take care of multiple interfaces when - * enabling/disabling SWBA. - */ - if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (!bss_conf->enable_beacon && - (sc->nbcnvifs <= 1)) { - cur_conf->enable_beacon = false; - } else if (bss_conf->enable_beacon) { - cur_conf->enable_beacon = true; - ath9k_cache_beacon_config(sc, bss_conf); - } - } - - /* - * Configure the HW beacon registers only when we have a valid - * beacon interval. - */ - if (cur_conf->beacon_interval) { + } else { /* - * If we are joining an existing IBSS network, start beaconing - * only after a TSF-sync has taken place. Ensure that this - * happens by setting the appropriate flags. + * Take care of multiple interfaces when + * enabling/disabling SWBA. */ - if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator && - bss_conf->enable_beacon) { - spin_lock_irqsave(&sc->sc_pm_lock, flags); - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - skip_beacon = true; - } else { - ath9k_set_beacon(sc); + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (!bss_conf->enable_beacon && + (sc->nbcnvifs <= 1)) { + cur_conf->enable_beacon = false; + } else if (bss_conf->enable_beacon) { + cur_conf->enable_beacon = true; + ath9k_cache_beacon_config(sc, bss_conf); + } } - /* - * Do not set the SC_OP_BEACONS flag for IBSS joiner mode - * here, it is done in ath9k_beacon_config_adhoc(). - */ - if (cur_conf->enable_beacon && !skip_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); - else - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + if (cur_conf->beacon_interval) { + ath9k_set_beacon(sc); + + if (cur_conf->enable_beacon) + set_bit(SC_OP_BEACONS, &sc->sc_flags); + else + clear_bit(SC_OP_BEACONS, &sc->sc_flags); + } } } diff --git a/trunk/drivers/net/wireless/ath/ath9k/debug.c b/trunk/drivers/net/wireless/ath/ath9k/debug.c index 3714b971d18e..6c5d313ebcb7 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/debug.c +++ b/trunk/drivers/net/wireless/ath/ath9k/debug.c @@ -895,7 +895,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, RXS_ERR("RX-Bytes-All", rx_bytes_all); RXS_ERR("RX-Beacons", rx_beacons); RXS_ERR("RX-Frags", rx_frags); - RXS_ERR("RX-Spectral", rx_spectral); if (len > size) len = size; @@ -1036,182 +1035,6 @@ static const struct file_operations fops_spec_scan_ctl = { .llseek = default_llseek, }; -static ssize_t read_file_spectral_short_repeat(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_short_repeat(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 1) - return -EINVAL; - - sc->spec_config.short_repeat = val; - return count; -} - -static const struct file_operations fops_spectral_short_repeat = { - .read = read_file_spectral_short_repeat, - .write = write_file_spectral_short_repeat, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_count(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.count); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_count(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 255) - return -EINVAL; - - sc->spec_config.count = val; - return count; -} - -static const struct file_operations fops_spectral_count = { - .read = read_file_spectral_count, - .write = write_file_spectral_count, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_period(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.period); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_period(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 255) - return -EINVAL; - - sc->spec_config.period = val; - return count; -} - -static const struct file_operations fops_spectral_period = { - .read = read_file_spectral_period, - .write = write_file_spectral_period, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_fft_period(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.fft_period); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_fft_period(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 15) - return -EINVAL; - - sc->spec_config.fft_period = val; - return count; -} - -static const struct file_operations fops_spectral_fft_period = { - .read = read_file_spectral_fft_period, - .write = write_file_spectral_fft_period, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - static struct dentry *create_buf_file_handler(const char *filename, struct dentry *parent, umode_t mode, @@ -1236,13 +1059,11 @@ static int remove_buf_file_handler(struct dentry *dentry) void ath_debug_send_fft_sample(struct ath_softc *sc, struct fft_sample_tlv *fft_sample_tlv) { - int length; if (!sc->rfs_chan_spec_scan) return; - length = __be16_to_cpu(fft_sample_tlv->length) + - sizeof(*fft_sample_tlv); - relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); + relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, + fft_sample_tlv->length + sizeof(*fft_sample_tlv)); } static struct rchan_callbacks rfs_spec_scan_cb = { @@ -2072,16 +1893,6 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_spec_scan_ctl); - debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_spectral_short_repeat); - debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_spectral_count); - debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_spectral_period); - debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_spectral_fft_period); #ifdef CONFIG_ATH9K_MAC_DEBUG debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, diff --git a/trunk/drivers/net/wireless/ath/ath9k/debug.h b/trunk/drivers/net/wireless/ath/ath9k/debug.h index 410d6d8f1aa7..a22c0d780700 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/debug.h +++ b/trunk/drivers/net/wireless/ath/ath9k/debug.h @@ -219,7 +219,6 @@ struct ath_tx_stats { * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. * @rx_beacons: No. of beacons received. * @rx_frags: No. of rx-fragements received. - * @rx_spectral: No of spectral packets received. */ struct ath_rx_stats { u32 rx_pkts_all; @@ -238,7 +237,6 @@ struct ath_rx_stats { u32 rx_too_many_frags_err; u32 rx_beacons; u32 rx_frags; - u32 rx_spectral; }; struct ath_stats { diff --git a/trunk/drivers/net/wireless/ath/ath9k/init.c b/trunk/drivers/net/wireless/ath/ath9k/init.c index af932c9444de..4b1abc7da98c 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/init.c +++ b/trunk/drivers/net/wireless/ath/ath9k/init.c @@ -497,13 +497,6 @@ static void ath9k_init_misc(struct ath_softc *sc) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; - - sc->spec_config.enabled = 0; - sc->spec_config.short_repeat = true; - sc->spec_config.count = 8; - sc->spec_config.endless = false; - sc->spec_config.period = 0xFF; - sc->spec_config.fft_period = 0xF; } static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, @@ -922,7 +915,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) ath9k_eeprom_release(sc); - if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { + if (sc->rfs_chan_spec_scan) { relay_close(sc->rfs_chan_spec_scan); sc->rfs_chan_spec_scan = NULL; } diff --git a/trunk/drivers/net/wireless/ath/ath9k/mac.c b/trunk/drivers/net/wireless/ath/ath9k/mac.c index 811007ec07a7..b42be910a83d 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/mac.c +++ b/trunk/drivers/net/wireless/ath/ath9k/mac.c @@ -605,13 +605,13 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, * reported, then decryption and MIC errors are irrelevant, * the frame is going to be dropped either way */ - if (ads.ds_rxstatus8 & AR_PHYErr) { + if (ads.ds_rxstatus8 & AR_CRCErr) + rs->rs_status |= ATH9K_RXERR_CRC; + else if (ads.ds_rxstatus8 & AR_PHYErr) { rs->rs_status |= ATH9K_RXERR_PHY; phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); rs->rs_phyerr = phyerr; - } else if (ads.ds_rxstatus8 & AR_CRCErr) - rs->rs_status |= ATH9K_RXERR_CRC; - else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; diff --git a/trunk/drivers/net/wireless/ath/ath9k/main.c b/trunk/drivers/net/wireless/ath/ath9k/main.c index 6e66f9c6782b..4b72b660f180 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/main.c +++ b/trunk/drivers/net/wireless/ath/ath9k/main.c @@ -320,25 +320,28 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct ath_node *an; + u8 density; an = (struct ath_node *)sta->drv_priv; an->sc = sc; an->sta = sta; an->vif = vif; - ath_tx_node_init(sc, an); - - if (sta->ht_cap.ht_supported) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); - an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); + density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); + an->mpdudensity = density; } } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; - ath_tx_node_cleanup(sc, an); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + ath_tx_node_cleanup(sc, an); } void ath9k_tasklet(unsigned long data) @@ -1096,34 +1099,45 @@ int ath9k_spectral_scan_config(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath_spec_scan param; if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { ath_err(common, "spectrum analyzer not implemented on this hardware\n"); return -1; } + /* NOTE: this will generate a few samples ... + * + * TODO: review default parameters, and/or define an interface to set + * them. + */ + param.enabled = 1; + param.short_repeat = true; + param.count = 8; + param.endless = false; + param.period = 0xFF; + param.fft_period = 0xF; + switch (spectral_mode) { case SPECTRAL_DISABLED: - sc->spec_config.enabled = 0; + param.enabled = 0; break; case SPECTRAL_BACKGROUND: /* send endless samples. * TODO: is this really useful for "background"? */ - sc->spec_config.endless = 1; - sc->spec_config.enabled = 1; + param.endless = 1; break; case SPECTRAL_CHANSCAN: + break; case SPECTRAL_MANUAL: - sc->spec_config.endless = 0; - sc->spec_config.enabled = 1; break; default: return -1; } ath9k_ps_wakeup(sc); - ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config); + ath9k_hw_ops(ah)->spectral_scan_config(ah, ¶m); ath9k_ps_restore(sc); sc->spectral_mode = spectral_mode; diff --git a/trunk/drivers/net/wireless/ath/ath9k/mci.c b/trunk/drivers/net/wireless/ath/ath9k/mci.c index 815bee21c19a..d2074334ec9b 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/mci.c +++ b/trunk/drivers/net/wireless/ath/ath9k/mci.c @@ -474,6 +474,8 @@ void ath_mci_cleanup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; + struct ath_mci_coex *mci = &sc->mci_coex; + struct ath_mci_buf *buf = &mci->sched_buf; ar9003_mci_cleanup(ah); diff --git a/trunk/drivers/net/wireless/ath/ath9k/recv.c b/trunk/drivers/net/wireless/ath/ath9k/recv.c index ee156e543147..d7c129bb571b 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/recv.c +++ b/trunk/drivers/net/wireless/ath/ath9k/recv.c @@ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (sc->ps_flags & PS_BEACON_SYNC) { sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, - "Reconfigure beacon timers based on synchronized timestamp\n"); + "Reconfigure Beacon timers based on timestamp from the AP\n"); ath9k_set_beacon(sc); } @@ -1016,20 +1016,18 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, rxs->flag &= ~RX_FLAG_DECRYPTED; } -#ifdef CONFIG_ATH9K_DEBUGFS static s8 fix_rssi_inv_only(u8 rssi_val) { if (rssi_val == 128) rssi_val = 0; return (s8) rssi_val; } -#endif -/* returns 1 if this was a spectral frame, even if not handled. */ -static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, - struct ath_rx_status *rs, u64 tsf) + +static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf) { -#ifdef CONFIG_ATH9K_DEBUGFS +#ifdef CONFIG_ATH_DEBUG struct ath_hw *ah = sc->sc_ah; u8 bins[SPECTRAL_HT20_NUM_BINS]; u8 *vdata = (u8 *)hdr; @@ -1037,8 +1035,7 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, struct ath_radar_info *radar_info; struct ath_ht20_mag_info *mag_info; int len = rs->rs_datalen; - int dc_pos; - u16 length, max_magnitude; + int i, dc_pos; /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT @@ -1047,14 +1044,7 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) - return 0; - - /* check if spectral scan bit is set. This does not have to be checked - * if received through a SPECTRAL phy error, but shouldn't hurt. - */ - radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; - if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) - return 0; + return; /* Variation in the data length is possible and will be fixed later. * Note that we only support HT20 for now. @@ -1063,13 +1053,19 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, */ if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) - return 1; + return; + + /* check if spectral scan bit is set. This does not have to be checked + * if received through a SPECTRAL phy error, but shouldn't hurt. + */ + radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) + return; fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; - length = sizeof(fft_sample) - sizeof(fft_sample.tlv); - fft_sample.tlv.length = __cpu_to_be16(length); + fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv); - fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); + fft_sample.freq = ah->curchan->chan->center_freq; fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); fft_sample.noise = ah->noise; @@ -1097,7 +1093,7 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); break; default: - return 1; + return; } /* DC value (value in the middle) is the blind spot of the spectral @@ -1109,41 +1105,19 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, /* mag data is at the end of the frame, in front of radar_info */ mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; - /* copy raw bins without scaling them */ - memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); - fft_sample.max_exp = mag_info->max_exp & 0xf; + /* Apply exponent and grab further auxiliary information. */ + for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) + fft_sample.data[i] = bins[i] << mag_info->max_exp; - max_magnitude = spectral_max_magnitude(mag_info->all_bins); - fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); + fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins); fft_sample.max_index = spectral_max_index(mag_info->all_bins); fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); - fft_sample.tsf = __cpu_to_be64(tsf); + fft_sample.tsf = tsf; ath_debug_send_fft_sample(sc, &fft_sample.tlv); - return 1; -#else - return 0; #endif } -static void ath9k_apply_ampdu_details(struct ath_softc *sc, - struct ath_rx_status *rs, struct ieee80211_rx_status *rxs) -{ - if (rs->rs_isaggr) { - rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; - - rxs->ampdu_reference = sc->rx.ampdu_ref; - - if (!rs->rs_moreaggr) { - rxs->flag |= RX_FLAG_AMPDU_IS_LAST; - sc->rx.ampdu_ref++; - } - - if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE) - rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR; - } -} - int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; @@ -1228,12 +1202,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; - if (rs.rs_status & ATH9K_RXERR_PHY) { - if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) { - RX_STAT_INC(rx_spectral); - goto requeue_drop_frag; - } - } + if ((rs.rs_status & ATH9K_RXERR_PHY)) + ath_process_fft(sc, hdr, &rs, rxs->mactime); retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, rxs, &decrypt_error); @@ -1350,8 +1320,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) ath_ant_comb_scan(sc, &rs); - ath9k_apply_ampdu_details(sc, &rs, rxs); - ieee80211_rx(hw, skb); requeue_drop_frag: diff --git a/trunk/drivers/net/wireless/ath/ath9k/xmit.c b/trunk/drivers/net/wireless/ath/ath9k/xmit.c index 89a64411b82e..feacaafee959 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/xmit.c +++ b/trunk/drivers/net/wireless/ath/ath9k/xmit.c @@ -1233,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, * in HT IBSS when a beacon with HT-info is received after the station * has already been added. */ - if (sta->ht_cap.ht_supported) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); @@ -1904,7 +1904,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, struct ath_buf *bf; u8 tidno; - if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an && + ieee80211_is_data_qos(hdr->frame_control)) { tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(txctl->an, tidno); diff --git a/trunk/drivers/net/wireless/ath/wil6210/cfg80211.c b/trunk/drivers/net/wireless/ath/wil6210/cfg80211.c index 002851fceb2f..116f4e807ae1 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/trunk/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -204,6 +204,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, break; default: return -EOPNOTSUPP; + } /* FW don't support scan after connection attempt */ @@ -227,8 +228,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } /* 0-based channel indexes */ cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; - wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch, - request->channels[i]->center_freq); + wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch, + request->channels[i]->center_freq); } return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + @@ -424,8 +425,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, - channel->center_freq, info->privacy ? "secure" : "open"); + wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, + channel->center_freq, info->privacy ? "secure" : "open"); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, info->ssid, info->ssid_len); diff --git a/trunk/drivers/net/wireless/ath/wil6210/interrupt.c b/trunk/drivers/net/wireless/ath/wil6210/interrupt.c index dc97e7b2609c..38049da71049 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/trunk/drivers/net/wireless/ath/wil6210/interrupt.c @@ -38,9 +38,7 @@ #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) -#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \ - ISR_MISC_MBOX_EVT | \ - ISR_MISC_FW_ERROR) +#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ BIT_DMA_PSEUDO_CAUSE_TX | \ @@ -52,6 +50,7 @@ static inline void wil_icr_clear(u32 x, void __iomem *addr) { + } #else /* defined(CONFIG_WIL6210_ISR_COR) */ /* configure to Write-1-to-Clear mode */ @@ -95,7 +94,7 @@ static void wil6210_mask_irq_misc(struct wil6210_priv *wil) static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) { - wil_dbg_irq(wil, "%s()\n", __func__); + wil_dbg_IRQ(wil, "%s()\n", __func__); iowrite32(WIL6210_IRQ_DISABLE, wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); @@ -126,7 +125,7 @@ static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) { - wil_dbg_irq(wil, "%s()\n", __func__); + wil_dbg_IRQ(wil, "%s()\n", __func__); set_bit(wil_status_irqen, &wil->status); @@ -136,7 +135,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) void wil6210_disable_irq(struct wil6210_priv *wil) { - wil_dbg_irq(wil, "%s()\n", __func__); + wil_dbg_IRQ(wil, "%s()\n", __func__); wil6210_mask_irq_tx(wil); wil6210_mask_irq_rx(wil); @@ -146,7 +145,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil) void wil6210_enable_irq(struct wil6210_priv *wil) { - wil_dbg_irq(wil, "%s()\n", __func__); + wil_dbg_IRQ(wil, "%s()\n", __func__); iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICC)); @@ -168,7 +167,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); + wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: RX\n"); @@ -178,7 +177,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil6210_mask_irq_rx(wil); if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { - wil_dbg_irq(wil, "RX done\n"); + wil_dbg_IRQ(wil, "RX done\n"); isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; wil_rx_handle(wil); } @@ -198,7 +197,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); + wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: TX\n"); @@ -209,13 +208,13 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { uint i; - wil_dbg_irq(wil, "TX done\n"); + wil_dbg_IRQ(wil, "TX done\n"); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; for (i = 0; i < 24; i++) { u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); if (isr & mask) { isr &= ~mask; - wil_dbg_irq(wil, "TX done(%i)\n", i); + wil_dbg_IRQ(wil, "TX done(%i)\n", i); wil_tx_complete(wil, i); } } @@ -229,17 +228,6 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) return IRQ_HANDLED; } -static void wil_notify_fw_error(struct wil6210_priv *wil) -{ - struct device *dev = &wil_to_ndev(wil)->dev; - char *envp[3] = { - [0] = "SOURCE=wil6210", - [1] = "EVENT=FW_ERROR", - [2] = NULL, - }; - kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); -} - static irqreturn_t wil6210_irq_misc(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -247,7 +235,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); + wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: MISC\n"); @@ -256,15 +244,8 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) wil6210_mask_irq_misc(wil); - if (isr & ISR_MISC_FW_ERROR) { - wil_dbg_irq(wil, "IRQ: Firmware error\n"); - clear_bit(wil_status_fwready, &wil->status); - wil_notify_fw_error(wil); - isr &= ~ISR_MISC_FW_ERROR; - } - if (isr & ISR_MISC_FW_READY) { - wil_dbg_irq(wil, "IRQ: FW ready\n"); + wil_dbg_IRQ(wil, "IRQ: FW ready\n"); /** * Actual FW ready indicated by the * WMI_FW_READY_EVENTID @@ -287,10 +268,10 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) struct wil6210_priv *wil = cookie; u32 isr = wil->isr_misc; - wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); + wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); if (isr & ISR_MISC_MBOX_EVT) { - wil_dbg_irq(wil, "MBOX event\n"); + wil_dbg_IRQ(wil, "MBOX event\n"); wmi_recv_cmd(wil); isr &= ~ISR_MISC_MBOX_EVT; } @@ -312,7 +293,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - wil_dbg_irq(wil, "Thread IRQ\n"); + wil_dbg_IRQ(wil, "Thread IRQ\n"); /* Discover real IRQ cause */ if (wil->isr_misc) wil6210_irq_misc_thread(irq, cookie); @@ -389,8 +370,6 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) if (wil6210_debug_irq_mask(wil, pseudo_cause)) return IRQ_NONE; - wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); - wil6210_mask_irq_pseudo(wil); /* Discover real IRQ cause @@ -422,6 +401,8 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) if (rc != IRQ_WAKE_THREAD) wil6210_unmask_irq_pseudo(wil); + wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); + return rc; } diff --git a/trunk/drivers/net/wireless/ath/wil6210/main.c b/trunk/drivers/net/wireless/ath/wil6210/main.c index 761c389586d4..95fcd361322b 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/main.c +++ b/trunk/drivers/net/wireless/ath/wil6210/main.c @@ -64,7 +64,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; - wil_dbg_misc(wil, "%s()\n", __func__); + wil_dbg(wil, "%s()\n", __func__); wil_link_off(wil); clear_bit(wil_status_fwconnected, &wil->status); @@ -80,13 +80,11 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) GFP_KERNEL); break; default: - break; + ; } for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) wil_vring_fini_tx(wil, i); - - clear_bit(wil_status_dontscan, &wil->status); } static void wil_disconnect_worker(struct work_struct *work) @@ -101,7 +99,7 @@ static void wil_connect_timer_fn(ulong x) { struct wil6210_priv *wil = (void *)x; - wil_dbg_misc(wil, "Connect timeout\n"); + wil_dbg(wil, "Connect timeout\n"); /* reschedule to thread context - disconnect won't * run from atomic context @@ -109,18 +107,9 @@ static void wil_connect_timer_fn(ulong x) schedule_work(&wil->disconnect_worker); } -static void wil_cache_mbox_regs(struct wil6210_priv *wil) -{ - /* make shadow copy of registers that should not change on run time */ - wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, - sizeof(struct wil6210_mbox_ctl)); - wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); - wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); -} - int wil_priv_init(struct wil6210_priv *wil) { - wil_dbg_misc(wil, "%s()\n", __func__); + wil_dbg(wil, "%s()\n", __func__); mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); @@ -147,7 +136,11 @@ int wil_priv_init(struct wil6210_priv *wil) return -EAGAIN; } - wil_cache_mbox_regs(wil); + /* make shadow copy of registers that should not change on run time */ + wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, + sizeof(struct wil6210_mbox_ctl)); + wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); + wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); return 0; } @@ -169,7 +162,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { - wil_dbg_misc(wil, "Resetting...\n"); + wil_dbg(wil, "Resetting...\n"); /* register write */ #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) @@ -209,7 +202,7 @@ static void wil_target_reset(struct wil6210_priv *wil) msleep(2000); - wil_dbg_misc(wil, "Reset completed\n"); + wil_dbg(wil, "Reset completed\n"); #undef W #undef S @@ -232,8 +225,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) wil_err(wil, "Firmware not ready\n"); return -ETIME; } else { - wil_dbg_misc(wil, "FW ready after %d ms\n", - jiffies_to_msecs(to-left)); + wil_dbg(wil, "FW ready after %d ms\n", + jiffies_to_msecs(to-left)); } return 0; } @@ -250,13 +243,13 @@ int wil_reset(struct wil6210_priv *wil) cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); - wil6210_disable_irq(wil); - wil->status = 0; - wmi_event_flush(wil); - flush_workqueue(wil->wmi_wq_conn); flush_workqueue(wil->wmi_wq); + flush_workqueue(wil->wmi_wq_conn); + + wil6210_disable_irq(wil); + wil->status = 0; /* TODO: put MAC in reset */ wil_target_reset(wil); @@ -265,7 +258,11 @@ int wil_reset(struct wil6210_priv *wil) wil->pending_connect_cid = -1; INIT_COMPLETION(wil->wmi_ready); - wil_cache_mbox_regs(wil); + /* make shadow copy of registers that should not change on run time */ + wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, + sizeof(struct wil6210_mbox_ctl)); + wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); + wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); /* TODO: release MAC reset */ wil6210_enable_irq(wil); @@ -281,7 +278,7 @@ void wil_link_on(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); - wil_dbg_misc(wil, "%s()\n", __func__); + wil_dbg(wil, "%s()\n", __func__); netif_carrier_on(ndev); netif_tx_wake_all_queues(ndev); @@ -291,7 +288,7 @@ void wil_link_off(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); - wil_dbg_misc(wil, "%s()\n", __func__); + wil_dbg(wil, "%s()\n", __func__); netif_tx_stop_all_queues(ndev); netif_carrier_off(ndev); @@ -314,27 +311,27 @@ static int __wil_up(struct wil6210_priv *wil) wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: - wil_dbg_misc(wil, "type: STATION\n"); + wil_dbg(wil, "type: STATION\n"); bi = 0; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_AP: - wil_dbg_misc(wil, "type: AP\n"); + wil_dbg(wil, "type: AP\n"); bi = 100; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_CLIENT: - wil_dbg_misc(wil, "type: P2P_CLIENT\n"); + wil_dbg(wil, "type: P2P_CLIENT\n"); bi = 0; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_GO: - wil_dbg_misc(wil, "type: P2P_GO\n"); + wil_dbg(wil, "type: P2P_GO\n"); bi = 100; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_MONITOR: - wil_dbg_misc(wil, "type: Monitor\n"); + wil_dbg(wil, "type: Monitor\n"); bi = 0; ndev->type = ARPHRD_IEEE80211_RADIOTAP; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ @@ -357,7 +354,7 @@ static int __wil_up(struct wil6210_priv *wil) wmi_set_channel(wil, channel->hw_value); break; default: - break; + ; } /* MAC address - pre-requisite for other commands */ diff --git a/trunk/drivers/net/wireless/ath/wil6210/netdev.c b/trunk/drivers/net/wireless/ath/wil6210/netdev.c index 8ce2e33dce20..3068b5cb53a7 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/netdev.c +++ b/trunk/drivers/net/wireless/ath/wil6210/netdev.c @@ -35,12 +35,37 @@ static int wil_stop(struct net_device *ndev) return wil_down(wil); } +/* + * AC to queue mapping + * + * AC_VO -> queue 3 + * AC_VI -> queue 2 + * AC_BE -> queue 1 + * AC_BK -> queue 0 + */ +static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb) +{ + static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + struct wil6210_priv *wil = ndev_to_wil(ndev); + u16 rc; + + skb->priority = cfg80211_classify8021d(skb); + + rc = wil_1d_to_queue[skb->priority]; + + wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority, + (int)rc); + + return rc; +} + static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, .ndo_start_xmit = wil_start_xmit, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, + .ndo_select_queue = wil_select_queue, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; void *wil_if_alloc(struct device *dev, void __iomem *csr) @@ -72,7 +97,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", ether_setup); + ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/trunk/drivers/net/wireless/ath/wil6210/pcie_bus.c b/trunk/drivers/net/wireless/ath/wil6210/pcie_bus.c index 81c35c6e3832..0fc83edd6bad 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/trunk/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -53,7 +53,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) } wil->n_msi = use_msi; if (wil->n_msi) { - wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); + wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi); rc = pci_enable_msi_block(pdev, wil->n_msi); if (rc && (wil->n_msi == 3)) { wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); @@ -65,7 +65,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) wil->n_msi = 0; } } else { - wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); + wil_dbg(wil, "MSI interrupts disabled, use INTx\n"); } rc = wil6210_init_irq(wil, pdev->irq); diff --git a/trunk/drivers/net/wireless/ath/wil6210/txrx.c b/trunk/drivers/net/wireless/ath/wil6210/txrx.c index 64b971fdc3cc..f29c294413cf 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/txrx.c +++ b/trunk/drivers/net/wireless/ath/wil6210/txrx.c @@ -100,8 +100,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) d->dma.status = TX_DMA_STATUS_DU; } - wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, - vring->va, (unsigned long long)vring->pa, vring->ctx); + wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, + vring->va, (unsigned long long)vring->pa, vring->ctx); return 0; } @@ -353,8 +353,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) wil_rx_add_radiotap_header(wil, skb, d); - wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); - wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, + wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); + wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); wil_vring_advance_head(vring, 1); @@ -369,7 +369,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ ftype = wil_rxdesc_ftype(d) << 2; if (ftype != IEEE80211_FTYPE_DATA) { - wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); + wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype); /* TODO: process it */ kfree_skb(skb); return NULL; @@ -430,8 +430,6 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) int rc; unsigned int len = skb->len; - skb_orphan(skb); - if (in_interrupt()) rc = netif_rx(skb); else @@ -461,11 +459,13 @@ void wil_rx_handle(struct wil6210_priv *wil) wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); return; } - wil_dbg_txrx(wil, "%s()\n", __func__); + wil_dbg_TXRX(wil, "%s()\n", __func__); while (NULL != (skb = wil_vring_reap_rx(wil, v))) { - wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); + skb_orphan(skb); + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { skb->dev = ndev; skb_reset_mac_header(skb); @@ -484,18 +484,53 @@ void wil_rx_handle(struct wil6210_priv *wil) int wil_rx_init(struct wil6210_priv *wil) { + struct net_device *ndev = wil_to_ndev(wil); + struct wireless_dev *wdev = wil->wdev; struct vring *vring = &wil->vring_rx; int rc; + struct wmi_cfg_rx_chain_cmd cmd = { + .action = WMI_RX_CHAIN_ADD, + .rx_sw_ring = { + .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), + }, + .mid = 0, /* TODO - what is it? */ + .decap_trans_type = WMI_DECAP_TYPE_802_3, + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cfg_rx_chain_done_event evt; + } __packed evt; vring->size = WIL6210_RX_RING_SIZE; rc = wil_vring_alloc(wil, vring); if (rc) return rc; - rc = wmi_rx_chain_add(wil, vring); + cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); + cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size); + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { + struct ieee80211_channel *ch = wdev->preset_chandef.chan; + + cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); + if (ch) + cmd.sniffer_cfg.channel = ch->hw_value - 1; + cmd.sniffer_cfg.phy_info_mode = + cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); + cmd.sniffer_cfg.phy_support = + cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) + ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); + } + /* typical time for secure PCP is 840ms */ + rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), + WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); if (rc) goto err_free; + vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); + + wil_dbg(wil, "Rx init: status %d tail 0x%08x\n", + le32_to_cpu(evt.evt.status), vring->hwtail); + rc = wil_rx_refill(wil, vring->size); if (rc) goto err_free; @@ -511,8 +546,25 @@ void wil_rx_fini(struct wil6210_priv *wil) { struct vring *vring = &wil->vring_rx; - if (vring->va) + if (vring->va) { + int rc; + struct wmi_cfg_rx_chain_cmd cmd = { + .action = cpu_to_le32(WMI_RX_CHAIN_DEL), + .rx_sw_ring = { + .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), + }, + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_cfg_rx_chain_done_event cfg; + } __packed wmi_rx_cfg_reply; + + rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), + WMI_CFG_RX_CHAIN_DONE_EVENTID, + &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply), + 100); wil_vring_free(wil, vring, 0); + } } int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, @@ -565,7 +617,6 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { wil_err(wil, "Tx config failed, status 0x%02x\n", reply.cmd.status); - rc = -EINVAL; goto out_free; } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); @@ -638,7 +689,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, uint i = swhead; dma_addr_t pa; - wil_dbg_txrx(wil, "%s()\n", __func__); + wil_dbg_TXRX(wil, "%s()\n", __func__); if (avail < vring->size/8) netif_tx_stop_all_queues(wil_to_ndev(wil)); @@ -655,9 +706,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), + wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), skb->data, (unsigned long long)pa); - wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); if (unlikely(dma_mapping_error(dev, pa))) @@ -686,12 +737,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); - wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, + wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); - wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); /* hold reference to skb * to prevent skb release before accounting @@ -724,7 +775,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct vring *vring; int rc; - wil_dbg_txrx(wil, "%s()\n", __func__); + wil_dbg_TXRX(wil, "%s()\n", __func__); if (!test_bit(wil_status_fwready, &wil->status)) { wil_err(wil, "FW not ready\n"); goto drop; @@ -751,13 +802,15 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) } switch (rc) { case 0: - /* statistics will be updated on the tx_complete */ + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; dev_kfree_skb_any(skb); return NETDEV_TX_OK; case -ENOMEM: return NETDEV_TX_BUSY; default: - break; /* goto drop; */ + ; /* goto drop; */ + break; } drop: netif_tx_stop_all_queues(ndev); @@ -774,7 +827,6 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ void wil_tx_complete(struct wil6210_priv *wil, int ringid) { - struct net_device *ndev = wil_to_ndev(wil); struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; @@ -783,7 +835,7 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) return; } - wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); + wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid); while (!wil_vring_is_empty(vring)) { volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; @@ -792,23 +844,16 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) if (!(d->dma.status & TX_DMA_STATUS_DU)) break; - wil_dbg_txrx(wil, + wil_dbg_TXRX(wil, "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", vring->swtail, d->dma.length, d->dma.status, d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); skb = vring->ctx[vring->swtail]; if (skb) { - if (d->dma.error == 0) { - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += skb->len; - } else { - ndev->stats.tx_errors++; - } - dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); dev_kfree_skb_any(skb); vring->ctx[vring->swtail] = NULL; diff --git a/trunk/drivers/net/wireless/ath/wil6210/wil6210.h b/trunk/drivers/net/wireless/ath/wil6210/wil6210.h index aea961ff8f08..9bcfffa4006c 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/trunk/drivers/net/wireless/ath/wil6210/wil6210.h @@ -36,6 +36,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) +#define WIL6210_TX_QUEUES (4) + #define WIL6210_RX_RING_SIZE (128) #define WIL6210_TX_RING_SIZE (128) #define WIL6210_MAX_TX_RINGS (24) @@ -99,7 +101,8 @@ struct RGF_ICR { #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) - #define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */ + #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28) + #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29) /* Interrupt moderation control */ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) @@ -118,9 +121,8 @@ struct RGF_ICR { #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 /* ISR register bits */ -#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT(0) -#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1) -#define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) +#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0 +#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1 /* Hardware definitions end */ @@ -270,18 +272,17 @@ struct wil6210_priv { #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) -#define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) -#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) -#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) -#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) +#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) +#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) -#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ +#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ prefix_type, rowsize, \ groupsize, buf, len, ascii) -#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \ +#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ prefix_type, rowsize, \ @@ -327,7 +328,6 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, const void *mac_addr, int key_len, const void *key); int wmi_echo(struct wil6210_priv *wil); int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); -int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); diff --git a/trunk/drivers/net/wireless/ath/wil6210/wmi.c b/trunk/drivers/net/wireless/ath/wil6210/wmi.c index 0b70e17cd1fb..12915f6e7617 100644 --- a/trunk/drivers/net/wireless/ath/wil6210/wmi.c +++ b/trunk/drivers/net/wireless/ath/wil6210/wmi.c @@ -18,10 +18,8 @@ #include #include #include -#include #include "wil6210.h" -#include "txrx.h" #include "wmi.h" /** @@ -188,6 +186,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) wil_err(wil, "WMI size too large: %d bytes, max is %d\n", (int)(sizeof(cmd) + len), r->entry_size); return -ERANGE; + } might_sleep(); @@ -214,7 +213,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) } /* next head */ next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); - wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); + wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); /* wait till FW finish with previous command */ for (retry = 5; retry > 0; retry--) { r->tail = ioread32(wil->csr + HOST_MBOX + @@ -235,10 +234,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) } cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); /* set command */ - wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len); - wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, + wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len); + wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, sizeof(cmd), true); - wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, + wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); @@ -274,7 +273,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) struct wmi_ready_event *evt = d; u32 ver = le32_to_cpu(evt->sw_version); - wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); + wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); if (!is_valid_ether_addr(ndev->dev_addr)) { memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); @@ -287,7 +286,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, int len) { - wil_dbg_wmi(wil, "WMI: FW ready\n"); + wil_dbg_WMI(wil, "WMI: FW ready\n"); set_bit(wil_status_fwready, &wil->status); /* reuse wmi_ready for the firmware ready indication */ @@ -310,11 +309,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) u32 d_len = le32_to_cpu(data->info.len); u16 d_status = le16_to_cpu(data->info.status); - wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", + wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n", data->info.channel, data->info.mcs, data->info.snr); - wil_dbg_wmi(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, + wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, le16_to_cpu(data->info.stype)); - wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", + wil_dbg_WMI(wil, "qid %d mid %d cid %d\n", data->info.qid, data->info.mid, data->info.cid); if (!channel) { @@ -330,13 +329,13 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, u.beacon.variable); - wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); + wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap); bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, tsf, cap, bi, ie_buf, ie_len, signal, GFP_KERNEL); if (bss) { - wil_dbg_wmi(wil, "Added BSS %pM\n", + wil_dbg_WMI(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid); cfg80211_put_bss(bss); } else { @@ -352,7 +351,7 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, struct wmi_scan_complete_event *data = d; bool aborted = (data->status != 0); - wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); + wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); cfg80211_scan_done(wil->scan_request, aborted); wil->scan_request = NULL; } else { @@ -387,9 +386,9 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) return; } ch = evt->channel + 1; - wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", + wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n", evt->bssid, ch, evt->cid); - wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, evt->assoc_info, len - sizeof(*evt), true); /* figure out IE's */ @@ -451,13 +450,14 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, { struct wmi_disconnect_event *evt = d; - wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", + wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n", evt->bssid, evt->protocol_reason_status, evt->disconnect_reason); wil->sinfo_gen++; wil6210_disconnect(wil, evt->bssid); + clear_bit(wil_status_dontscan, &wil->status); } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) @@ -476,7 +476,7 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); - wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" + wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n" "BF status 0x%08x SNR 0x%08x\n" "Tx Tpt %d goodput %d Rx goodput %d\n" "Sectors(rx:tx) my %d:%d peer %d:%d\n", @@ -501,7 +501,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, struct sk_buff *skb; struct ethhdr *eth; - wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, + wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len, evt->src_mac); if (eapol_len > 196) { /* TODO: revisit size limit */ @@ -599,15 +599,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil) iowrite32(0, wil->csr + HOSTADDR(r->tail) + offsetof(struct wil6210_mbox_ring_desc, sync)); /* indicate */ - wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", + wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n", le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), hdr.flags); if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { - wil_dbg_wmi(wil, "WMI event 0x%04x\n", + wil_dbg_WMI(wil, "WMI event 0x%04x\n", evt->event.wmi.id); } - wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, + wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1, &evt->event.hdr, sizeof(hdr) + len, true); /* advance tail */ @@ -623,7 +623,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) { int q = queue_work(wil->wmi_wq, &wil->wmi_event_worker); - wil_dbg_wmi(wil, "queue_work -> %d\n", q); + wil_dbg_WMI(wil, "queue_work -> %d\n", q); } } } @@ -650,7 +650,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, cmdid, reply_id, to_msec); rc = -ETIME; } else { - wil_dbg_wmi(wil, + wil_dbg_WMI(wil, "wmi_call(0x%04x->0x%04x) completed in %d msec\n", cmdid, reply_id, to_msec - jiffies_to_msecs(remain)); @@ -680,7 +680,7 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) memcpy(cmd.mac, addr, ETH_ALEN); - wil_dbg_wmi(wil, "Set MAC %pM\n", addr); + wil_dbg_WMI(wil, "Set MAC %pM\n", addr); return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); } @@ -778,7 +778,7 @@ int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) skb_set_mac_header(skb, 0); eth = eth_hdr(skb); - wil_dbg_wmi(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); + wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) goto found_dest; @@ -853,60 +853,11 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) return rc; } -int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) -{ - struct wireless_dev *wdev = wil->wdev; - struct net_device *ndev = wil_to_ndev(wil); - struct wmi_cfg_rx_chain_cmd cmd = { - .action = WMI_RX_CHAIN_ADD, - .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), - .ring_mem_base = cpu_to_le64(vring->pa), - .ring_size = cpu_to_le16(vring->size), - }, - .mid = 0, /* TODO - what is it? */ - .decap_trans_type = WMI_DECAP_TYPE_802_3, - }; - struct { - struct wil6210_mbox_hdr_wmi wmi; - struct wmi_cfg_rx_chain_done_event evt; - } __packed evt; - int rc; - - if (wdev->iftype == NL80211_IFTYPE_MONITOR) { - struct ieee80211_channel *ch = wdev->preset_chandef.chan; - - cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); - if (ch) - cmd.sniffer_cfg.channel = ch->hw_value - 1; - cmd.sniffer_cfg.phy_info_mode = - cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); - cmd.sniffer_cfg.phy_support = - cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) - ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); - } - /* typical time for secure PCP is 840ms */ - rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), - WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); - if (rc) - return rc; - - vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); - - wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n", - le32_to_cpu(evt.evt.status), vring->hwtail); - - if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS) - rc = -EINVAL; - - return rc; -} - void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; - wil_dbg_wmi(wil, "%s()\n", __func__); + wil_dbg_WMI(wil, "%s()\n", __func__); list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { list_del(&evt->list); @@ -948,7 +899,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, wmi_evt_call_handler(wil, id, evt_data, len - sizeof(*wmi)); } - wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id); + wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id); complete(&wil->wmi_ready); return; } @@ -1013,7 +964,7 @@ void wmi_connect_worker(struct work_struct *work) return; } - wil_dbg_wmi(wil, "Configure for connection CID %d\n", + wil_dbg_WMI(wil, "Configure for connection CID %d\n", wil->pending_connect_cid); rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/trunk/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 756e19fc2795..1a6661a9f008 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -26,7 +26,6 @@ brcmfmac-objs += \ wl_cfg80211.o \ fwil.o \ fweh.o \ - p2p.o \ dhd_cdc.o \ dhd_common.o \ dhd_linux.o @@ -38,4 +37,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ usb.o brcmfmac-$(CONFIG_BRCMDBG) += \ - dhd_dbg.o + dhd_dbg.o \ No newline at end of file diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index ef6f23be6d32..a2f32fb990fa 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -72,7 +72,6 @@ #define BRCMF_C_SET_WSEC 134 #define BRCMF_C_GET_PHY_NOISE 135 #define BRCMF_C_GET_BSS_INFO 136 -#define BRCMF_C_SET_SCB_TIMEOUT 158 #define BRCMF_C_GET_PHYLIST 180 #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 @@ -150,7 +149,6 @@ #define BRCMF_E_REASON_MINTXRATE 9 #define BRCMF_E_REASON_TXFAIL 10 -#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4 #define BRCMF_E_REASON_FAST_ROAM_FAILED 5 #define BRCMF_E_REASON_DIRECTED_ROAM 6 #define BRCMF_E_REASON_TSPEC_REJECTED 7 @@ -377,28 +375,6 @@ struct brcmf_join_params { struct brcmf_assoc_params_le params_le; }; -/* scan params for extended join */ -struct brcmf_join_scan_params_le { - u8 scan_type; /* 0 use default, active or passive scan */ - __le32 nprobes; /* -1 use default, nr of probes per channel */ - __le32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - __le32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - __le32 home_time; /* -1 use default, dwell time for the home - * channel between channel scans - */ -}; - -/* extended join params */ -struct brcmf_ext_join_params_le { - struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */ - struct brcmf_join_scan_params_le scan_le; - struct brcmf_assoc_params_le assoc_le; -}; - struct brcmf_wsec_key { u32 index; /* key index */ u32 len; /* key length */ @@ -475,19 +451,6 @@ struct brcmf_sta_info_le { __le32 rx_decrypt_failures; /* # of packet decrypted failed */ }; -/* - * WLC_E_PROBRESP_MSG - * WLC_E_P2P_PROBREQ_MSG - * WLC_E_ACTION_FRAME_RX - */ -struct brcmf_rx_mgmt_data { - __be16 version; - __be16 chanspec; - __be32 rssi; - __be32 mactime; - __be32 rate; -}; - /* Bus independent dongle command */ struct brcmf_dcmd { uint cmd; /* common dongle cmd definition */ @@ -526,6 +489,9 @@ struct brcmf_pub { struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; + atomic_t pend_8021x_cnt; + wait_queue_head_t pend_8021x_wait; + struct brcmf_fweh_info fweh; #ifdef DEBUG struct dentry *dbgfs_dir; @@ -549,11 +515,9 @@ struct brcmf_cfg80211_vif; * @vif: points to cfg80211 specific interface information. * @ndev: associated network device. * @stats: interface specific network statistics. - * @ifidx: interface index in device firmware. + * @idx: interface index in device firmware. * @bssidx: index of bss associated with this interface. * @mac_addr: assigned mac address. - * @pend_8021x_cnt: tracks outstanding number of 802.1x frames. - * @pend_8021x_wait: used for signalling change in count. */ struct brcmf_if { struct brcmf_pub *drvr; @@ -562,11 +526,9 @@ struct brcmf_if { struct net_device_stats stats; struct work_struct setmacaddr_work; struct work_struct multicast_work; - int ifidx; + int idx; s32 bssidx; u8 mac_addr[ETH_ALEN]; - atomic_t pend_8021x_cnt; - wait_queue_head_t pend_8021x_wait; }; @@ -585,10 +547,9 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, struct sk_buff *rxp); -extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); -extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, - s32 ifidx, char *name, u8 *mac_addr); -extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); -extern u32 brcmf_get_chip_info(struct brcmf_if *ifp); +extern int brcmf_net_attach(struct brcmf_if *ifp); +extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, + s32 bssidx, char *name, u8 *mac_addr); +extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); #endif /* _BRCMF_H_ */ diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index ad25c3408b59..64c38f4226a3 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -24,6 +24,18 @@ enum brcmf_bus_state { BRCMF_BUS_DATA /* Ready for frame transfers */ }; +struct dngl_stats { + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* packets dropped by dongle */ + unsigned long tx_dropped; /* packets dropped by dongle */ + unsigned long multicast; /* multicast packets received */ +}; + struct brcmf_bus_dcmd { char *name; char *param; @@ -60,12 +72,11 @@ struct brcmf_bus_ops { * @drvr: public driver information. * @state: operational state of the bus interface. * @maxctl: maximum size for rxctl request message. + * @drvr_up: indicates driver up/down status. * @tx_realloc: number of tx packets realloced for headroom. * @dstats: dongle-based statistical data. * @align: alignment requirement for the bus. * @dcmd_list: bus/device specific dongle initialization commands. - * @chip: device identifier of the dongle chip. - * @chiprev: revision of the dongle chip. */ struct brcmf_bus { union { @@ -76,10 +87,10 @@ struct brcmf_bus { struct brcmf_pub *drvr; enum brcmf_bus_state state; uint maxctl; + bool drvr_up; unsigned long tx_realloc; + struct dngl_stats dstats; u8 align; - u32 chip; - u32 chiprev; struct list_head dcmd_list; struct brcmf_bus_ops *ops; diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index a2354d951dd7..bb454cdab29d 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -303,14 +303,6 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); return -EBADE; } - /* The ifidx is the idx to map to matching netdev/ifp. When receiving - * events this is easy because it contains the bssidx which maps - * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. - * bssidx 1 is used for p2p0 and no data can be received or - * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 - */ - if (*ifidx) - (*ifidx)++; if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 6e3846ca88be..e3326a58bdb1 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -26,8 +26,6 @@ #include "dhd_bus.h" #include "dhd_proto.h" #include "dhd_dbg.h" -#include "fwil_types.h" -#include "p2p.h" #include "wl_cfg80211.h" #include "fwil.h" @@ -42,12 +40,6 @@ MODULE_LICENSE("Dual BSD/GPL"); int brcmf_msg_level; module_param(brcmf_msg_level, int, 0); -/* P2P0 enable */ -static int brcmf_p2p_enable; -#ifdef CONFIG_BRCMDBG -module_param_named(p2pon, brcmf_p2p_enable, int, 0); -MODULE_PARM_DESC(p2pon, "enable p2p management functionality"); -#endif char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) { @@ -78,10 +70,9 @@ static void _brcmf_set_multicast_list(struct work_struct *work) u32 buflen; s32 err; - ifp = container_of(work, struct brcmf_if, multicast_work); - - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + brcmf_dbg(TRACE, "enter\n"); + ifp = container_of(work, struct brcmf_if, multicast_work); ndev = ifp->ndev; /* Determine initial value of allmulti flag */ @@ -138,10 +129,9 @@ _brcmf_set_mac_address(struct work_struct *work) struct brcmf_if *ifp; s32 err; - ifp = container_of(work, struct brcmf_if, setmacaddr_work); - - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + brcmf_dbg(TRACE, "enter\n"); + ifp = container_of(work, struct brcmf_if, setmacaddr_work); err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, ETH_ALEN); if (err < 0) { @@ -178,7 +168,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, struct brcmf_pub *drvr = ifp->drvr; struct ethhdr *eh; - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + brcmf_dbg(TRACE, "Enter\n"); /* Can the device send data? */ if (drvr->bus_if->state != BRCMF_BUS_DATA) { @@ -189,8 +179,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, goto done; } - if (!drvr->iflist[ifp->bssidx]) { - brcmf_err("bad ifidx %d\n", ifp->bssidx); + if (!drvr->iflist[ifp->idx]) { + brcmf_err("bad ifidx %d\n", ifp->idx); netif_stop_queue(ndev); dev_kfree_skb(skb); ret = -ENODEV; @@ -202,14 +192,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, struct sk_buff *skb2; brcmf_dbg(INFO, "%s: insufficient headroom\n", - brcmf_ifname(drvr, ifp->bssidx)); + brcmf_ifname(drvr, ifp->idx)); drvr->bus_if->tx_realloc++; skb2 = skb_realloc_headroom(skb, drvr->hdrlen); dev_kfree_skb(skb); skb = skb2; if (skb == NULL) { brcmf_err("%s: skb_realloc_headroom failed\n", - brcmf_ifname(drvr, ifp->bssidx)); + brcmf_ifname(drvr, ifp->idx)); ret = -ENOMEM; goto done; } @@ -227,21 +217,19 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, if (is_multicast_ether_addr(eh->h_dest)) drvr->tx_multicast++; if (ntohs(eh->h_proto) == ETH_P_PAE) - atomic_inc(&ifp->pend_8021x_cnt); + atomic_inc(&drvr->pend_8021x_cnt); /* If the protocol uses a data header, apply it */ - brcmf_proto_hdrpush(drvr, ifp->ifidx, skb); + brcmf_proto_hdrpush(drvr, ifp->idx, skb); /* Use bus module to send data frame */ ret = brcmf_bus_txdata(drvr->bus_if, skb); done: - if (ret) { - ifp->stats.tx_dropped++; - } else { - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += skb->len; - } + if (ret) + drvr->bus_if->dstats.tx_dropped++; + else + drvr->bus_if->dstats.tx_packets++; /* Return ok: we always eat the packet */ return NETDEV_TX_OK; @@ -282,13 +270,12 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) skb_queue_walk_safe(skb_list, skb, pnext) { skb_unlink(skb, skb_list); - /* process and remove protocol-specific header */ + /* process and remove protocol-specific header + */ ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); - ifp = drvr->iflist[ifidx]; - - if (ret || !ifp || !ifp->ndev) { - if ((ret != -ENODATA) && ifp) - ifp->stats.rx_errors++; + if (ret < 0) { + if (ret != -ENODATA) + bus_if->dstats.rx_errors++; brcmu_pkt_buf_free_skb(skb); continue; } @@ -308,11 +295,21 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) eth = skb->data; len = skb->len; + ifp = drvr->iflist[ifidx]; + if (ifp == NULL) + ifp = drvr->iflist[0]; + + if (!ifp || !ifp->ndev || + ifp->ndev->reg_state != NETREG_REGISTERED) { + brcmu_pkt_buf_free_skb(skb); + continue; + } + skb->dev = ifp->ndev; skb->protocol = eth_type_trans(skb, skb->dev); if (skb->pkt_type == PACKET_MULTICAST) - ifp->stats.multicast++; + bus_if->dstats.multicast++; skb->data = eth; skb->len = len; @@ -328,13 +325,8 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) ifp->ndev->last_rx = jiffies; } - if (!(ifp->ndev->flags & IFF_UP)) { - brcmu_pkt_buf_free_skb(skb); - continue; - } - - ifp->stats.rx_bytes += skb->len; - ifp->stats.rx_packets++; + bus_if->dstats.rx_bytes += skb->len; + bus_if->dstats.rx_packets++; /* Local count */ if (in_interrupt()) netif_rx(skb); @@ -356,31 +348,36 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) u16 type; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; - struct brcmf_if *ifp; brcmf_proto_hdrpull(drvr, &ifidx, txp); - ifp = drvr->iflist[ifidx]; - if (!ifp) - return; - eh = (struct ethhdr *)(txp->data); type = ntohs(eh->h_proto); if (type == ETH_P_PAE) { - atomic_dec(&ifp->pend_8021x_cnt); - if (waitqueue_active(&ifp->pend_8021x_wait)) - wake_up(&ifp->pend_8021x_wait); + atomic_dec(&drvr->pend_8021x_cnt); + if (waitqueue_active(&drvr->pend_8021x_wait)) + wake_up(&drvr->pend_8021x_wait); } - if (!success) - ifp->stats.tx_errors++; } static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_bus *bus_if = ifp->drvr->bus_if; + + brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + /* Copy dongle stats to net device stats */ + ifp->stats.rx_packets = bus_if->dstats.rx_packets; + ifp->stats.tx_packets = bus_if->dstats.tx_packets; + ifp->stats.rx_bytes = bus_if->dstats.rx_bytes; + ifp->stats.tx_bytes = bus_if->dstats.tx_bytes; + ifp->stats.rx_errors = bus_if->dstats.rx_errors; + ifp->stats.tx_errors = bus_if->dstats.tx_errors; + ifp->stats.rx_dropped = bus_if->dstats.rx_dropped; + ifp->stats.tx_dropped = bus_if->dstats.tx_dropped; + ifp->stats.multicast = bus_if->dstats.multicast; return &ifp->stats; } @@ -432,7 +429,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) u32 toe_cmpnt, csum_dir; int ret; - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + brcmf_dbg(TRACE, "Enter\n"); /* all ethtool calls start with a cmd word */ if (copy_from_user(&cmd, uaddr, sizeof(u32))) @@ -455,7 +452,13 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) sprintf(info.driver, "dhd"); strcpy(info.version, BRCMF_VERSION_STR); } - /* report dongle driver type */ + + /* otherwise, require dongle to be up */ + else if (!drvr->bus_if->drvr_up) { + brcmf_err("dongle is not up\n"); + return -ENODEV; + } + /* finally, report dongle driver type */ else sprintf(info.driver, "wl"); @@ -529,9 +532,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); + brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); - if (!drvr->iflist[ifp->bssidx]) + if (!drvr->iflist[ifp->idx]) return -1; if (cmd == SIOCETHTOOL) @@ -543,12 +546,17 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, static int brcmf_netdev_stop(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; + + brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + if (drvr->bus_if->drvr_up == 0) + return 0; brcmf_cfg80211_down(ndev); /* Set state and stop OS transmissions */ + drvr->bus_if->drvr_up = false; netif_stop_queue(ndev); return 0; @@ -562,7 +570,7 @@ static int brcmf_netdev_open(struct net_device *ndev) u32 toe_ol; s32 ret = 0; - brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); + brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); /* If bus is not ready, can't continue */ if (bus_if->state != BRCMF_BUS_DATA) { @@ -570,7 +578,9 @@ static int brcmf_netdev_open(struct net_device *ndev) return -EAGAIN; } - atomic_set(&ifp->pend_8021x_cnt, 0); + atomic_set(&drvr->pend_8021x_cnt, 0); + + memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); /* Get current TOE mode from dongle */ if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 @@ -581,6 +591,7 @@ static int brcmf_netdev_open(struct net_device *ndev) /* Allow transmit calls */ netif_start_queue(ndev); + drvr->bus_if->drvr_up = true; if (brcmf_cfg80211_up(ndev)) { brcmf_err("failed to bring up cfg80211\n"); return -1; @@ -599,18 +610,29 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { .ndo_set_rx_mode = brcmf_netdev_set_multicast_list }; -int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) +static const struct net_device_ops brcmf_netdev_ops_virt = { + .ndo_open = brcmf_cfg80211_up, + .ndo_stop = brcmf_cfg80211_down, + .ndo_get_stats = brcmf_netdev_get_stats, + .ndo_do_ioctl = brcmf_netdev_ioctl_entry, + .ndo_start_xmit = brcmf_netdev_start_xmit, + .ndo_set_mac_address = brcmf_netdev_set_mac_address, + .ndo_set_rx_mode = brcmf_netdev_set_multicast_list +}; + +int brcmf_net_attach(struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; struct net_device *ndev; - s32 err; - brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, - ifp->mac_addr); + brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); ndev = ifp->ndev; /* set appropriate operations */ - ndev->netdev_ops = &brcmf_netdev_ops_pri; + if (!ifp->idx) + ndev->netdev_ops = &brcmf_netdev_ops_pri; + else + ndev->netdev_ops = &brcmf_netdev_ops_virt; ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; ndev->ethtool_ops = &brcmf_ethtool_ops; @@ -621,14 +643,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) /* set the mac address */ memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); - INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); - INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); - - if (rtnl_locked) - err = register_netdevice(ndev); - else - err = register_netdev(ndev); - if (err != 0) { + if (register_netdev(ndev) != 0) { brcmf_err("couldn't register the net device\n"); goto fail; } @@ -642,78 +657,16 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) return -EBADE; } -static int brcmf_net_p2p_open(struct net_device *ndev) -{ - brcmf_dbg(TRACE, "Enter\n"); - - return brcmf_cfg80211_up(ndev); -} - -static int brcmf_net_p2p_stop(struct net_device *ndev) -{ - brcmf_dbg(TRACE, "Enter\n"); - - return brcmf_cfg80211_down(ndev); -} - -static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, - struct ifreq *ifr, int cmd) -{ - brcmf_dbg(TRACE, "Enter\n"); - return 0; -} - -static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb, - struct net_device *ndev) -{ - if (skb) - dev_kfree_skb_any(skb); - - return NETDEV_TX_OK; -} - -static const struct net_device_ops brcmf_netdev_ops_p2p = { - .ndo_open = brcmf_net_p2p_open, - .ndo_stop = brcmf_net_p2p_stop, - .ndo_do_ioctl = brcmf_net_p2p_do_ioctl, - .ndo_start_xmit = brcmf_net_p2p_start_xmit -}; - -static int brcmf_net_p2p_attach(struct brcmf_if *ifp) -{ - struct net_device *ndev; - - brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, - ifp->mac_addr); - ndev = ifp->ndev; - - ndev->netdev_ops = &brcmf_netdev_ops_p2p; - - /* set the mac address */ - memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); - - if (register_netdev(ndev) != 0) { - brcmf_err("couldn't register the p2p net device\n"); - goto fail; - } - - brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); - - return 0; - -fail: - return -EBADE; -} - -struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, - char *name, u8 *mac_addr) +struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, + char *name, u8 *addr_mask) { struct brcmf_if *ifp; struct net_device *ndev; + int i; - brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx); + brcmf_dbg(TRACE, "idx %d\n", ifidx); - ifp = drvr->iflist[bssidx]; + ifp = drvr->iflist[ifidx]; /* * Delete the existing interface before overwriting it * in case we missed the BRCMF_E_IF_DEL event. @@ -725,7 +678,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, netif_stop_queue(ifp->ndev); unregister_netdev(ifp->ndev); free_netdev(ifp->ndev); - drvr->iflist[bssidx] = NULL; + drvr->iflist[ifidx] = NULL; } else { brcmf_err("ignore IF event\n"); return ERR_PTR(-EINVAL); @@ -742,15 +695,16 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, ifp = netdev_priv(ndev); ifp->ndev = ndev; ifp->drvr = drvr; - drvr->iflist[bssidx] = ifp; - ifp->ifidx = ifidx; + drvr->iflist[ifidx] = ifp; + ifp->idx = ifidx; ifp->bssidx = bssidx; + INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); + INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); - init_waitqueue_head(&ifp->pend_8021x_wait); - - if (mac_addr != NULL) - memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); + if (addr_mask != NULL) + for (i = 0; i < ETH_ALEN; i++) + ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", current->pid, ifp->ndev->name, ifp->mac_addr); @@ -758,18 +712,19 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, return ifp; } -void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) +void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) { struct brcmf_if *ifp; - ifp = drvr->iflist[bssidx]; + brcmf_dbg(TRACE, "idx %d\n", ifidx); + + ifp = drvr->iflist[ifidx]; if (!ifp) { - brcmf_err("Null interface, idx=%d\n", bssidx); + brcmf_err("Null interface\n"); return; } - brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx); if (ifp->ndev) { - if (bssidx == 0) { + if (ifidx == 0) { if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { rtnl_lock(); brcmf_netdev_stop(ifp->ndev); @@ -779,14 +734,12 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) netif_stop_queue(ifp->ndev); } - if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { - cancel_work_sync(&ifp->setmacaddr_work); - cancel_work_sync(&ifp->multicast_work); - } + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); unregister_netdev(ifp->ndev); - drvr->iflist[bssidx] = NULL; - if (bssidx == 0) + drvr->iflist[ifidx] = NULL; + if (ifidx == 0) brcmf_cfg80211_detach(drvr->config); free_netdev(ifp->ndev); } @@ -826,6 +779,8 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); + init_waitqueue_head(&drvr->pend_8021x_wait); + return ret; fail: @@ -840,7 +795,6 @@ int brcmf_bus_start(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_if *ifp; - struct brcmf_if *p2p_ifp; brcmf_dbg(TRACE, "\n"); @@ -856,13 +810,6 @@ int brcmf_bus_start(struct device *dev) if (IS_ERR(ifp)) return PTR_ERR(ifp); - if (brcmf_p2p_enable) - p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); - else - p2p_ifp = NULL; - if (IS_ERR(p2p_ifp)) - p2p_ifp = NULL; - /* signal bus ready */ bus_if->state = BRCMF_BUS_DATA; @@ -881,22 +828,16 @@ int brcmf_bus_start(struct device *dev) if (ret < 0) goto fail; - ret = brcmf_net_attach(ifp, false); + ret = brcmf_net_attach(ifp); fail: if (ret < 0) { brcmf_err("failed: %d\n", ret); if (drvr->config) brcmf_cfg80211_detach(drvr->config); - free_netdev(ifp->ndev); + free_netdev(drvr->iflist[0]->ndev); drvr->iflist[0] = NULL; - if (p2p_ifp) { - free_netdev(p2p_ifp->ndev); - drvr->iflist[1] = NULL; - } return ret; } - if ((brcmf_p2p_enable) && (p2p_ifp)) - brcmf_net_p2p_attach(p2p_ifp); return 0; } @@ -922,13 +863,12 @@ void brcmf_dev_reset(struct device *dev) if (drvr == NULL) return; - if (drvr->iflist[0]) - brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); + brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); } void brcmf_detach(struct device *dev) { - s32 i; + int i; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; @@ -955,18 +895,19 @@ void brcmf_detach(struct device *dev) kfree(drvr); } -static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) +static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr) { - return atomic_read(&ifp->pend_8021x_cnt); + return atomic_read(&drvr->pend_8021x_cnt); } int brcmf_netdev_wait_pend8021x(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; int err; - err = wait_event_timeout(ifp->pend_8021x_wait, - !brcmf_get_pend_8021x_cnt(ifp), + err = wait_event_timeout(drvr->pend_8021x_wait, + !brcmf_get_pend_8021x_cnt(drvr), msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); WARN_ON(!err); @@ -974,16 +915,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) return !err; } -/* - * return chip id and rev of the device encoded in u32. - */ -u32 brcmf_get_chip_info(struct brcmf_if *ifp) -{ - struct brcmf_bus *bus = ifp->drvr->bus_if; - - return bus->chip << 4 | bus->chiprev; -} - static void brcmf_driver_init(struct work_struct *work) { brcmf_debugfs_init(); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 35817631ea06..7fef9b5ba003 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -1096,6 +1096,7 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && type != BRCMF_SDIO_FT_SUPER) { brcmf_err("HW header length too long\n"); + bus->sdiodev->bus_if->dstats.rx_errors++; bus->sdcnt.rx_toolong++; brcmf_sdbrcm_rxfail(bus, false, false); rd->len = 0; @@ -1297,6 +1298,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) if (errcode < 0) { brcmf_err("glom read of %d bytes failed: %d\n", dlen, errcode); + bus->sdiodev->bus_if->dstats.rx_errors++; sdio_claim_host(bus->sdiodev->func[1]); if (bus->glomerr++ < 3) { @@ -1476,6 +1478,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { brcmf_err("%d-byte control read exceeds %d-byte buffer\n", rdlen, bus->sdiodev->bus_if->maxctl); + bus->sdiodev->bus_if->dstats.rx_errors++; brcmf_sdbrcm_rxfail(bus, false, false); goto done; } @@ -1483,6 +1486,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) if ((len - doff) > bus->sdiodev->bus_if->maxctl) { brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", len, len - doff, bus->sdiodev->bus_if->maxctl); + bus->sdiodev->bus_if->dstats.rx_errors++; bus->sdcnt.rx_toolong++; brcmf_sdbrcm_rxfail(bus, false, false); goto done; @@ -1630,6 +1634,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) if (!pkt) { /* Give up on data, request rtx of events */ brcmf_err("brcmu_pkt_buf_get_skb failed\n"); + bus->sdiodev->bus_if->dstats.rx_dropped++; brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(rd->channel)); sdio_release_host(bus->sdiodev->func[1]); @@ -1647,6 +1652,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) brcmf_err("read %d bytes from channel %d failed: %d\n", rd->len, rd->channel, sdret); brcmu_pkt_buf_free_skb(pkt); + bus->sdiodev->bus_if->dstats.rx_errors++; sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(rd->channel)); @@ -1934,6 +1940,10 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) datalen = pkt->len - SDPCM_HDRLEN; ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); + if (ret) + bus->sdiodev->bus_if->dstats.tx_errors++; + else + bus->sdiodev->bus_if->dstats.tx_bytes += datalen; /* In poll mode, need to check for other events */ if (!bus->intr && cnt) { @@ -1952,7 +1962,8 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) } /* Deflow-control stack if needed */ - if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && + if (bus->sdiodev->bus_if->drvr_up && + (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { bus->txoff = false; brcmf_txflowblock(bus->sdiodev->dev, false); @@ -2699,10 +2710,9 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, * address of sdpcm_shared structure */ sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); rv = brcmf_sdbrcm_membytes(bus, false, shaddr, (u8 *)&addr_le, 4); - sdio_release_host(bus->sdiodev->func[1]); + sdio_claim_host(bus->sdiodev->func[1]); if (rv < 0) return rv; @@ -2721,8 +2731,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, } /* Read hndrte_shared structure */ + sdio_claim_host(bus->sdiodev->func[1]); rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, sizeof(struct sdpcm_shared_le)); + sdio_release_host(bus->sdiodev->func[1]); if (rv < 0) return rv; @@ -2824,12 +2836,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, if ((sh->flags & SDPCM_SHARED_TRAP) == 0) return 0; + sdio_claim_host(bus->sdiodev->func[1]); error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, sizeof(struct brcmf_trap_info)); if (error < 0) return error; nbytes = brcmf_sdio_dump_console(bus, sh, data, count); + sdio_release_host(bus->sdiodev->func[1]); if (nbytes < 0) return nbytes; @@ -3294,6 +3308,9 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) { int ret; + if (bus->sdiodev->bus_if->drvr_up) + return -EISCONN; + ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, &bus->sdiodev->func[2]->dev); if (ret) { @@ -3924,8 +3941,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) /* Assign bus interface call back */ bus->sdiodev->bus_if->dev = bus->sdiodev->dev; bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; - bus->sdiodev->bus_if->chip = bus->ci->chip; - bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; /* Attach to the brcmf/OS/network interface */ ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index e9d6f91a1f2b..ba0b22512f12 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, return; } - ifp = drvr->iflist[ifevent->bssidx]; + ifp = drvr->iflist[ifevent->ifidx]; if (ifevent->action == BRCMF_E_IF_ADD) { brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, emsg->addr); - ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, + ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, emsg->ifname, emsg->addr); if (IS_ERR(ifp)) return; if (!drvr->fweh.evt_handler[BRCMF_E_IF]) - err = brcmf_net_attach(ifp, false); + err = brcmf_net_attach(ifp); } err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); if (ifevent->action == BRCMF_E_IF_DEL) - brcmf_del_if(drvr, ifevent->bssidx); + brcmf_del_if(drvr, ifevent->ifidx); } /** @@ -250,6 +250,8 @@ static void brcmf_fweh_event_worker(struct work_struct *work) drvr = container_of(fweh, struct brcmf_pub, fweh); while ((event = brcmf_fweh_dequeue_event(fweh))) { + ifp = drvr->iflist[event->ifidx]; + brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", brcmf_fweh_event_name(event->code), event->code, event->emsg.ifidx, event->emsg.bsscfgidx, @@ -281,7 +283,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work) goto event_free; } - ifp = drvr->iflist[emsg.bsscfgidx]; err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, event->data); if (err) { diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index 8c39b51dcccf..36901f76a3b5 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -83,7 +83,6 @@ struct brcmf_event; BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ BRCMF_ENUM_DEF(TRACE, 52) \ BRCMF_ENUM_DEF(IF, 54) \ - BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ BRCMF_ENUM_DEF(RSSI, 56) \ BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ @@ -97,11 +96,8 @@ struct brcmf_event; BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ - BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \ - BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \ BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ - BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ - BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) + BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) #define BRCMF_ENUM_DEF(id, val) \ BRCMF_E_##id = (val), diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 8d1def935b8d..d8d8b6549dc5 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -45,10 +45,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) if (data != NULL) len = min_t(uint, len, BRCMF_DCMD_MAXLEN); if (set) - err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data, - len); + err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len); else - err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, + err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data, len); if (err >= 0) @@ -101,7 +100,6 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) __le32 data_le = cpu_to_le32(data); mutex_lock(&ifp->drvr->proto_block); - brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data); err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); mutex_unlock(&ifp->drvr->proto_block); @@ -118,7 +116,6 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); mutex_unlock(&ifp->drvr->proto_block); *data = le32_to_cpu(data_le); - brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data); return err; } diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h deleted file mode 100644 index 0f2c83bc95dc..000000000000 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2012 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - - -#ifndef FWIL_TYPES_H_ -#define FWIL_TYPES_H_ - -#include - - -#define BRCMF_FIL_ACTION_FRAME_SIZE 1800 - - -enum brcmf_fil_p2p_if_types { - BRCMF_FIL_P2P_IF_CLIENT, - BRCMF_FIL_P2P_IF_GO, - BRCMF_FIL_P2P_IF_DYNBCN_GO, - BRCMF_FIL_P2P_IF_DEV, -}; - -struct brcmf_fil_p2p_if_le { - u8 addr[ETH_ALEN]; - __le16 type; - __le16 chspec; -}; - -struct brcmf_fil_chan_info_le { - __le32 hw_channel; - __le32 target_channel; - __le32 scan_channel; -}; - -struct brcmf_fil_action_frame_le { - u8 da[ETH_ALEN]; - __le16 len; - __le32 packet_id; - u8 data[BRCMF_FIL_ACTION_FRAME_SIZE]; -}; - -struct brcmf_fil_af_params_le { - __le32 channel; - __le32 dwell_time; - u8 bssid[ETH_ALEN]; - u8 pad[2]; - struct brcmf_fil_action_frame_le action_frame; -}; - -struct brcmf_fil_bss_enable_le { - __le32 bsscfg_idx; - __le32 enable; -}; - -#endif /* FWIL_TYPES_H_ */ diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/p2p.c deleted file mode 100644 index 4166e642068b..000000000000 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ /dev/null @@ -1,2277 +0,0 @@ -/* - * Copyright (c) 2012 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include "fwil.h" -#include "fwil_types.h" -#include "p2p.h" -#include "wl_cfg80211.h" - -/* parameters used for p2p escan */ -#define P2PAPI_SCAN_NPROBES 1 -#define P2PAPI_SCAN_DWELL_TIME_MS 80 -#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 -#define P2PAPI_SCAN_HOME_TIME_MS 60 -#define P2PAPI_SCAN_NPROBS_TIME_MS 30 -#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 -#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 -#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 - -#define BRCMF_P2P_WILDCARD_SSID "DIRECT-" -#define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1) - -#define SOCIAL_CHAN_1 1 -#define SOCIAL_CHAN_2 6 -#define SOCIAL_CHAN_3 11 -#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ - (channel == SOCIAL_CHAN_2) || \ - (channel == SOCIAL_CHAN_3)) -#define SOCIAL_CHAN_CNT 3 -#define AF_PEER_SEARCH_CNT 2 - -#define BRCMF_SCB_TIMEOUT_VALUE 20 - -#define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */ -#define P2P_PUB_AF_CATEGORY 0x04 -#define P2P_PUB_AF_ACTION 0x09 -#define P2P_AF_CATEGORY 0x7f -#define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */ -#define P2P_OUI_LEN 3 /* P2P OUI length */ - -/* Action Frame Constants */ -#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action */ -#define DOT11_ACTION_CAT_OFF 0 /* category offset */ -#define DOT11_ACTION_ACT_OFF 1 /* action offset */ - -#define P2P_AF_DWELL_TIME 200 -#define P2P_AF_MIN_DWELL_TIME 100 -#define P2P_AF_MED_DWELL_TIME 400 -#define P2P_AF_LONG_DWELL_TIME 1000 -#define P2P_AF_TX_MAX_RETRY 1 -#define P2P_AF_MAX_WAIT_TIME 2000 -#define P2P_INVALID_CHANNEL -1 -#define P2P_CHANNEL_SYNC_RETRY 5 -#define P2P_AF_FRM_SCAN_MAX_WAIT 1500 -#define P2P_DEFAULT_SLEEP_TIME_VSDB 200 - -/* WiFi P2P Public Action Frame OUI Subtypes */ -#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ -#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ -#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ -#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ -#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ -#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ -#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ -#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ -#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ -#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ - -/* WiFi P2P Action Frame OUI Subtypes */ -#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ -#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ -#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ -#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ - -/* P2P Service Discovery related */ -#define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */ -#define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */ -#define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */ -#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */ -#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */ - -/** - * struct brcmf_p2p_disc_st_le - set discovery state in firmware. - * - * @state: requested discovery state (see enum brcmf_p2p_disc_state). - * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state. - * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state. - */ -struct brcmf_p2p_disc_st_le { - u8 state; - __le16 chspec; - __le16 dwell; -}; - -/** - * enum brcmf_p2p_disc_state - P2P discovery state values - * - * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE. - * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time. - * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE. - */ -enum brcmf_p2p_disc_state { - WL_P2P_DISC_ST_SCAN, - WL_P2P_DISC_ST_LISTEN, - WL_P2P_DISC_ST_SEARCH -}; - -/** - * struct brcmf_p2p_scan_le - P2P specific scan request. - * - * @type: type of scan method requested (values: 'E' or 'S'). - * @reserved: reserved (ignored). - * @eparams: parameters used for type 'E'. - * @sparams: parameters used for type 'S'. - */ -struct brcmf_p2p_scan_le { - u8 type; - u8 reserved[3]; - union { - struct brcmf_escan_params_le eparams; - struct brcmf_scan_params_le sparams; - }; -}; - -/** - * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame - * - * @category: P2P_PUB_AF_CATEGORY - * @action: P2P_PUB_AF_ACTION - * @oui[3]: P2P_OUI - * @oui_type: OUI type - P2P_VER - * @subtype: OUI subtype - P2P_TYPE_* - * @dialog_token: nonzero, identifies req/rsp transaction - * @elts[1]: Variable length information elements. - */ -struct brcmf_p2p_pub_act_frame { - u8 category; - u8 action; - u8 oui[3]; - u8 oui_type; - u8 subtype; - u8 dialog_token; - u8 elts[1]; -}; - -/** - * struct brcmf_p2p_action_frame - WiFi P2P Action Frame - * - * @category: P2P_AF_CATEGORY - * @OUI[3]: OUI - P2P_OUI - * @type: OUI Type - P2P_VER - * @subtype: OUI Subtype - P2P_AF_* - * @dialog_token: nonzero, identifies req/resp tranaction - * @elts[1]: Variable length information elements. - */ -struct brcmf_p2p_action_frame { - u8 category; - u8 oui[3]; - u8 type; - u8 subtype; - u8 dialog_token; - u8 elts[1]; -}; - -/** - * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame - * - * @category: 0x04 Public Action Frame - * @action: 0x6c Advertisement Protocol - * @dialog_token: nonzero, identifies req/rsp transaction - * @query_data[1]: Query Data. SD gas ireq SD gas iresp - */ -struct brcmf_p2psd_gas_pub_act_frame { - u8 category; - u8 action; - u8 dialog_token; - u8 query_data[1]; -}; - -/** - * struct brcmf_config_af_params - Action Frame Parameters for tx. - * - * @mpc_onoff: To make sure to send successfully action frame, we have to - * turn off mpc 0: off, 1: on, (-1): do nothing - * @search_channel: 1: search peer's channel to send af - * extra_listen: keep the dwell time to get af response frame. - */ -struct brcmf_config_af_params { - s32 mpc_onoff; - bool search_channel; - bool extra_listen; -}; - -/** - * brcmf_p2p_is_pub_action() - true if p2p public type frame. - * - * @frame: action frame data. - * @frame_len: length of action frame data. - * - * Determine if action frame is p2p public action type - */ -static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len) -{ - struct brcmf_p2p_pub_act_frame *pact_frm; - - if (frame == NULL) - return false; - - pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; - if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1) - return false; - - if (pact_frm->category == P2P_PUB_AF_CATEGORY && - pact_frm->action == P2P_PUB_AF_ACTION && - pact_frm->oui_type == P2P_VER && - memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) - return true; - - return false; -} - -/** - * brcmf_p2p_is_p2p_action() - true if p2p action type frame. - * - * @frame: action frame data. - * @frame_len: length of action frame data. - * - * Determine if action frame is p2p action type - */ -static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len) -{ - struct brcmf_p2p_action_frame *act_frm; - - if (frame == NULL) - return false; - - act_frm = (struct brcmf_p2p_action_frame *)frame; - if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1) - return false; - - if (act_frm->category == P2P_AF_CATEGORY && - act_frm->type == P2P_VER && - memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) - return true; - - return false; -} - -/** - * brcmf_p2p_is_gas_action() - true if p2p gas action type frame. - * - * @frame: action frame data. - * @frame_len: length of action frame data. - * - * Determine if action frame is p2p gas action type - */ -static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len) -{ - struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; - - if (frame == NULL) - return false; - - sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; - if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1) - return false; - - if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) - return false; - - if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) - return true; - - return false; -} - -/** - * brcmf_p2p_print_actframe() - debug print routine. - * - * @tx: Received or to be transmitted - * @frame: action frame data. - * @frame_len: length of action frame data. - * - * Print information about the p2p action frame - */ - -#ifdef DEBUG - -static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) -{ - struct brcmf_p2p_pub_act_frame *pact_frm; - struct brcmf_p2p_action_frame *act_frm; - struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; - - if (!frame || frame_len <= 2) - return; - - if (brcmf_p2p_is_pub_action(frame, frame_len)) { - pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; - switch (pact_frm->subtype) { - case P2P_PAF_GON_REQ: - brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_GON_RSP: - brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_GON_CONF: - brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_INVITE_REQ: - brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_INVITE_RSP: - brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_DEVDIS_REQ: - brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_DEVDIS_RSP: - brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_PROVDIS_REQ: - brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_PAF_PROVDIS_RSP: - brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n", - (tx) ? "TX" : "RX"); - break; - default: - brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n", - (tx) ? "TX" : "RX"); - break; - } - } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) { - act_frm = (struct brcmf_p2p_action_frame *)frame; - switch (act_frm->subtype) { - case P2P_AF_NOTICE_OF_ABSENCE: - brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_AF_PRESENCE_REQ: - brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_AF_PRESENCE_RSP: - brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n", - (tx) ? "TX" : "RX"); - break; - case P2P_AF_GO_DISC_REQ: - brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n", - (tx) ? "TX" : "RX"); - break; - default: - brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n", - (tx) ? "TX" : "RX"); - } - - } else if (brcmf_p2p_is_gas_action(frame, frame_len)) { - sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; - switch (sd_act_frm->action) { - case P2PSD_ACTION_ID_GAS_IREQ: - brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n", - (tx) ? "TX" : "RX"); - break; - case P2PSD_ACTION_ID_GAS_IRESP: - brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n", - (tx) ? "TX" : "RX"); - break; - case P2PSD_ACTION_ID_GAS_CREQ: - brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n", - (tx) ? "TX" : "RX"); - break; - case P2PSD_ACTION_ID_GAS_CRESP: - brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n", - (tx) ? "TX" : "RX"); - break; - default: - brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n", - (tx) ? "TX" : "RX"); - break; - } - } -} - -#else - -static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) -{ -} - -#endif - - -/** - * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec. - * - * @channel: channel number - */ -static u16 brcmf_p2p_chnr_to_chspec(u16 channel) -{ - u16 chanspec; - - chanspec = channel & WL_CHANSPEC_CHAN_MASK; - - if (channel <= CH_MAX_2G_CHANNEL) - chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; - - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - return chanspec; -} - - -/** - * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation. - * - * @ifp: ifp to use for iovars (primary). - * @p2p_mac: mac address to configure for p2p_da_override - */ -static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) -{ - s32 ret = 0; - - brcmf_fil_iovar_int_set(ifp, "apsta", 1); - - /* In case of COB type, firmware has default mac address - * After Initializing firmware, we have to set current mac address to - * firmware for P2P device address - */ - ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac, - ETH_ALEN); - if (ret) - brcmf_err("failed to update device address ret %d\n", ret); - - return ret; -} - -/** - * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P. - * - * @p2p: P2P specific data. - * - * P2P needs mac addresses for P2P device and interface. These are - * derived from the primary net device, ie. the permanent ethernet - * address of the device. - */ -static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p) -{ - struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; - - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. - */ - memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN); - p2p->dev_addr[0] |= 0x02; - memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); - - /* Generate the P2P Interface Address. If the discovery and connection - * BSSCFGs need to simultaneously co-exist, then this address must be - * different from the P2P Device Address, but also locally administered. - */ - memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN); - p2p->int_addr[4] ^= 0x80; -} - -/** - * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan. - * - * @request: the scan request as received from cfg80211. - * - * returns true if one of the ssids in the request matches the - * P2P wildcard ssid; otherwise returns false. - */ -static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request) -{ - struct cfg80211_ssid *ssids = request->ssids; - int i; - - for (i = 0; i < request->n_ssids; i++) { - if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN) - continue; - - brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid); - if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid, - BRCMF_P2P_WILDCARD_SSID_LEN)) - return true; - } - return false; -} - -/** - * brcmf_p2p_set_discover_state - set discover state in firmware. - * - * @ifp: low-level interface object. - * @state: discover state to set. - * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only). - * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only). - */ -static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state, - u16 chanspec, u16 listen_ms) -{ - struct brcmf_p2p_disc_st_le discover_state; - s32 ret = 0; - brcmf_dbg(TRACE, "enter\n"); - - discover_state.state = state; - discover_state.chspec = cpu_to_le16(chanspec); - discover_state.dwell = cpu_to_le16(listen_ms); - ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state, - sizeof(discover_state)); - return ret; -} - -/** - * brcmf_p2p_deinit_discovery() - disable P2P device discovery. - * - * @p2p: P2P specific data. - * - * Resets the discovery state and disables it in firmware. - */ -static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) -{ - struct brcmf_cfg80211_vif *vif; - - brcmf_dbg(TRACE, "enter\n"); - - /* Set the discovery state to SCAN */ - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); - - /* Disable P2P discovery in the firmware */ - vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - (void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0); - - return 0; -} - -/** - * brcmf_p2p_enable_discovery() - initialize and configure discovery. - * - * @p2p: P2P specific data. - * - * Initializes the discovery device and configure the virtual interface. - */ -static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) -{ - struct brcmf_cfg80211_vif *vif; - s32 ret = 0; - - brcmf_dbg(TRACE, "enter\n"); - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - if (!vif) { - brcmf_err("P2P config device not available\n"); - ret = -EPERM; - goto exit; - } - - if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) { - brcmf_dbg(INFO, "P2P config device already configured\n"); - goto exit; - } - - /* Re-initialize P2P Discovery in the firmware */ - vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1); - if (ret < 0) { - brcmf_err("set p2p_disc error\n"); - goto exit; - } - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); - if (ret < 0) { - brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n"); - goto exit; - } - - /* - * Set wsec to any non-zero value in the discovery bsscfg - * to ensure our P2P probe responses have the privacy bit - * set in the 802.11 WPA IE. Some peer devices may not - * initiate WPS with us if this bit is not set. - */ - ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED); - if (ret < 0) { - brcmf_err("wsec error %d\n", ret); - goto exit; - } - - set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status); -exit: - return ret; -} - -/** - * brcmf_p2p_escan() - initiate a P2P scan. - * - * @p2p: P2P specific data. - * @num_chans: number of channels to scan. - * @chanspecs: channel parameters for @num_chans channels. - * @search_state: P2P discover state to use. - * @action: scan action to pass to firmware. - * @bss_type: type of P2P bss. - */ -static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, - u16 chanspecs[], s32 search_state, u16 action, - enum p2p_bss_type bss_type) -{ - s32 ret = 0; - s32 memsize = offsetof(struct brcmf_p2p_scan_le, - eparams.params_le.channel_list); - s32 nprobes; - s32 active; - u32 i; - u8 *memblk; - struct brcmf_cfg80211_vif *vif; - struct brcmf_p2p_scan_le *p2p_params; - struct brcmf_scan_params_le *sparams; - struct brcmf_ssid ssid; - - memsize += num_chans * sizeof(__le16); - memblk = kzalloc(memsize, GFP_KERNEL); - if (!memblk) - return -ENOMEM; - - vif = p2p->bss_idx[bss_type].vif; - if (vif == NULL) { - brcmf_err("no vif for bss type %d\n", bss_type); - ret = -EINVAL; - goto exit; - } - - switch (search_state) { - case WL_P2P_DISC_ST_SEARCH: - /* - * If we in SEARCH STATE, we don't need to set SSID explictly - * because dongle use P2P WILDCARD internally by default - */ - /* use null ssid */ - ssid.SSID_len = 0; - memset(ssid.SSID, 0, sizeof(ssid.SSID)); - break; - case WL_P2P_DISC_ST_SCAN: - /* - * wpa_supplicant has p2p_find command with type social or - * progressive. For progressive, we need to set the ssid to - * P2P WILDCARD because we just do broadcast scan unless - * setting SSID. - */ - ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN; - memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len); - break; - default: - brcmf_err(" invalid search state %d\n", search_state); - ret = -EINVAL; - goto exit; - } - - brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0); - - /* - * set p2p scan parameters. - */ - p2p_params = (struct brcmf_p2p_scan_le *)memblk; - p2p_params->type = 'E'; - - /* determine the scan engine parameters */ - sparams = &p2p_params->eparams.params_le; - sparams->bss_type = DOT11_BSSTYPE_ANY; - if (p2p->cfg->active_scan) - sparams->scan_type = 0; - else - sparams->scan_type = 1; - - memset(&sparams->bssid, 0xFF, ETH_ALEN); - if (ssid.SSID_len) - memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len); - sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); - sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS); - - /* - * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan - * supported by the supplicant. - */ - if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1)) - active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS; - else if (num_chans == AF_PEER_SEARCH_CNT) - active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS; - else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED)) - active = -1; - else - active = P2PAPI_SCAN_DWELL_TIME_MS; - - /* Override scan params to find a peer for a connection */ - if (num_chans == 1) { - active = WL_SCAN_CONNECT_DWELL_TIME_MS; - /* WAR to sync with presence period of VSDB GO. - * send probe request more frequently - */ - nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS; - } else { - nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS; - } - - if (nprobes <= 0) - nprobes = 1; - - brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active); - sparams->active_time = cpu_to_le32(active); - sparams->nprobes = cpu_to_le32(nprobes); - sparams->passive_time = cpu_to_le32(-1); - sparams->channel_num = cpu_to_le32(num_chans & - BRCMF_SCAN_PARAMS_COUNT_MASK); - for (i = 0; i < num_chans; i++) - sparams->channel_list[i] = cpu_to_le16(chanspecs[i]); - - /* set the escan specific parameters */ - p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); - p2p_params->eparams.action = cpu_to_le16(action); - p2p_params->eparams.sync_id = cpu_to_le16(0x1234); - /* perform p2p scan on primary device */ - ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize); - if (!ret) - set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status); -exit: - kfree(memblk); - return ret; -} - -/** - * brcmf_p2p_run_escan() - escan callback for peer-to-peer. - * - * @cfg: driver private data for cfg80211 interface. - * @ndev: net device for which scan is requested. - * @request: scan request from cfg80211. - * @action: scan action. - * - * Determines the P2P discovery state based to scan request parameters and - * validates the channels in the request. - */ -static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - struct cfg80211_scan_request *request, - u16 action) -{ - struct brcmf_p2p_info *p2p = &cfg->p2p; - s32 err = 0; - s32 search_state = WL_P2P_DISC_ST_SCAN; - struct brcmf_cfg80211_vif *vif; - struct net_device *dev = NULL; - int i, num_nodfs = 0; - u16 *chanspecs; - - brcmf_dbg(TRACE, "enter\n"); - - if (!request) { - err = -EINVAL; - goto exit; - } - - if (request->n_channels) { - chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs), - GFP_KERNEL); - if (!chanspecs) { - err = -ENOMEM; - goto exit; - } - vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; - if (vif) - dev = vif->wdev.netdev; - if (request->n_channels == 3 && - request->channels[0]->hw_value == SOCIAL_CHAN_1 && - request->channels[1]->hw_value == SOCIAL_CHAN_2 && - request->channels[2]->hw_value == SOCIAL_CHAN_3) { - /* SOCIAL CHANNELS 1, 6, 11 */ - search_state = WL_P2P_DISC_ST_SEARCH; - brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); - } else if (dev != NULL && vif->mode == WL_MODE_AP) { - /* If you are already a GO, then do SEARCH only */ - brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n"); - search_state = WL_P2P_DISC_ST_SEARCH; - } else { - brcmf_dbg(INFO, "P2P SCAN STATE START\n"); - } - - /* - * no P2P scanning on passive or DFS channels. - */ - for (i = 0; i < request->n_channels; i++) { - struct ieee80211_channel *chan = request->channels[i]; - - if (chan->flags & (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN)) - continue; - - chanspecs[i] = channel_to_chanspec(chan); - brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n", - num_nodfs, chan->hw_value, chanspecs[i]); - num_nodfs++; - } - err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state, - action, P2PAPI_BSSCFG_DEVICE); - } -exit: - if (err) - brcmf_err("error (%d)\n", err); - return err; -} - - -/** - * brcmf_p2p_find_listen_channel() - find listen channel in ie string. - * - * @ie: string of information elements. - * @ie_len: length of string. - * - * Scan ie for p2p ie and look for attribute 6 channel. If available determine - * channel and return it. - */ -static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len) -{ - u8 channel_ie[5]; - s32 listen_channel; - s32 err; - - err = cfg80211_get_p2p_attr(ie, ie_len, - IEEE80211_P2P_ATTR_LISTEN_CHANNEL, - channel_ie, sizeof(channel_ie)); - if (err < 0) - return err; - - /* listen channel subel length format: */ - /* 3(country) + 1(op. class) + 1(chan num) */ - listen_channel = (s32)channel_ie[3 + 1]; - - if (listen_channel == SOCIAL_CHAN_1 || - listen_channel == SOCIAL_CHAN_2 || - listen_channel == SOCIAL_CHAN_3) { - brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel); - return listen_channel; - } - - return -EPERM; -} - - -/** - * brcmf_p2p_scan_prep() - prepare scan based on request. - * - * @wiphy: wiphy device. - * @request: scan request from cfg80211. - * @vif: vif on which scan request is to be executed. - * - * Prepare the scan appropriately for type of scan requested. Overrides the - * escan .run() callback for peer-to-peer scanning. - */ -int brcmf_p2p_scan_prep(struct wiphy *wiphy, - struct cfg80211_scan_request *request, - struct brcmf_cfg80211_vif *vif) -{ - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_p2p_info *p2p = &cfg->p2p; - int err = 0; - - if (brcmf_p2p_scan_is_p2p_request(request)) { - /* find my listen channel */ - err = brcmf_p2p_find_listen_channel(request->ie, - request->ie_len); - if (err < 0) - return err; - - p2p->afx_hdl.my_listen_chan = err; - - clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); - brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); - - err = brcmf_p2p_enable_discovery(p2p); - if (err) - return err; - - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - - /* override .run_escan() callback. */ - cfg->escan_info.run = brcmf_p2p_run_escan; - } - err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG, - request->ie, request->ie_len); - return err; -} - - -/** - * brcmf_p2p_discover_listen() - set firmware to discover listen state. - * - * @p2p: p2p device. - * @channel: channel nr for discover listen. - * @duration: time in ms to stay on channel. - * - */ -static s32 -brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration) -{ - struct brcmf_cfg80211_vif *vif; - s32 err = 0; - u16 chanspec; - - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - if (!vif) { - brcmf_err("Discovery is not set, so we have nothing to do\n"); - err = -EPERM; - goto exit; - } - - if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) { - brcmf_err("Previous LISTEN is not completed yet\n"); - /* WAR: prevent cookie mismatch in wpa_supplicant return OK */ - goto exit; - } - - chanspec = brcmf_p2p_chnr_to_chspec(channel); - err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN, - chanspec, (u16)duration); - if (!err) { - set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status); - p2p->remain_on_channel_cookie++; - } -exit: - return err; -} - - -/** - * brcmf_p2p_remain_on_channel() - put device on channel and stay there. - * - * @wiphy: wiphy device. - * @channel: channel to stay on. - * @duration: time in ms to remain on channel. - * - */ -int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *channel, - unsigned int duration, u64 *cookie) -{ - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_p2p_info *p2p = &cfg->p2p; - s32 err; - u16 channel_nr; - - channel_nr = ieee80211_frequency_to_channel(channel->center_freq); - brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr, - duration); - - err = brcmf_p2p_enable_discovery(p2p); - if (err) - goto exit; - err = brcmf_p2p_discover_listen(p2p, channel_nr, duration); - if (err) - goto exit; - - memcpy(&p2p->remain_on_channel, channel, sizeof(*channel)); - *cookie = p2p->remain_on_channel_cookie; - cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL); - -exit: - return err; -} - - -/** - * brcmf_p2p_notify_listen_complete() - p2p listen has completed. - * - * @ifp: interfac control. - * @e: event message. Not used, to make it usable for fweh event dispatcher. - * @data: payload of message. Not used. - * - */ -int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct brcmf_p2p_info *p2p = &cfg->p2p; - - brcmf_dbg(TRACE, "Enter\n"); - if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, - &p2p->status)) { - if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, - &p2p->status)) { - clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, - &p2p->status); - brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n"); - complete(&p2p->wait_next_af); - } - - cfg80211_remain_on_channel_expired(&ifp->vif->wdev, - p2p->remain_on_channel_cookie, - &p2p->remain_on_channel, - GFP_KERNEL); - } - return 0; -} - - -/** - * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state. - * - * @ifp: interfac control. - * - */ -void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp) -{ - if (!ifp) - return; - brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0); - brcmf_p2p_notify_listen_complete(ifp, NULL, NULL); -} - - -/** - * brcmf_p2p_act_frm_search() - search function for action frame. - * - * @p2p: p2p device. - * channel: channel on which action frame is to be trasmitted. - * - * search function to reach at common channel to send action frame. When - * channel is 0 then all social channels will be used to send af - */ -static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel) -{ - s32 err; - u32 channel_cnt; - u16 *default_chan_list; - u32 i; - - brcmf_dbg(TRACE, "Enter\n"); - - if (channel) - channel_cnt = AF_PEER_SEARCH_CNT; - else - channel_cnt = SOCIAL_CHAN_CNT; - default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list), - GFP_KERNEL); - if (default_chan_list == NULL) { - brcmf_err("channel list allocation failed\n"); - err = -ENOMEM; - goto exit; - } - if (channel) { - /* insert same channel to the chan_list */ - for (i = 0; i < channel_cnt; i++) - default_chan_list[i] = - brcmf_p2p_chnr_to_chspec(channel); - } else { - default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1); - default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2); - default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3); - } - err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list, - WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START, - P2PAPI_BSSCFG_DEVICE); - kfree(default_chan_list); -exit: - return err; -} - - -/** - * brcmf_p2p_afx_handler() - afx worker thread. - * - * @work: - * - */ -static void brcmf_p2p_afx_handler(struct work_struct *work) -{ - struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work); - struct brcmf_p2p_info *p2p = container_of(afx_hdl, - struct brcmf_p2p_info, - afx_hdl); - s32 err; - - if (!afx_hdl->is_active) - return; - - if (afx_hdl->is_listen && afx_hdl->my_listen_chan) - /* 100ms ~ 300ms */ - err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan, - 100 * (1 + (random32() % 3))); - else - err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan); - - if (err) { - brcmf_err("ERROR occurred! value is (%d)\n", err); - if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, - &p2p->status)) - complete(&afx_hdl->act_frm_scan); - } -} - - -/** - * brcmf_p2p_af_searching_channel() - search channel. - * - * @p2p: p2p device info struct. - * - */ -static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) -{ - struct afx_hdl *afx_hdl = &p2p->afx_hdl; - struct brcmf_cfg80211_vif *pri_vif; - unsigned long duration; - s32 retry; - - brcmf_dbg(TRACE, "Enter\n"); - - pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - - INIT_COMPLETION(afx_hdl->act_frm_scan); - set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); - afx_hdl->is_active = true; - afx_hdl->peer_chan = P2P_INVALID_CHANNEL; - - /* Loop to wait until we find a peer's channel or the - * pending action frame tx is cancelled. - */ - retry = 0; - duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT); - while ((retry < P2P_CHANNEL_SYNC_RETRY) && - (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) { - afx_hdl->is_listen = false; - brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n", - retry); - /* search peer on peer's listen channel */ - schedule_work(&afx_hdl->afx_work); - wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration); - if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || - (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, - &p2p->status))) - break; - - if (afx_hdl->my_listen_chan) { - brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n", - afx_hdl->my_listen_chan); - /* listen on my listen channel */ - afx_hdl->is_listen = true; - schedule_work(&afx_hdl->afx_work); - wait_for_completion_timeout(&afx_hdl->act_frm_scan, - duration); - } - if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || - (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, - &p2p->status))) - break; - retry++; - - /* if sta is connected or connecting, sleep for a while before - * retry af tx or finding a peer - */ - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) || - test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state)) - msleep(P2P_DEFAULT_SLEEP_TIME_VSDB); - } - - brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n", - afx_hdl->peer_chan); - afx_hdl->is_active = false; - - clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); - - return afx_hdl->peer_chan; -} - - -/** - * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel - * - * @cfg: common configuration struct. - * @bi: bss info struct, result from scan. - * - */ -bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, - struct brcmf_bss_info_le *bi) - -{ - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct afx_hdl *afx_hdl = &p2p->afx_hdl; - u8 *ie; - s32 err; - u8 p2p_dev_addr[ETH_ALEN]; - - if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status)) - return false; - - if (bi == NULL) { - brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n"); - if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL) - complete(&afx_hdl->act_frm_scan); - return true; - } - - ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); - memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr)); - err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length), - IEEE80211_P2P_ATTR_DEVICE_INFO, - p2p_dev_addr, sizeof(p2p_dev_addr)); - if (err < 0) - err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length), - IEEE80211_P2P_ATTR_DEVICE_ID, - p2p_dev_addr, sizeof(p2p_dev_addr)); - if ((err >= 0) && - (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) { - afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); - brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n", - afx_hdl->tx_dst_addr, afx_hdl->peer_chan); - complete(&afx_hdl->act_frm_scan); - } - return true; -} - -/** - * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete. - * - * @cfg: common configuration struct. - * - */ -static void -brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct net_device *ndev = cfg->escan_info.ndev; - - if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) && - (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) || - test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) { - brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n"); - /* if channel is not zero, "actfame" uses off channel scan. - * So abort scan for off channel completion. - */ - if (p2p->af_sent_channel) - brcmf_notify_escan_complete(cfg, ndev, true, true); - } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, - &p2p->status)) { - brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n"); - /* So abort scan to cancel listen */ - brcmf_notify_escan_complete(cfg, ndev, true, true); - } -} - - -/** - * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission - * - * @p2p: p2p device info struct. - * - * return true if recevied action frame is to be dropped. - */ -static bool -brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac) -{ - struct brcmf_cfg80211_info *cfg = p2p->cfg; - struct brcmf_if *ifp; - - brcmf_dbg(TRACE, "Enter\n"); - - if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) || - !p2p->gon_req_action) - return false; - - brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n"); - /* if sa(peer) addr is less than da(my) addr, then this device - * process peer's gon request and block to send gon req. - * if not (sa addr > da addr), - * this device will process gon request and drop gon req of peer. - */ - ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; - if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) { - brcmf_dbg(INFO, "Block transmit gon req !!!\n"); - p2p->block_gon_req_tx = true; - /* if we are finding a common channel for sending af, - * do not scan more to block to send current gon req - */ - if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, - &p2p->status)) - complete(&p2p->afx_hdl.act_frm_scan); - if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, - &p2p->status)) - brcmf_p2p_stop_wait_next_action_frame(cfg); - return false; - } - - /* drop gon request of peer to process gon request by this device. */ - brcmf_dbg(INFO, "Drop received gon req !!!\n"); - - return true; -} - - -/** - * brcmf_p2p_notify_action_frame_rx() - received action frame. - * - * @ifp: interfac control. - * @e: event message. Not used, to make it usable for fweh event dispatcher. - * @data: payload of message, containing action frame data. - * - */ -int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct afx_hdl *afx_hdl = &p2p->afx_hdl; - struct wireless_dev *wdev; - u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data); - struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; - u8 *frame = (u8 *)(rxframe + 1); - struct brcmf_p2p_pub_act_frame *act_frm; - struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; - u16 chanspec = be16_to_cpu(rxframe->chanspec); - struct ieee80211_mgmt *mgmt_frame; - s32 freq; - u16 mgmt_type; - u8 action; - - /* Check if wpa_supplicant has registered for this frame */ - brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg); - mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4; - if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) - return 0; - - brcmf_p2p_print_actframe(false, frame, mgmt_frame_len); - - action = P2P_PAF_SUBTYPE_INVALID; - if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) { - act_frm = (struct brcmf_p2p_pub_act_frame *)frame; - action = act_frm->subtype; - if ((action == P2P_PAF_GON_REQ) && - (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) { - if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, - &p2p->status) && - (memcmp(afx_hdl->tx_dst_addr, e->addr, - ETH_ALEN) == 0)) { - afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec); - brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n", - afx_hdl->peer_chan); - complete(&afx_hdl->act_frm_scan); - } - return 0; - } - /* After complete GO Negotiation, roll back to mpc mode */ - if ((action == P2P_PAF_GON_CONF) || - (action == P2P_PAF_PROVDIS_RSP)) - brcmf_set_mpc(ifp->ndev, 1); - if (action == P2P_PAF_GON_CONF) { - brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n"); - clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); - } - } else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) { - sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; - action = sd_act_frm->action; - } - - if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) && - (p2p->next_af_subtype == action)) { - brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action); - clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, - &p2p->status); - /* Stop waiting for next AF. */ - brcmf_p2p_stop_wait_next_action_frame(cfg); - } - - mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) + - mgmt_frame_len, GFP_KERNEL); - if (!mgmt_frame) { - brcmf_err("No memory available for action frame\n"); - return -ENOMEM; - } - memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); - brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid, - ETH_ALEN); - memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); - mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); - memcpy(&mgmt_frame->u, frame, mgmt_frame_len); - mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); - - freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), - CHSPEC_IS2G(chanspec) ? - IEEE80211_BAND_2GHZ : - IEEE80211_BAND_5GHZ); - wdev = ifp->ndev->ieee80211_ptr; - cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, - GFP_ATOMIC); - - kfree(mgmt_frame); - return 0; -} - - -/** - * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete - * - * @ifp: interfac control. - * @e: event message. Not used, to make it usable for fweh event dispatcher. - * @data: not used. - * - */ -int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct brcmf_p2p_info *p2p = &cfg->p2p; - - brcmf_dbg(INFO, "Enter: event %s, status=%d\n", - e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ? - "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE", - e->status); - - if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status)) - return 0; - - if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) { - if (e->status == BRCMF_E_STATUS_SUCCESS) - set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, - &p2p->status); - else { - set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); - /* If there is no ack, we don't need to wait for - * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event - */ - brcmf_p2p_stop_wait_next_action_frame(cfg); - } - - } else { - complete(&p2p->send_af_done); - } - return 0; -} - - -/** - * brcmf_p2p_tx_action_frame() - send action frame over fil. - * - * @p2p: p2p info struct for vif. - * @af_params: action frame data/info. - * - * Send an action frame immediately without doing channel synchronization. - * - * This function waits for a completion event before returning. - * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action - * frame is transmitted. - */ -static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, - struct brcmf_fil_af_params_le *af_params) -{ - struct brcmf_cfg80211_vif *vif; - s32 err = 0; - s32 timeout = 0; - - brcmf_dbg(TRACE, "Enter\n"); - - INIT_COMPLETION(p2p->send_af_done); - clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); - clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); - - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params, - sizeof(*af_params)); - if (err) { - brcmf_err(" sending action frame has failed\n"); - goto exit; - } - - p2p->af_sent_channel = le32_to_cpu(af_params->channel); - p2p->af_tx_sent_jiffies = jiffies; - - timeout = wait_for_completion_timeout(&p2p->send_af_done, - msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME)); - - if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) { - brcmf_dbg(TRACE, "TX action frame operation is success\n"); - } else { - err = -EIO; - brcmf_dbg(TRACE, "TX action frame operation has failed\n"); - } - /* clear status bit for action tx */ - clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); - clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); - -exit: - return err; -} - - -/** - * brcmf_p2p_pub_af_tx() - public action frame tx routine. - * - * @cfg: driver private data for cfg80211 interface. - * @af_params: action frame data/info. - * @config_af_params: configuration data for action frame. - * - * routine which transmits ation frame public type. - */ -static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg, - struct brcmf_fil_af_params_le *af_params, - struct brcmf_config_af_params *config_af_params) -{ - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct brcmf_fil_action_frame_le *action_frame; - struct brcmf_p2p_pub_act_frame *act_frm; - s32 err = 0; - u16 ie_len; - - action_frame = &af_params->action_frame; - act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data); - - config_af_params->extra_listen = true; - - switch (act_frm->subtype) { - case P2P_PAF_GON_REQ: - brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n"); - set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); - config_af_params->mpc_onoff = 0; - config_af_params->search_channel = true; - p2p->next_af_subtype = act_frm->subtype + 1; - p2p->gon_req_action = true; - /* increase dwell time to wait for RESP frame */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); - break; - case P2P_PAF_GON_RSP: - p2p->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time to wait for CONF frame */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); - break; - case P2P_PAF_GON_CONF: - /* If we reached till GO Neg confirmation reset the filter */ - brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n"); - clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); - /* turn on mpc again if go nego is done */ - config_af_params->mpc_onoff = 1; - /* minimize dwell time */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); - config_af_params->extra_listen = false; - break; - case P2P_PAF_INVITE_REQ: - config_af_params->search_channel = true; - p2p->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); - break; - case P2P_PAF_INVITE_RSP: - /* minimize dwell time */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); - config_af_params->extra_listen = false; - break; - case P2P_PAF_DEVDIS_REQ: - config_af_params->search_channel = true; - p2p->next_af_subtype = act_frm->subtype + 1; - /* maximize dwell time to wait for RESP frame */ - af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME); - break; - case P2P_PAF_DEVDIS_RSP: - /* minimize dwell time */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); - config_af_params->extra_listen = false; - break; - case P2P_PAF_PROVDIS_REQ: - ie_len = le16_to_cpu(action_frame->len) - - offsetof(struct brcmf_p2p_pub_act_frame, elts); - if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len, - IEEE80211_P2P_ATTR_GROUP_ID, - NULL, 0) < 0) - config_af_params->search_channel = true; - config_af_params->mpc_onoff = 0; - p2p->next_af_subtype = act_frm->subtype + 1; - /* increase dwell time to wait for RESP frame */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); - break; - case P2P_PAF_PROVDIS_RSP: - /* wpa_supplicant send go nego req right after prov disc */ - p2p->next_af_subtype = P2P_PAF_GON_REQ; - /* increase dwell time to MED level */ - af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); - config_af_params->extra_listen = false; - break; - default: - brcmf_err("Unknown p2p pub act frame subtype: %d\n", - act_frm->subtype); - err = -EINVAL; - } - return err; -} - -/** - * brcmf_p2p_send_action_frame() - send action frame . - * - * @cfg: driver private data for cfg80211 interface. - * @ndev: net device to transmit on. - * @af_params: configuration data for action frame. - */ -bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - struct brcmf_fil_af_params_le *af_params) -{ - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct brcmf_fil_action_frame_le *action_frame; - struct brcmf_config_af_params config_af_params; - struct afx_hdl *afx_hdl = &p2p->afx_hdl; - u16 action_frame_len; - bool ack = false; - u8 category; - u8 action; - s32 tx_retry; - s32 extra_listen_time; - uint delta_ms; - - action_frame = &af_params->action_frame; - action_frame_len = le16_to_cpu(action_frame->len); - - brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len); - - /* Add the default dwell time. Dwell time to stay off-channel */ - /* to wait for a response action frame after transmitting an */ - /* GO Negotiation action frame */ - af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME); - - category = action_frame->data[DOT11_ACTION_CAT_OFF]; - action = action_frame->data[DOT11_ACTION_ACT_OFF]; - - /* initialize variables */ - p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; - p2p->gon_req_action = false; - - /* config parameters */ - config_af_params.mpc_onoff = -1; - config_af_params.search_channel = false; - config_af_params.extra_listen = false; - - if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) { - /* p2p public action frame process */ - if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) { - /* Just send unknown subtype frame with */ - /* default parameters. */ - brcmf_err("P2P Public action frame, unknown subtype.\n"); - } - } else if (brcmf_p2p_is_gas_action(action_frame->data, - action_frame_len)) { - /* service discovery process */ - if (action == P2PSD_ACTION_ID_GAS_IREQ || - action == P2PSD_ACTION_ID_GAS_CREQ) { - /* configure service discovery query frame */ - config_af_params.search_channel = true; - - /* save next af suptype to cancel */ - /* remaining dwell time */ - p2p->next_af_subtype = action + 1; - - af_params->dwell_time = - cpu_to_le32(P2P_AF_MED_DWELL_TIME); - } else if (action == P2PSD_ACTION_ID_GAS_IRESP || - action == P2PSD_ACTION_ID_GAS_CRESP) { - /* configure service discovery response frame */ - af_params->dwell_time = - cpu_to_le32(P2P_AF_MIN_DWELL_TIME); - } else { - brcmf_err("Unknown action type: %d\n", action); - goto exit; - } - } else if (brcmf_p2p_is_p2p_action(action_frame->data, - action_frame_len)) { - /* do not configure anything. it will be */ - /* sent with a default configuration */ - } else { - brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n", - category, action); - return false; - } - - /* if connecting on primary iface, sleep for a while before sending - * af tx for VSDB - */ - if (test_bit(BRCMF_VIF_STATUS_CONNECTING, - &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state)) - msleep(50); - - /* if scan is ongoing, abort current scan. */ - if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) - brcmf_abort_scanning(cfg); - - memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN); - - /* To make sure to send successfully action frame, turn off mpc */ - if (config_af_params.mpc_onoff == 0) - brcmf_set_mpc(ndev, 0); - - /* set status and destination address before sending af */ - if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { - /* set status to cancel the remained dwell time in rx process */ - set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); - } - - p2p->af_sent_channel = 0; - set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status); - /* validate channel and p2p ies */ - if (config_af_params.search_channel && - IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) && - p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) { - afx_hdl = &p2p->afx_hdl; - afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel); - - if (brcmf_p2p_af_searching_channel(p2p) == - P2P_INVALID_CHANNEL) { - brcmf_err("Couldn't find peer's channel.\n"); - goto exit; - } - - /* Abort scan even for VSDB scenarios. Scan gets aborted in - * firmware but after the check of piggyback algorithm. To take - * care of current piggback algo, lets abort the scan here - * itself. - */ - brcmf_notify_escan_complete(cfg, ndev, true, true); - - /* update channel */ - af_params->channel = cpu_to_le32(afx_hdl->peer_chan); - } - - tx_retry = 0; - while (!p2p->block_gon_req_tx && - (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) { - ack = !brcmf_p2p_tx_action_frame(p2p, af_params); - tx_retry++; - } - if (ack == false) { - brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry); - clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); - } - -exit: - clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status); - - /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. - * if we coundn't get the next action response frame and dongle does - * not keep the dwell time, go to listen state again to get next action - * response frame. - */ - if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx && - test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) && - p2p->af_sent_channel == afx_hdl->my_listen_chan) { - delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies); - if (le32_to_cpu(af_params->dwell_time) > delta_ms) - extra_listen_time = le32_to_cpu(af_params->dwell_time) - - delta_ms; - else - extra_listen_time = 0; - if (extra_listen_time > 50) { - set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, - &p2p->status); - brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n", - le32_to_cpu(af_params->dwell_time), - extra_listen_time); - extra_listen_time += 100; - if (!brcmf_p2p_discover_listen(p2p, - p2p->af_sent_channel, - extra_listen_time)) { - unsigned long duration; - - extra_listen_time += 100; - duration = msecs_to_jiffies(extra_listen_time); - wait_for_completion_timeout(&p2p->wait_next_af, - duration); - } - clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, - &p2p->status); - } - } - - if (p2p->block_gon_req_tx) { - /* if ack is true, supplicant will wait more time(100ms). - * so we will return it as a success to get more time . - */ - p2p->block_gon_req_tx = false; - ack = true; - } - - clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); - /* if all done, turn mpc on again */ - if (config_af_params.mpc_onoff == 1) - brcmf_set_mpc(ndev, 1); - - return ack; -} - -/** - * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req. - * - * @ifp: interface pointer for which event was received. - * @e: even message. - * @data: payload of event message (probe request). - */ -s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct afx_hdl *afx_hdl = &p2p->afx_hdl; - struct wireless_dev *wdev; - struct brcmf_cfg80211_vif *vif = ifp->vif; - struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; - u16 chanspec = be16_to_cpu(rxframe->chanspec); - u8 *mgmt_frame; - u32 mgmt_frame_len; - s32 freq; - u16 mgmt_type; - - brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, - e->reason); - - if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && - (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) { - afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec); - brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n", - afx_hdl->peer_chan); - complete(&afx_hdl->act_frm_scan); - } - - /* Firmware sends us two proberesponses for each idx one. At the */ - /* moment anything but bsscfgidx 0 is passed up to supplicant */ - if (e->bsscfgidx == 0) - return 0; - - /* Filter any P2P probe reqs arriving during the GO-NEG Phase */ - if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) { - brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n"); - return 0; - } - - /* Check if wpa_supplicant has registered for this frame */ - brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg); - mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4; - if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) - return 0; - - mgmt_frame = (u8 *)(rxframe + 1); - mgmt_frame_len = e->datalen - sizeof(*rxframe); - freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), - CHSPEC_IS2G(chanspec) ? - IEEE80211_BAND_2GHZ : - IEEE80211_BAND_5GHZ); - wdev = ifp->ndev->ieee80211_ptr; - cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); - - brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", - mgmt_frame_len, e->datalen, chanspec, freq); - - return 0; -} - - -/** - * brcmf_p2p_attach() - attach for P2P. - * - * @cfg: driver private data for cfg80211 interface. - */ -s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_if *pri_ifp; - struct brcmf_if *p2p_ifp; - struct brcmf_cfg80211_vif *p2p_vif; - struct brcmf_p2p_info *p2p; - struct brcmf_pub *drvr; - s32 bssidx; - s32 err = 0; - - p2p = &cfg->p2p; - p2p->cfg = cfg; - - drvr = cfg->pub; - - pri_ifp = drvr->iflist[0]; - p2p_ifp = drvr->iflist[1]; - - p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; - - if (p2p_ifp) { - p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE, - false); - if (IS_ERR(p2p_vif)) { - brcmf_err("could not create discovery vif\n"); - err = -ENOMEM; - goto exit; - } - - p2p_vif->ifp = p2p_ifp; - p2p_ifp->vif = p2p_vif; - p2p_vif->wdev.netdev = p2p_ifp->ndev; - p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev; - SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy)); - - p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; - - brcmf_p2p_generate_bss_mac(p2p); - brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); - - /* Initialize P2P Discovery in the firmware */ - err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); - if (err < 0) { - brcmf_err("set p2p_disc error\n"); - brcmf_free_vif(p2p_vif); - goto exit; - } - /* obtain bsscfg index for P2P discovery */ - err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); - if (err < 0) { - brcmf_err("retrieving discover bsscfg index failed\n"); - brcmf_free_vif(p2p_vif); - goto exit; - } - /* Verify that firmware uses same bssidx as driver !! */ - if (p2p_ifp->bssidx != bssidx) { - brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", - bssidx, p2p_ifp->bssidx); - brcmf_free_vif(p2p_vif); - goto exit; - } - - init_completion(&p2p->send_af_done); - INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); - init_completion(&p2p->afx_hdl.act_frm_scan); - init_completion(&p2p->wait_next_af); - } -exit: - return err; -} - - -/** - * brcmf_p2p_detach() - detach P2P. - * - * @p2p: P2P specific data. - */ -void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) -{ - struct brcmf_cfg80211_vif *vif; - - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - if (vif != NULL) { - brcmf_p2p_cancel_remain_on_channel(vif->ifp); - brcmf_p2p_deinit_discovery(p2p); - /* remove discovery interface */ - brcmf_free_vif(vif); - p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; - } - /* just set it all to zero */ - memset(p2p, 0, sizeof(*p2p)); -} - -/** - * brcmf_p2p_get_current_chanspec() - Get current operation channel. - * - * @p2p: P2P specific data. - * @chanspec: chanspec to be returned. - */ -static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p, - u16 *chanspec) -{ - struct brcmf_if *ifp; - struct brcmf_fil_chan_info_le ci; - s32 err; - - ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - - *chanspec = 11 & WL_CHANSPEC_CHAN_MASK; - - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci)); - if (!err) { - *chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK; - if (*chanspec < CH_MAX_2G_CHANNEL) - *chanspec |= WL_CHANSPEC_BAND_2G; - else - *chanspec |= WL_CHANSPEC_BAND_5G; - } - *chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; -} - -/** - * Change a P2P Role. - * Parameters: - * @mac: MAC address of the BSS to change a role - * Returns 0 if success. - */ -int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, - enum brcmf_fil_p2p_if_types if_type) -{ - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct brcmf_cfg80211_vif *vif; - struct brcmf_fil_p2p_if_le if_request; - s32 err; - u16 chanspec; - - brcmf_dbg(TRACE, "Enter\n"); - - vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - if (!vif) { - brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n"); - return -EPERM; - } - brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true); - vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; - if (!vif) { - brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n"); - return -EPERM; - } - brcmf_set_mpc(vif->ifp->ndev, 0); - - /* In concurrency case, STA may be already associated in a particular */ - /* channel. so retrieve the current channel of primary interface and */ - /* then start the virtual interface on that. */ - brcmf_p2p_get_current_chanspec(p2p, &chanspec); - - if_request.type = cpu_to_le16((u16)if_type); - if_request.chspec = cpu_to_le16(chanspec); - memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr)); - - brcmf_cfg80211_arm_vif_event(cfg, vif); - err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request, - sizeof(if_request)); - if (err) { - brcmf_err("p2p_ifupd FAILED, err=%d\n", err); - brcmf_cfg80211_arm_vif_event(cfg, NULL); - return err; - } - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE, - msecs_to_jiffies(1500)); - brcmf_cfg80211_arm_vif_event(cfg, NULL); - if (!err) { - brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); - return -EIO; - } - - err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT, - BRCMF_SCB_TIMEOUT_VALUE); - - return err; -} - -static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p, - struct brcmf_if *ifp, u8 ea[ETH_ALEN], - enum brcmf_fil_p2p_if_types iftype) -{ - struct brcmf_fil_p2p_if_le if_request; - int err; - u16 chanspec; - - /* we need a default channel */ - brcmf_p2p_get_current_chanspec(p2p, &chanspec); - - /* fill the firmware request */ - memcpy(if_request.addr, ea, ETH_ALEN); - if_request.type = cpu_to_le16((u16)iftype); - if_request.chspec = cpu_to_le16(chanspec); - - err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request, - sizeof(if_request)); - if (err) - return err; - - return err; -} - -static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif) -{ - struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); - struct net_device *pri_ndev = cfg_to_ndev(cfg); - struct brcmf_if *ifp = netdev_priv(pri_ndev); - u8 *addr = vif->wdev.netdev->dev_addr; - - return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN); -} - -static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif) -{ - struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); - struct net_device *pri_ndev = cfg_to_ndev(cfg); - struct brcmf_if *ifp = netdev_priv(pri_ndev); - u8 *addr = vif->wdev.netdev->dev_addr; - - return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN); -} - -/** - * brcmf_p2p_add_vif() - create a new P2P virtual interface. - * - * @wiphy: wiphy device of new interface. - * @name: name of the new interface. - * @type: nl80211 interface type. - * @flags: TBD - * @params: TBD - */ -struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); - struct brcmf_cfg80211_vif *vif; - enum brcmf_fil_p2p_if_types iftype; - enum wl_mode mode; - int err; - - if (brcmf_cfg80211_vif_event_armed(cfg)) - return ERR_PTR(-EBUSY); - - brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type); - - switch (type) { - case NL80211_IFTYPE_P2P_CLIENT: - iftype = BRCMF_FIL_P2P_IF_CLIENT; - mode = WL_MODE_BSS; - break; - case NL80211_IFTYPE_P2P_GO: - iftype = BRCMF_FIL_P2P_IF_GO; - mode = WL_MODE_AP; - break; - default: - return ERR_PTR(-EOPNOTSUPP); - } - - vif = brcmf_alloc_vif(cfg, type, false); - if (IS_ERR(vif)) - return (struct wireless_dev *)vif; - brcmf_cfg80211_arm_vif_event(cfg, vif); - - err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr, - iftype); - if (err) { - brcmf_cfg80211_arm_vif_event(cfg, NULL); - goto fail; - } - - /* wait for firmware event */ - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, - msecs_to_jiffies(1500)); - brcmf_cfg80211_arm_vif_event(cfg, NULL); - if (!err) { - brcmf_err("timeout occurred\n"); - err = -EIO; - goto fail; - } - - /* interface created in firmware */ - ifp = vif->ifp; - if (!ifp) { - brcmf_err("no if pointer provided\n"); - err = -ENOENT; - goto fail; - } - - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); - err = brcmf_net_attach(ifp, true); - if (err) { - brcmf_err("Registering netdevice failed\n"); - goto fail; - } - cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; - /* Disable firmware roaming for P2P interface */ - brcmf_fil_iovar_int_set(ifp, "roam_off", 1); - if (iftype == BRCMF_FIL_P2P_IF_GO) { - /* set station timeout for p2p */ - brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT, - BRCMF_SCB_TIMEOUT_VALUE); - } - return &ifp->vif->wdev; - -fail: - brcmf_free_vif(vif); - return ERR_PTR(err); -} - -/** - * brcmf_p2p_del_vif() - delete a P2P virtual interface. - * - * @wiphy: wiphy device of interface. - * @wdev: wireless device of interface. - * - * TODO: not yet supported. - */ -int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - struct brcmf_p2p_info *p2p = &cfg->p2p; - struct brcmf_cfg80211_vif *vif; - unsigned long jiffie_timeout = msecs_to_jiffies(1500); - bool wait_for_disable = false; - int err; - - brcmf_dbg(TRACE, "delete P2P vif\n"); - vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); - - switch (vif->wdev.iftype) { - case NL80211_IFTYPE_P2P_CLIENT: - if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state)) - wait_for_disable = true; - break; - - case NL80211_IFTYPE_P2P_GO: - if (!brcmf_p2p_disable_p2p_if(vif)) - wait_for_disable = true; - break; - - case NL80211_IFTYPE_P2P_DEVICE: - default: - return -ENOTSUPP; - break; - } - - clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); - brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); - - if (wait_for_disable) - wait_for_completion_timeout(&cfg->vif_disabled, - msecs_to_jiffies(500)); - - brcmf_vif_clear_mgmt_ies(vif); - - brcmf_cfg80211_arm_vif_event(cfg, vif); - err = brcmf_p2p_release_p2p_if(vif); - if (!err) { - /* wait for firmware event */ - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, - jiffie_timeout); - if (!err) - err = -EIO; - else - err = 0; - } - brcmf_cfg80211_arm_vif_event(cfg, NULL); - brcmf_free_vif(vif); - p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; - - return err; -} diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/p2p.h deleted file mode 100644 index 6821b26224be..000000000000 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/p2p.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2012 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef WL_CFGP2P_H_ -#define WL_CFGP2P_H_ - -#include - -struct brcmf_cfg80211_info; - -/** - * enum p2p_bss_type - different type of BSS configurations. - * - * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg. - * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg. - * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg. - * @P2PAPI_BSSCFG_MAX: used for range checking. - */ -enum p2p_bss_type { - P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ - P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ - P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ - P2PAPI_BSSCFG_MAX -}; - -/** - * struct p2p_bss - peer-to-peer bss related information. - * - * @vif: virtual interface of this P2P bss. - * @private_data: TBD - */ -struct p2p_bss { - struct brcmf_cfg80211_vif *vif; - void *private_data; -}; - -/** - * enum brcmf_p2p_status - P2P specific dongle status. - * - * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle. - * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED? - * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle. - * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle. - * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle. - * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed. - * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked. - * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing. - * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel. - * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame. - * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx. - * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response. - * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active. - */ -enum brcmf_p2p_status { - BRCMF_P2P_STATUS_ENABLED, - BRCMF_P2P_STATUS_IF_ADD, - BRCMF_P2P_STATUS_IF_DEL, - BRCMF_P2P_STATUS_IF_DELETING, - BRCMF_P2P_STATUS_IF_CHANGING, - BRCMF_P2P_STATUS_IF_CHANGED, - BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, - BRCMF_P2P_STATUS_ACTION_TX_NOACK, - BRCMF_P2P_STATUS_GO_NEG_PHASE, - BRCMF_P2P_STATUS_DISCOVER_LISTEN, - BRCMF_P2P_STATUS_SENDING_ACT_FRAME, - BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, - BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, - BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL -}; - -/** - * struct afx_hdl - action frame off channel storage. - * - * @afx_work: worker thread for searching channel - * @act_frm_scan: thread synchronizing struct. - * @is_active: channel searching active. - * @peer_chan: current channel. - * @is_listen: sets mode for afx worker. - * @my_listen_chan: this peers listen channel. - * @peer_listen_chan: remote peers listen channel. - * @tx_dst_addr: mac address where tx af should be sent to. - */ -struct afx_hdl { - struct work_struct afx_work; - struct completion act_frm_scan; - bool is_active; - s32 peer_chan; - bool is_listen; - u16 my_listen_chan; - u16 peer_listen_chan; - u8 tx_dst_addr[ETH_ALEN]; -}; - -/** - * struct brcmf_p2p_info - p2p specific driver information. - * - * @cfg: driver private data for cfg80211 interface. - * @status: status of P2P (see enum brcmf_p2p_status). - * @dev_addr: P2P device address. - * @int_addr: P2P interface address. - * @bss_idx: informate for P2P bss types. - * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state. - * @ssid: ssid for P2P GO. - * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state. - * @remain_on_channel: contains copy of struct used by cfg80211. - * @remain_on_channel_cookie: cookie counter for remain on channel cmd - * @next_af_subtype: expected action frame subtype. - * @send_af_done: indication that action frame tx is complete. - * @afx_hdl: action frame search handler info. - * @af_sent_channel: channel action frame is sent. - * @af_tx_sent_jiffies: jiffies time when af tx was transmitted. - * @wait_next_af: thread synchronizing struct. - * @gon_req_action: about to send go negotiation requets frame. - * @block_gon_req_tx: drop tx go negotiation requets frame. - */ -struct brcmf_p2p_info { - struct brcmf_cfg80211_info *cfg; - unsigned long status; - u8 dev_addr[ETH_ALEN]; - u8 int_addr[ETH_ALEN]; - struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; - struct timer_list listen_timer; - struct brcmf_ssid ssid; - u8 listen_channel; - struct ieee80211_channel remain_on_channel; - u32 remain_on_channel_cookie; - u8 next_af_subtype; - struct completion send_af_done; - struct afx_hdl afx_hdl; - u32 af_sent_channel; - unsigned long af_tx_sent_jiffies; - struct completion wait_next_af; - bool gon_req_action; - bool block_gon_req_tx; -}; - -s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); -void brcmf_p2p_detach(struct brcmf_p2p_info *p2p); -struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params); -int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); -int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, - enum brcmf_fil_p2p_if_types if_type); -int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); -void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); -int brcmf_p2p_scan_prep(struct wiphy *wiphy, - struct cfg80211_scan_request *request, - struct brcmf_cfg80211_vif *vif); -int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *channel, - unsigned int duration, u64 *cookie); -int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data); -void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp); -int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data); -int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data); -bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - struct brcmf_fil_af_params_le *af_params); -bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, - struct brcmf_bss_info_le *bi); -s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, - void *data); -#endif /* WL_CFGP2P_H_ */ diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c index a55994d33763..e15630cc3889 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -421,6 +421,10 @@ static void brcmf_usb_tx_complete(struct urb *urb) brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, req->skb); brcmf_usb_del_fromq(devinfo, req); + if (urb->status == 0) + devinfo->bus_pub.bus->dstats.tx_packets++; + else + devinfo->bus_pub.bus->dstats.tx_errors++; brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); @@ -447,7 +451,10 @@ static void brcmf_usb_rx_complete(struct urb *urb) req->skb = NULL; /* zero lenght packets indicate usb "failure". Do not refill */ - if (urb->status != 0 || !urb->actual_length) { + if (urb->status == 0 && urb->actual_length) { + devinfo->bus_pub.bus->dstats.rx_packets++; + } else { + devinfo->bus_pub.bus->dstats.rx_errors++; brcmu_pkt_buf_free_skb(skb); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); return; @@ -1250,8 +1257,6 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) bus->bus_priv.usb = bus_pub; dev_set_drvdata(dev, bus); bus->ops = &brcmf_usb_bus_ops; - bus->chip = bus_pub->devid; - bus->chiprev = bus_pub->chiprev; /* Attach to the common driver interface */ ret = brcmf_attach(0, dev); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 481f41ad7989..62a528e8b958 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -26,8 +26,6 @@ #include #include "dhd.h" #include "dhd_dbg.h" -#include "fwil_types.h" -#include "p2p.h" #include "wl_cfg80211.h" #include "fwil.h" @@ -43,13 +41,16 @@ #define BRCMF_PNO_SCAN_COMPLETE 1 #define BRCMF_PNO_SCAN_INCOMPLETE 0 -#define BRCMF_IFACE_MAX_CNT 3 +#define BRCMF_IFACE_MAX_CNT 2 +#define TLV_LEN_OFF 1 /* length offset */ +#define TLV_HDR_LEN 2 /* header length */ +#define TLV_BODY_OFF 2 /* body offset */ +#define TLV_OUI_LEN 3 /* oui id length */ #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ #define WPA_OUI_TYPE 1 #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ #define WME_OUI_TYPE 2 -#define WPS_OUI_TYPE 4 #define VS_IE_FIXED_HDR_LEN 6 #define WPA_IE_VERSION_LEN 2 @@ -75,15 +76,13 @@ #define VNDR_IE_PKTFLAG_OFFSET 8 #define VNDR_IE_VSIE_OFFSET 12 #define VNDR_IE_HDR_SIZE 12 -#define VNDR_IE_PARSE_LIMIT 5 +#define VNDR_IE_BEACON_FLAG 0x1 +#define VNDR_IE_PRBRSP_FLAG 0x2 +#define MAX_VNDR_IE_NUMBER 5 #define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ #define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ -#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 -#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 -#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20 - #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) @@ -272,6 +271,13 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_AES_CMAC, }; +/* tag_ID/length/value_buffer tuple */ +struct brcmf_tlv { + u8 id; + u8 len; + u8 data[1]; +}; + /* Vendor specific ie. id = 221, oui and type defines exact ie */ struct brcmf_vs_tlv { u8 id; @@ -288,7 +294,7 @@ struct parsed_vndr_ie_info { struct parsed_vndr_ies { u32 count; - struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; + struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; }; /* Quarter dBm units to mW @@ -375,7 +381,7 @@ static u8 brcmf_mw_to_qdbm(u16 mw) return qdbm; } -u16 channel_to_chanspec(struct ieee80211_channel *ch) +static u16 channel_to_chanspec(struct ieee80211_channel *ch) { u16 chanspec; @@ -387,92 +393,19 @@ u16 channel_to_chanspec(struct ieee80211_channel *ch) else chanspec |= WL_CHANSPEC_BAND_5G; - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - return chanspec; -} - -/* Traverse a string of 1-byte tag/1-byte length/variable-length value - * triples, returning a pointer to the substring whose first element - * matches tag - */ -struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) -{ - struct brcmf_tlv *elt; - int totlen; - - elt = (struct brcmf_tlv *)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len; - - /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) - return elt; - - elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - - return NULL; -} - -/* Is any of the tlvs the expected entry? If - * not update the tlvs buffer pointer/length. - */ -static bool -brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, - u8 *oui, u32 oui_len, u8 type) -{ - /* If the contents match the OUI and the type */ - if (ie[TLV_LEN_OFF] >= oui_len + 1 && - !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && - type == ie[TLV_BODY_OFF + oui_len]) { - return true; - } - - if (tlvs == NULL) - return false; - /* point to the next ie */ - ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; - /* calculate the length of the rest of the buffer */ - *tlvs_len -= (int)(ie - *tlvs); - /* update the pointer to the start of the buffer */ - *tlvs = ie; - - return false; -} - -static struct brcmf_vs_tlv * -brcmf_find_wpaie(u8 *parse, u32 len) -{ - struct brcmf_tlv *ie; - - while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { - if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, - WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) - return (struct brcmf_vs_tlv *)ie; - } - return NULL; -} - -static struct brcmf_vs_tlv * -brcmf_find_wpsie(u8 *parse, u32 len) -{ - struct brcmf_tlv *ie; - - while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { - if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, - WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE)) - return (struct brcmf_vs_tlv *)ie; + if (ch->flags & IEEE80211_CHAN_NO_HT40) { + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + } else { + chanspec |= WL_CHANSPEC_BW_40; + if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS) + chanspec |= WL_CHANSPEC_CTL_SB_LOWER; + else + chanspec |= WL_CHANSPEC_CTL_SB_UPPER; } - return NULL; + return chanspec; } - static void convert_key_from_CPU(struct brcmf_wsec_key *key, struct brcmf_wsec_key_le *key_le) { @@ -505,153 +438,11 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) return err; } -static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, - const char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) -{ - brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); - switch (type) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_MESH_POINT: - return ERR_PTR(-EOPNOTSUPP); - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_P2P_GO: - return brcmf_p2p_add_vif(wiphy, name, type, flags, params); - case NL80211_IFTYPE_UNSPECIFIED: - case NL80211_IFTYPE_P2P_DEVICE: - default: - return ERR_PTR(-EINVAL); - } -} - -void brcmf_set_mpc(struct net_device *ndev, int mpc) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - s32 err = 0; - - if (check_vif_up(ifp->vif)) { - err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); - if (err) { - brcmf_err("fail to set mpc\n"); - return; - } - brcmf_dbg(INFO, "MPC : %d\n", mpc); - } -} - -s32 -brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - bool aborted, bool fw_abort) -{ - struct brcmf_scan_params_le params_le; - struct cfg80211_scan_request *scan_request; - s32 err = 0; - - brcmf_dbg(SCAN, "Enter\n"); - - /* clear scan request, because the FW abort can cause a second call */ - /* to this functon and might cause a double cfg80211_scan_done */ - scan_request = cfg->scan_request; - cfg->scan_request = NULL; - - if (timer_pending(&cfg->escan_timeout)) - del_timer_sync(&cfg->escan_timeout); - - if (fw_abort) { - /* Do a scan abort to stop the driver's scan engine */ - brcmf_dbg(SCAN, "ABORT scan in firmware\n"); - memset(¶ms_le, 0, sizeof(params_le)); - memset(params_le.bssid, 0xFF, ETH_ALEN); - params_le.bss_type = DOT11_BSSTYPE_ANY; - params_le.scan_type = 0; - params_le.channel_num = cpu_to_le32(1); - params_le.nprobes = cpu_to_le32(1); - params_le.active_time = cpu_to_le32(-1); - params_le.passive_time = cpu_to_le32(-1); - params_le.home_time = cpu_to_le32(-1); - /* Scan is aborted by setting channel_list[0] to -1 */ - params_le.channel_list[0] = cpu_to_le16(-1); - /* E-Scan (or anyother type) can be aborted by SCAN */ - err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, - ¶ms_le, sizeof(params_le)); - if (err) - brcmf_err("Scan abort failed\n"); - } - /* - * e-scan can be initiated by scheduled scan - * which takes precedence. - */ - if (cfg->sched_escan) { - brcmf_dbg(SCAN, "scheduled scan completed\n"); - cfg->sched_escan = false; - if (!aborted) - cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); - brcmf_set_mpc(ndev, 1); - } else if (scan_request) { - brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", - aborted ? "Aborted" : "Done"); - cfg80211_scan_done(scan_request, aborted); - brcmf_set_mpc(ndev, 1); - } - if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) - brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); - - return err; -} - -static -int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) -{ - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - struct net_device *ndev = wdev->netdev; - - /* vif event pending in firmware */ - if (brcmf_cfg80211_vif_event_armed(cfg)) - return -EBUSY; - - if (ndev) { - if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) && - cfg->escan_info.ndev == ndev) - brcmf_notify_escan_complete(cfg, ndev, true, - true); - - brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1); - } - - switch (wdev->iftype) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_MESH_POINT: - return -EOPNOTSUPP; - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_P2P_GO: - return brcmf_p2p_del_vif(wiphy, wdev); - case NL80211_IFTYPE_UNSPECIFIED: - case NL80211_IFTYPE_P2P_DEVICE: - default: - return -EINVAL; - } - return -EOPNOTSUPP; -} - static s32 brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_vif *vif = ifp->vif; s32 infra = 0; @@ -671,23 +462,10 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, infra = 0; break; case NL80211_IFTYPE_STATION: - /* Ignore change for p2p IF. Unclear why supplicant does this */ - if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) || - (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) { - brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n"); - /* WAR: It is unexpected to get a change of VIF for P2P - * IF, but it happens. The request can not be handled - * but returning EPERM causes a crash. Returning 0 - * without setting ieee80211_ptr->iftype causes trace - * (WARN_ON) but it works with wpa_supplicant - */ - return 0; - } vif->mode = WL_MODE_BSS; infra = 1; break; case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: vif->mode = WL_MODE_AP; ap = 1; break; @@ -697,14 +475,8 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, } if (ap) { - if (type == NL80211_IFTYPE_P2P_GO) { - brcmf_dbg(INFO, "IF Type = P2P GO\n"); - err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO); - } - if (!err) { - set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); - brcmf_dbg(INFO, "IF Type = AP\n"); - } + set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); + brcmf_dbg(INFO, "IF Type = AP\n"); } else { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); if (err) { @@ -723,6 +495,21 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, return err; } +static void brcmf_set_mpc(struct net_device *ndev, int mpc) +{ + struct brcmf_if *ifp = netdev_priv(ndev); + s32 err = 0; + + if (check_vif_up(ifp->vif)) { + err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); + if (err) { + brcmf_err("fail to set mpc\n"); + return; + } + brcmf_dbg(INFO, "MPC : %d\n", mpc); + } +} + static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, struct cfg80211_scan_request *request) { @@ -802,6 +589,69 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK)); } +static s32 +brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, + struct net_device *ndev, + bool aborted, bool fw_abort) +{ + struct brcmf_scan_params_le params_le; + struct cfg80211_scan_request *scan_request; + s32 err = 0; + + brcmf_dbg(SCAN, "Enter\n"); + + /* clear scan request, because the FW abort can cause a second call */ + /* to this functon and might cause a double cfg80211_scan_done */ + scan_request = cfg->scan_request; + cfg->scan_request = NULL; + + if (timer_pending(&cfg->escan_timeout)) + del_timer_sync(&cfg->escan_timeout); + + if (fw_abort) { + /* Do a scan abort to stop the driver's scan engine */ + brcmf_dbg(SCAN, "ABORT scan in firmware\n"); + memset(¶ms_le, 0, sizeof(params_le)); + memset(params_le.bssid, 0xFF, ETH_ALEN); + params_le.bss_type = DOT11_BSSTYPE_ANY; + params_le.scan_type = 0; + params_le.channel_num = cpu_to_le32(1); + params_le.nprobes = cpu_to_le32(1); + params_le.active_time = cpu_to_le32(-1); + params_le.passive_time = cpu_to_le32(-1); + params_le.home_time = cpu_to_le32(-1); + /* Scan is aborted by setting channel_list[0] to -1 */ + params_le.channel_list[0] = cpu_to_le16(-1); + /* E-Scan (or anyother type) can be aborted by SCAN */ + err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, + ¶ms_le, sizeof(params_le)); + if (err) + brcmf_err("Scan abort failed\n"); + } + /* + * e-scan can be initiated by scheduled scan + * which takes precedence. + */ + if (cfg->sched_escan) { + brcmf_dbg(SCAN, "scheduled scan completed\n"); + cfg->sched_escan = false; + if (!aborted) + cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); + brcmf_set_mpc(ndev, 1); + } else if (scan_request) { + brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", + aborted ? "Aborted" : "Done"); + cfg80211_scan_done(scan_request, aborted); + brcmf_set_mpc(ndev, 1); + } + if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + brcmf_err("Scan complete while device not scanning\n"); + return -EPERM; + } + + return err; +} + static s32 brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, struct cfg80211_scan_request *request, u16 action) @@ -853,12 +703,11 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, s32 err; u32 passive_scan; struct brcmf_scan_results *results; - struct escan_info *escan = &cfg->escan_info; brcmf_dbg(SCAN, "Enter\n"); - escan->ndev = ndev; - escan->wiphy = wiphy; - escan->escan_state = WL_ESCAN_STATE_SCANNING; + cfg->escan_info.ndev = ndev; + cfg->escan_info.wiphy = wiphy; + cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; passive_scan = cfg->active_scan ? 0 : 1; err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN, passive_scan); @@ -872,7 +721,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, results->count = 0; results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; - err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START); + err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START); if (err) brcmf_set_mpc(ndev, 1); return err; @@ -909,12 +758,6 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, return -EAGAIN; } - /* If scan req comes for p2p0, send it over primary I/F */ - if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) { - ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - ndev = ifp->ndev; - } - /* Arm scan timeout timer */ mod_timer(&cfg->escan_timeout, jiffies + WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); @@ -933,11 +776,6 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, cfg->scan_request = request; set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); if (escan_req) { - cfg->escan_info.run = brcmf_run_escan; - err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif); - if (err) - goto scan_out; - err = brcmf_do_escan(cfg, wiphy, ndev, request); if (err) goto scan_out; @@ -1095,6 +933,31 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) memset(prof, 0, sizeof(*prof)); } +static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, + size_t *join_params_size) +{ + u16 chanspec = 0; + + if (ch != 0) { + if (ch <= CH_MAX_2G_CHANNEL) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + + sizeof(u16); + + chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); + join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); + join_params->params_le.chanspec_num = cpu_to_le32(1); + + brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec); + } +} + static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) { s32 err = 0; @@ -1125,7 +988,6 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, s32 err = 0; s32 wsec = 0; s32 bcnprd; - u16 chanspec; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) @@ -1229,11 +1091,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, params->chandef.chan->center_freq); if (params->channel_fixed) { /* adding chanspec */ - chanspec = channel_to_chanspec(params->chandef.chan); - join_params.params_le.chanspec_list[0] = - cpu_to_le16(chanspec); - join_params.params_le.chanspec_num = cpu_to_le32(1); - join_params_size += sizeof(join_params.params_le); + brcmf_ch_to_chanspec(cfg->channel, + &join_params, &join_params_size); } /* set channel for starter */ @@ -1296,7 +1155,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, else val = WPA_AUTH_DISABLED; brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); + err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val); if (err) { brcmf_err("set wpa_auth failed (%d)\n", err); return err; @@ -1335,7 +1194,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, break; } - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); + err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val); if (err) { brcmf_err("set auth failed (%d)\n", err); return err; @@ -1399,12 +1258,7 @@ brcmf_set_set_cipher(struct net_device *ndev, } brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval); - /* In case of privacy, but no security and WPS then simulate */ - /* setting AES. WPS-2.0 allows no security */ - if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval && - sme->privacy) - pval = AES_ENABLED; - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval); + err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval); if (err) { brcmf_err("error (%d)\n", err); return err; @@ -1426,8 +1280,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) s32 err = 0; if (sme->crypto.n_akm_suites) { - err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), - "wpa_auth", &val); + err = brcmf_fil_iovar_int_get(netdev_priv(ndev), + "wpa_auth", &val); if (err) { brcmf_err("could not get wpa_auth (%d)\n", err); return err; @@ -1461,8 +1315,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) } brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), - "wpa_auth", val); + err = brcmf_fil_iovar_int_set(netdev_priv(ndev), + "wpa_auth", val); if (err) { brcmf_err("could not set wpa_auth (%d)\n", err); return err; @@ -1539,28 +1393,9 @@ brcmf_set_sharedkey(struct net_device *ndev, return err; } -static -enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp, - enum nl80211_auth_type type) -{ - u32 ci; - if (type == NL80211_AUTHTYPE_AUTOMATIC) { - /* shift to ignore chip revision */ - ci = brcmf_get_chip_info(ifp) >> 4; - switch (ci) { - case 43236: - brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n"); - return NL80211_AUTHTYPE_OPEN_SYSTEM; - default: - break; - } - } - return type; -} - static s32 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_connect_params *sme) + struct cfg80211_connect_params *sme) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); @@ -1568,12 +1403,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *chan = sme->channel; struct brcmf_join_params join_params; size_t join_params_size; - struct brcmf_tlv *rsn_ie; - struct brcmf_vs_tlv *wpa_ie; - void *ie; - u32 ie_len; - struct brcmf_ext_join_params_le *ext_join_params; - u16 chanspec; + struct brcmf_ssid ssid; s32 err = 0; @@ -1586,46 +1416,15 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, return -EOPNOTSUPP; } - if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) { - /* A normal (non P2P) connection request setup. */ - ie = NULL; - ie_len = 0; - /* find the WPA_IE */ - wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len); - if (wpa_ie) { - ie = wpa_ie; - ie_len = wpa_ie->len + TLV_HDR_LEN; - } else { - /* find the RSN_IE */ - rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len, - WLAN_EID_RSN); - if (rsn_ie) { - ie = rsn_ie; - ie_len = rsn_ie->len + TLV_HDR_LEN; - } - } - brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len); - } - - err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG, - sme->ie, sme->ie_len); - if (err) - brcmf_err("Set Assoc REQ IE Failed\n"); - else - brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n"); - set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); if (chan) { cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); - chanspec = channel_to_chanspec(chan); - brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n", - cfg->channel, chan->center_freq, chanspec); - } else { + brcmf_dbg(CONN, "channel (%d), center_req (%d)\n", + cfg->channel, chan->center_freq); + } else cfg->channel = 0; - chanspec = 0; - } brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); @@ -1635,7 +1434,6 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type); err = brcmf_set_auth_type(ndev, sme); if (err) { brcmf_err("wl_set_auth_type failed (%d)\n", err); @@ -1660,88 +1458,27 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID), - (u32)sme->ssid_len); - memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); - if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { - profile->ssid.SSID[profile->ssid.SSID_len] = 0; - brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID, - profile->ssid.SSID_len); - } - - /* Join with specific BSSID and cached SSID - * If SSID is zero join based on BSSID only - */ - join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) + - offsetof(struct brcmf_assoc_params_le, chanspec_list); - if (cfg->channel) - join_params_size += sizeof(u16); - ext_join_params = kzalloc(join_params_size, GFP_KERNEL); - if (ext_join_params == NULL) { - err = -ENOMEM; - goto done; - } - ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); - memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, - profile->ssid.SSID_len); - /*increase dwell time to receive probe response or detect Beacon - * from target AP at a noisy air only during connect command - */ - ext_join_params->scan_le.active_time = - cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); - ext_join_params->scan_le.passive_time = - cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); - /* Set up join scan parameters */ - ext_join_params->scan_le.scan_type = -1; - /* to sync with presence period of VSDB GO. - * Send probe request more frequently. Probe request will be stopped - * when it gets probe response from target AP/GO. - */ - ext_join_params->scan_le.nprobes = - cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / - BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); - ext_join_params->scan_le.home_time = cpu_to_le32(-1); - - if (sme->bssid) - memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN); - else - memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN); - - if (cfg->channel) { - ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1); - - ext_join_params->assoc_le.chanspec_list[0] = - cpu_to_le16(chanspec); - } - - err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, - join_params_size); - kfree(ext_join_params); - if (!err) - /* This is it. join command worked, we are done */ - goto done; - - /* join command failed, fallback to set ssid */ memset(&join_params, 0, sizeof(join_params)); join_params_size = sizeof(join_params.ssid_le); + profile->ssid.SSID_len = min_t(u32, + sizeof(ssid.SSID), (u32)sme->ssid_len); memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); + memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); - if (sme->bssid) - memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN); - else - memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); + memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); - if (cfg->channel) { - join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec); - join_params.params_le.chanspec_num = cpu_to_le32(1); - join_params_size += sizeof(join_params.params_le); - } + if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) + brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n", + ssid.SSID, ssid.SSID_len); + + brcmf_ch_to_chanspec(cfg->channel, + &join_params, &join_params_size); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, join_params_size); if (err) - brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err); + brcmf_err("WLC_SET_SSID failed (%d)\n", err); done: if (err) @@ -2200,7 +1937,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, goto done; } /* Report the current tx rate */ - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); if (err) { brcmf_err("Could not get rate (%d)\n", err); goto done; @@ -2445,10 +2182,78 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) return vif->mode == WL_MODE_IBSS; } -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, - struct brcmf_if *ifp) +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag + */ +static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) { - struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); + struct brcmf_tlv *elt; + int totlen; + + elt = (struct brcmf_tlv *) buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) + return elt; + + elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +/* Is any of the tlvs the expected entry? If + * not update the tlvs buffer pointer/length. + */ +static bool +brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, + u8 *oui, u32 oui_len, u8 type) +{ + /* If the contents match the OUI and the type */ + if (ie[TLV_LEN_OFF] >= oui_len + 1 && + !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { + return true; + } + + if (tlvs == NULL) + return false; + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return false; +} + +static struct brcmf_vs_tlv * +brcmf_find_wpaie(u8 *parse, u32 len) +{ + struct brcmf_tlv *ie; + + while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { + if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, + WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) + return (struct brcmf_vs_tlv *)ie; + } + return NULL; +} + +static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) +{ + struct net_device *ndev = cfg_to_ndev(cfg); + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); + struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_bss_info_le *bi; struct brcmf_ssid *ssid; struct brcmf_tlv *tim; @@ -2504,7 +2309,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, return err; } -void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) +static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) { struct escan_info *escan = &cfg->escan_info; @@ -2523,7 +2328,8 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) container_of(work, struct brcmf_cfg80211_info, escan_timeout_work); - brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); + brcmf_notify_escan_complete(cfg, + cfg->escan_info.ndev, true, true); } static void brcmf_escan_timeout(unsigned long data) @@ -2600,6 +2406,11 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, brcmf_err("Invalid escan result (NULL pointer)\n"); goto exit; } + if (!cfg->scan_request) { + brcmf_dbg(SCAN, "result without cfg80211 request\n"); + goto exit; + } + if (le16_to_cpu(escan_result_le->bss_count) != 1) { brcmf_err("Invalid bss_count %d: ignoring\n", escan_result_le->bss_count); @@ -2607,14 +2418,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, } bss_info_le = &escan_result_le->bss_info_le; - if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) - goto exit; - - if (!cfg->scan_request) { - brcmf_dbg(SCAN, "result without cfg80211 request\n"); - goto exit; - } - bi_length = le32_to_cpu(bss_info_le->length); if (bi_length != (le32_to_cpu(escan_result_le->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { @@ -2653,8 +2456,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, list->count++; } else { cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) - goto exit; if (cfg->scan_request) { cfg->bss_list = (struct brcmf_scan_results *) cfg->escan_info.escan_buf; @@ -2663,8 +2464,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, brcmf_notify_escan_complete(cfg, ndev, aborted, false); } else - brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n", - status); + brcmf_err("Unexpected scan result 0x%x\n", status); } exit: return err; @@ -3168,8 +2968,9 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) } #endif -static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) +static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx) { + struct brcmf_if *ifp = netdev_priv(ndev); s32 err; /* set auth */ @@ -3428,7 +3229,7 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, parsed_info->vndrie.oui[2], parsed_info->vndrie.oui_type); - if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT) + if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) break; next: remaining_len -= (ie->len + TLV_HDR_LEN); @@ -3462,6 +3263,7 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) return ie_len + VNDR_IE_HDR_SIZE; } +static s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, const u8 *vndr_ie_buf, u32 vndr_ie_len) { @@ -3493,28 +3295,24 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, if (!iovar_ie_buf) return -ENOMEM; curr_ie_buf = iovar_ie_buf; - switch (pktflag) { - case BRCMF_VNDR_IE_PRBREQ_FLAG: - mgmt_ie_buf = saved_ie->probe_req_ie; - mgmt_ie_len = &saved_ie->probe_req_ie_len; - mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie); - break; - case BRCMF_VNDR_IE_PRBRSP_FLAG: - mgmt_ie_buf = saved_ie->probe_res_ie; - mgmt_ie_len = &saved_ie->probe_res_ie_len; - mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); - break; - case BRCMF_VNDR_IE_BEACON_FLAG: - mgmt_ie_buf = saved_ie->beacon_ie; - mgmt_ie_len = &saved_ie->beacon_ie_len; - mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); - break; - case BRCMF_VNDR_IE_ASSOCREQ_FLAG: - mgmt_ie_buf = saved_ie->assoc_req_ie; - mgmt_ie_len = &saved_ie->assoc_req_ie_len; - mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie); - break; - default: + if (ifp->vif->mode == WL_MODE_AP) { + switch (pktflag) { + case VNDR_IE_PRBRSP_FLAG: + mgmt_ie_buf = saved_ie->probe_res_ie; + mgmt_ie_len = &saved_ie->probe_res_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); + break; + case VNDR_IE_BEACON_FLAG: + mgmt_ie_buf = saved_ie->beacon_ie; + mgmt_ie_len = &saved_ie->beacon_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); + break; + default: + err = -EPERM; + brcmf_err("not suitable type\n"); + goto exit; + } + } else { err = -EPERM; brcmf_err("not suitable type\n"); goto exit; @@ -3623,49 +3421,6 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, return err; } -s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif) -{ - s32 pktflags[] = { - BRCMF_VNDR_IE_PRBREQ_FLAG, - BRCMF_VNDR_IE_PRBRSP_FLAG, - BRCMF_VNDR_IE_BEACON_FLAG - }; - int i; - - for (i = 0; i < ARRAY_SIZE(pktflags); i++) - brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0); - - memset(&vif->saved_ie, 0, sizeof(vif->saved_ie)); - return 0; -} - -static s32 -brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, - struct cfg80211_beacon_data *beacon) -{ - s32 err; - - /* Set Beacon IEs to FW */ - err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG, - beacon->tail, beacon->tail_len); - if (err) { - brcmf_err("Set Beacon IE Failed\n"); - return err; - } - brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); - - /* Set Probe Response IEs to FW */ - err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG, - beacon->proberesp_ies, - beacon->proberesp_ies_len); - if (err) - brcmf_err("Set Probe Resp IE Failed\n"); - else - brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); - - return err; -} - static s32 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *settings) @@ -3678,8 +3433,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_tlv *rsn_ie; struct brcmf_vs_tlv *wpa_ie; struct brcmf_join_params join_params; - enum nl80211_iftype dev_role; - struct brcmf_fil_bss_enable_le bss_enable; + s32 bssidx = 0; brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", cfg80211_get_chandef_type(&settings->chandef), @@ -3689,7 +3443,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, settings->ssid, settings->ssid_len, settings->auth_type, settings->inactivity_timeout); - dev_role = ifp->vif->wdev.iftype; + if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) { + brcmf_err("Not in AP creation mode\n"); + return -EPERM; + } memset(&ssid_le, 0, sizeof(ssid_le)); if (settings->ssid == NULL || settings->ssid_len == 0) { @@ -3710,6 +3467,21 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, } brcmf_set_mpc(ndev, 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); + if (err < 0) { + brcmf_err("BRCMF_C_DOWN error %d\n", err); + goto exit; + } + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); + if (err < 0) { + brcmf_err("SET INFRA error %d\n", err); + goto exit; + } + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); + if (err < 0) { + brcmf_err("setting AP mode failed %d\n", err); + goto exit; + } /* find the RSN_IE */ rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, @@ -3735,10 +3507,27 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, } } else { brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); - brcmf_configure_opensecurity(ifp); + brcmf_configure_opensecurity(ndev, bssidx); } + /* Set Beacon IEs to FW */ + err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), + VNDR_IE_BEACON_FLAG, + settings->beacon.tail, + settings->beacon.tail_len); + if (err) + brcmf_err("Set Beacon IE Failed\n"); + else + brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); - brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); + /* Set Probe Response IEs to FW */ + err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), + VNDR_IE_PRBRSP_FLAG, + settings->beacon.proberesp_ies, + settings->beacon.proberesp_ies_len); + if (err) + brcmf_err("Set Probe Resp IE Failed\n"); + else + brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); if (settings->beacon_interval) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, @@ -3756,61 +3545,21 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, goto exit; } } - - if (dev_role == NL80211_IFTYPE_AP) { - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); - if (err < 0) { - brcmf_err("BRCMF_C_DOWN error %d\n", err); - goto exit; - } - brcmf_fil_iovar_int_set(ifp, "apsta", 0); - } - - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) { - brcmf_err("SET INFRA error %d\n", err); + brcmf_err("BRCMF_C_UP error (%d)\n", err); goto exit; } - if (dev_role == NL80211_IFTYPE_AP) { - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); - if (err < 0) { - brcmf_err("setting AP mode failed %d\n", err); - goto exit; - } - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); - if (err < 0) { - brcmf_err("BRCMF_C_UP error (%d)\n", err); - goto exit; - } - - memset(&join_params, 0, sizeof(join_params)); - /* join parameters starts with ssid */ - memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); - /* create softap */ - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, - &join_params, sizeof(join_params)); - if (err < 0) { - brcmf_err("SET SSID error (%d)\n", err); - goto exit; - } - brcmf_dbg(TRACE, "AP mode configuration complete\n"); - } else { - err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, - sizeof(ssid_le)); - if (err < 0) { - brcmf_err("setting ssid failed %d\n", err); - goto exit; - } - bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); - bss_enable.enable = cpu_to_le32(1); - err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, - sizeof(bss_enable)); - if (err < 0) { - brcmf_err("bss_enable config failed %d\n", err); - goto exit; - } - brcmf_dbg(TRACE, "GO mode configuration complete\n"); + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); + /* create softap */ + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, + &join_params, sizeof(join_params)); + if (err < 0) { + brcmf_err("SET SSID error (%d)\n", err); + goto exit; } clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); @@ -3825,11 +3574,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); s32 err = -EPERM; - struct brcmf_fil_bss_enable_le bss_enable; brcmf_dbg(TRACE, "Enter\n"); - if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { /* Due to most likely deauths outstanding we sleep */ /* first to make sure they get processed by fw. */ msleep(400); @@ -3843,41 +3591,18 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) brcmf_err("BRCMF_C_UP error %d\n", err); goto exit; } - } else { - bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); - bss_enable.enable = cpu_to_le32(0); - err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, - sizeof(bss_enable)); - if (err < 0) - brcmf_err("bss_enable config failed %d\n", err); + brcmf_set_mpc(ndev, 1); + clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); } - brcmf_set_mpc(ndev, 1); - set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); - clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); - exit: return err; } -static s32 -brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_beacon_data *info) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - s32 err; - - brcmf_dbg(TRACE, "Enter\n"); - - err = brcmf_config_ap_mgmt_ie(ifp->vif, info); - - return err; -} - static int brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_scb_val_le scbval; struct brcmf_if *ifp = netdev_priv(ndev); s32 err; @@ -3887,8 +3612,6 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(TRACE, "Enter %pM\n", mac); - if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) - ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; if (!check_vif_up(ifp->vif)) return -EIO; @@ -3903,147 +3626,7 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, return err; } - -static void -brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, - struct wireless_dev *wdev, - u16 frame_type, bool reg) -{ - struct brcmf_if *ifp = netdev_priv(wdev->netdev); - struct brcmf_cfg80211_vif *vif = ifp->vif; - u16 mgmt_type; - - brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg); - - mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; - if (reg) - vif->mgmt_rx_reg |= BIT(mgmt_type); - else - vif->mgmt_rx_reg &= ~BIT(mgmt_type); -} - - -static int -brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, - struct ieee80211_channel *chan, bool offchan, - unsigned int wait, const u8 *buf, size_t len, - bool no_cck, bool dont_wait_for_ack, u64 *cookie) -{ - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - const struct ieee80211_mgmt *mgmt; - struct brcmf_if *ifp; - struct brcmf_cfg80211_vif *vif; - s32 err = 0; - s32 ie_offset; - s32 ie_len; - struct brcmf_fil_action_frame_le *action_frame; - struct brcmf_fil_af_params_le *af_params; - bool ack; - s32 chan_nr; - - brcmf_dbg(TRACE, "Enter\n"); - - *cookie = 0; - - mgmt = (const struct ieee80211_mgmt *)buf; - - if (!ieee80211_is_mgmt(mgmt->frame_control)) { - brcmf_err("Driver only allows MGMT packet type\n"); - return -EPERM; - } - - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - /* Right now the only reason to get a probe response */ - /* is for p2p listen response or for p2p GO from */ - /* wpa_supplicant. Unfortunately the probe is send */ - /* on primary ndev, while dongle wants it on the p2p */ - /* vif. Since this is only reason for a probe */ - /* response to be sent, the vif is taken from cfg. */ - /* If ever desired to send proberesp for non p2p */ - /* response then data should be checked for */ - /* "DIRECT-". Note in future supplicant will take */ - /* dedicated p2p wdev to do this and then this 'hack'*/ - /* is not needed anymore. */ - ie_offset = DOT11_MGMT_HDR_LEN + - DOT11_BCN_PRB_FIXED_LEN; - ie_len = len - ie_offset; - ifp = netdev_priv(wdev->netdev); - vif = ifp->vif; - if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) - vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - err = brcmf_vif_set_mgmt_ie(vif, - BRCMF_VNDR_IE_PRBRSP_FLAG, - &buf[ie_offset], - ie_len); - cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, - GFP_KERNEL); - } else if (ieee80211_is_action(mgmt->frame_control)) { - af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); - if (af_params == NULL) { - brcmf_err("unable to allocate frame\n"); - err = -ENOMEM; - goto exit; - } - action_frame = &af_params->action_frame; - /* Add the packet Id */ - action_frame->packet_id = cpu_to_le32(*cookie); - /* Add BSSID */ - memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN); - memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN); - /* Add the length exepted for 802.11 header */ - action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); - /* Add the channel */ - chan_nr = ieee80211_frequency_to_channel(chan->center_freq); - af_params->channel = cpu_to_le32(chan_nr); - - memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], - le16_to_cpu(action_frame->len)); - - brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n", - *cookie, le16_to_cpu(action_frame->len), - chan->center_freq); - - ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev, - af_params); - - cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, - GFP_KERNEL); - kfree(af_params); - } else { - brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); - brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len); - } - -exit: - return err; -} - - -static int -brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, - struct wireless_dev *wdev, - u64 cookie) -{ - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_vif *vif; - int err = 0; - - brcmf_dbg(TRACE, "Enter p2p listen cancel\n"); - - vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - if (vif == NULL) { - brcmf_err("No p2p device available for probe response\n"); - err = -ENODEV; - goto exit; - } - brcmf_p2p_cancel_remain_on_channel(vif->ifp); -exit: - return err; -} - static struct cfg80211_ops wl_cfg80211_ops = { - .add_virtual_intf = brcmf_cfg80211_add_iface, - .del_virtual_intf = brcmf_cfg80211_del_iface, .change_virtual_intf = brcmf_cfg80211_change_iface, .scan = brcmf_cfg80211_scan, .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, @@ -4067,43 +3650,28 @@ static struct cfg80211_ops wl_cfg80211_ops = { .flush_pmksa = brcmf_cfg80211_flush_pmksa, .start_ap = brcmf_cfg80211_start_ap, .stop_ap = brcmf_cfg80211_stop_ap, - .change_beacon = brcmf_cfg80211_change_beacon, .del_station = brcmf_cfg80211_del_station, .sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, - .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, - .mgmt_tx = brcmf_cfg80211_mgmt_tx, - .remain_on_channel = brcmf_p2p_remain_on_channel, - .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, #ifdef CONFIG_NL80211_TESTMODE .testmode_cmd = brcmf_cfg80211_testmode #endif }; -static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) +static s32 brcmf_mode_to_nl80211_iftype(s32 mode) { - switch (type) { - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_MESH_POINT: - return -ENOTSUPP; - case NL80211_IFTYPE_ADHOC: - return WL_MODE_IBSS; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - return WL_MODE_BSS; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - return WL_MODE_AP; - case NL80211_IFTYPE_P2P_DEVICE: - return WL_MODE_P2P; - case NL80211_IFTYPE_UNSPECIFIED: + s32 err = 0; + + switch (mode) { + case WL_MODE_BSS: + return NL80211_IFTYPE_STATION; + case WL_MODE_IBSS: + return NL80211_IFTYPE_ADHOC; default: - break; + return NL80211_IFTYPE_UNSPECIFIED; } - return -EINVAL; + return err; } static void brcmf_wiphy_pno_params(struct wiphy *wiphy) @@ -4115,56 +3683,6 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; } -static const struct ieee80211_iface_limit brcmf_iface_limits[] = { - { - .max = 2, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) - }, -}; -static const struct ieee80211_iface_combination brcmf_iface_combos[] = { - { - .max_interfaces = BRCMF_IFACE_MAX_CNT, - .num_different_channels = 1, /* no multi-channel for now */ - .n_limits = ARRAY_SIZE(brcmf_iface_limits), - .limits = brcmf_iface_limits - } -}; - -static const struct ieee80211_txrx_stypes -brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { - [NL80211_IFTYPE_STATION] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_P2P_CLIENT] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_P2P_GO] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - } -}; - static struct wiphy *brcmf_setup_wiphy(struct device *phydev) { struct wiphy *wiphy; @@ -4177,16 +3695,10 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) } set_wiphy_dev(wiphy, phydev); wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; - wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_DEVICE); - wiphy->iface_combinations = brcmf_iface_combos; - wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); + BIT(NL80211_IFTYPE_AP); wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set * it as 11a by default. @@ -4198,11 +3710,10 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = __wl_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); - wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | - WIPHY_FLAG_OFFCHAN_TX | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->mgmt_stypes = brcmf_txrx_stypes; - wiphy->max_remain_on_channel_duration = 5000; + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power + * save mode + * by default + */ brcmf_wiphy_pno_params(wiphy); err = wiphy_register(wiphy); if (err < 0) { @@ -4213,25 +3724,31 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) return wiphy; } +static struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - enum nl80211_iftype type, - bool pm_block) + struct net_device *netdev, + s32 mode, bool pm_block) { struct brcmf_cfg80211_vif *vif; if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) return ERR_PTR(-ENOSPC); - brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", - sizeof(*vif)); vif = kzalloc(sizeof(*vif), GFP_KERNEL); if (!vif) return ERR_PTR(-ENOMEM); vif->wdev.wiphy = cfg->wiphy; - vif->wdev.iftype = type; + vif->wdev.netdev = netdev; + vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode); + + if (netdev) { + vif->ifp = netdev_priv(netdev); + netdev->ieee80211_ptr = &vif->wdev; + SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy)); + } - vif->mode = brcmf_nl80211_iftype_to_mode(type); + vif->mode = mode; vif->pm_block = pm_block; vif->roam_off = -1; @@ -4242,7 +3759,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, return vif; } -void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) +static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) { struct brcmf_cfg80211_info *cfg; struct wiphy *wiphy; @@ -4316,9 +3833,9 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) conn_info->resp_ie_len = 0; } -static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, - struct brcmf_if *ifp) +static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) { + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct brcmf_cfg80211_assoc_ielen_le *assoc_info; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); u32 req_len; @@ -4394,9 +3911,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, brcmf_dbg(TRACE, "Enter\n"); - brcmf_get_assoc_ies(cfg, ifp); + brcmf_get_assoc_ies(cfg); memcpy(profile->bssid, e->addr, ETH_ALEN); - brcmf_update_bss_info(cfg, ifp); + brcmf_update_bss_info(cfg); buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); if (buf == NULL) { @@ -4451,11 +3968,9 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { if (completed) { - brcmf_get_assoc_ies(cfg, ifp); + brcmf_get_assoc_ies(cfg); memcpy(profile->bssid, e->addr, ETH_ALEN); - brcmf_update_bss_info(cfg, ifp); - set_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state); + brcmf_update_bss_info(cfg); } cfg80211_connect_result(ndev, (u8 *)profile->bssid, @@ -4466,6 +3981,9 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); + if (completed) + set_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state); brcmf_dbg(CONN, "Report connect result - connection %s\n", completed ? "succeeded" : "failed"); } @@ -4478,38 +3996,38 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { - static int generation; + s32 err = 0; u32 event = e->event_code; u32 reason = e->reason; + u32 len = e->datalen; + static int generation; + struct station_info sinfo; brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); - if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS && - ndev != cfg_to_ndev(cfg)) { - brcmf_dbg(CONN, "AP mode link down\n"); - complete(&cfg->vif_disabled); - return 0; - } + memset(&sinfo, 0, sizeof(sinfo)); + sinfo.filled = 0; if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && - (reason == BRCMF_E_STATUS_SUCCESS)) { - memset(&sinfo, 0, sizeof(sinfo)); + reason == BRCMF_E_STATUS_SUCCESS) { sinfo.filled = STATION_INFO_ASSOC_REQ_IES; if (!data) { brcmf_err("No IEs present in ASSOC/REASSOC_IND"); return -EINVAL; } sinfo.assoc_req_ies = data; - sinfo.assoc_req_ies_len = e->datalen; + sinfo.assoc_req_ies_len = len; generation++; sinfo.generation = generation; - cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL); + cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC); } else if ((event == BRCMF_E_DISASSOC_IND) || (event == BRCMF_E_DEAUTH_IND) || (event == BRCMF_E_DEAUTH)) { - cfg80211_del_sta(ndev, e->addr, GFP_KERNEL); + generation++; + sinfo.generation = generation; + cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC); } - return 0; + return err; } static s32 @@ -4546,8 +4064,6 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, } brcmf_link_down(ifp->vif); brcmf_init_prof(ndev_to_prof(ndev)); - if (ndev != cfg_to_ndev(cfg)) - complete(&cfg->vif_disabled); } else if (brcmf_is_nonetwork(cfg, e)) { if (brcmf_is_ibssmode(ifp->vif)) clear_bit(BRCMF_VIF_STATUS_CONNECTING, @@ -4596,57 +4112,6 @@ brcmf_notify_mic_status(struct brcmf_if *ifp, return 0; } -static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, - const struct brcmf_event_msg *e, void *data) -{ - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data; - struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; - struct brcmf_cfg80211_vif *vif; - - brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n", - ifevent->action, ifevent->flags, ifevent->ifidx, - ifevent->bssidx); - - mutex_lock(&event->vif_event_lock); - event->action = ifevent->action; - vif = event->vif; - - switch (ifevent->action) { - case BRCMF_E_IF_ADD: - /* waiting process may have timed out */ - if (!cfg->vif_event.vif) - return -EBADF; - - ifp->vif = vif; - vif->ifp = ifp; - vif->wdev.netdev = ifp->ndev; - ifp->ndev->ieee80211_ptr = &vif->wdev; - SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy)); - mutex_unlock(&event->vif_event_lock); - wake_up(&event->vif_wq); - return 0; - - case BRCMF_E_IF_DEL: - ifp->vif = NULL; - mutex_unlock(&event->vif_event_lock); - /* event may not be upon user request */ - if (brcmf_cfg80211_vif_event_armed(cfg)) - wake_up(&event->vif_wq); - return 0; - - case BRCMF_E_IF_CHANGE: - mutex_unlock(&event->vif_event_lock); - wake_up(&event->vif_wq); - return 0; - - default: - mutex_unlock(&event->vif_event_lock); - break; - } - return -EINVAL; -} - static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { conf->frag_threshold = (u32)-1; @@ -4678,18 +4143,6 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) brcmf_notify_connect_status); brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, brcmf_notify_sched_scan_results); - brcmf_fweh_register(cfg->pub, BRCMF_E_IF, - brcmf_notify_vif_event); - brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG, - brcmf_p2p_notify_rx_mgmt_p2p_probereq); - brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE, - brcmf_p2p_notify_listen_complete); - brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX, - brcmf_p2p_notify_action_frame_rx); - brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE, - brcmf_p2p_notify_action_tx_complete); - brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, - brcmf_p2p_notify_action_tx_complete); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) @@ -4745,7 +4198,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) mutex_init(&cfg->usr_sync); brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); - init_completion(&cfg->vif_disabled); + return err; } @@ -4756,12 +4209,6 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) brcmf_deinit_priv_mem(cfg); } -static void init_vif_event(struct brcmf_cfg80211_vif_event *event) -{ - init_waitqueue_head(&event->vif_wq); - mutex_init(&event->vif_event_lock); -} - struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, struct device *busdev) { @@ -4785,41 +4232,25 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, cfg = wiphy_priv(wiphy); cfg->wiphy = wiphy; cfg->pub = drvr; - init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); - vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); + vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false); if (IS_ERR(vif)) { wiphy_free(wiphy); return NULL; } - vif->ifp = ifp; - vif->wdev.netdev = ndev; - ndev->ieee80211_ptr = &vif->wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); - err = wl_init_priv(cfg); if (err) { brcmf_err("Failed to init iwm_priv (%d)\n", err); goto cfg80211_attach_out; } - ifp->vif = vif; - - err = brcmf_p2p_attach(cfg); - if (err) { - brcmf_err("P2P initilisation failed (%d)\n", err); - goto cfg80211_p2p_attach_out; - } + ifp->vif = vif; return cfg; -cfg80211_p2p_attach_out: - wl_deinit_priv(cfg); - cfg80211_attach_out: brcmf_free_vif(vif); - wiphy_free(wiphy); return NULL; } @@ -5058,57 +4489,3 @@ s32 brcmf_cfg80211_down(struct net_device *ndev) return err; } -u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state) -{ - struct brcmf_cfg80211_vif *vif; - bool result = 0; - - list_for_each_entry(vif, &cfg->vif_list, list) { - if (test_bit(state, &vif->sme_state)) - result++; - } - return result; -} - -static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event, - u8 action) -{ - u8 evt_action; - - mutex_lock(&event->vif_event_lock); - evt_action = event->action; - mutex_unlock(&event->vif_event_lock); - return evt_action == action; -} - -void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, - struct brcmf_cfg80211_vif *vif) -{ - struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; - - mutex_lock(&event->vif_event_lock); - event->vif = vif; - event->action = 0; - mutex_unlock(&event->vif_event_lock); -} - -bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; - bool armed; - - mutex_lock(&event->vif_event_lock); - armed = event->vif != NULL; - mutex_unlock(&event->vif_event_lock); - - return armed; -} -int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, - u8 action, ulong timeout) -{ - struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; - - return wait_event_timeout(event->vif_wq, - vif_event_equals(event, action), timeout); -} - diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 8b5d4989906c..e4d9cc7a8e63 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -41,38 +41,6 @@ #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ #define IE_MAX_LEN 512 -/* IE TLV processing */ -#define TLV_LEN_OFF 1 /* length offset */ -#define TLV_HDR_LEN 2 /* header length */ -#define TLV_BODY_OFF 2 /* body offset */ -#define TLV_OUI_LEN 3 /* oui id length */ - -/* 802.11 Mgmt Packet flags */ -#define BRCMF_VNDR_IE_BEACON_FLAG 0x1 -#define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2 -#define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4 -#define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8 -#define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10 -#define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20 -/* vendor IE in IW advertisement protocol ID field */ -#define BRCMF_VNDR_IE_IWAPID_FLAG 0x40 -/* allow custom IE id */ -#define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100 - -/* P2P Action Frames flags (spec ordered) */ -#define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000 -#define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000 -#define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000 -#define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000 -#define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000 -#define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000 -#define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000 -#define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000 -#define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000 - -#define BRCMF_VNDR_IE_P2PAF_SHIFT 12 - - /** * enum brcmf_scan_status - dongle scan status * @@ -84,19 +52,11 @@ enum brcmf_scan_status { BRCMF_SCAN_STATUS_ABORT, }; -/** - * enum wl_mode - driver mode of virtual interface. - * - * @WL_MODE_BSS: connects to BSS. - * @WL_MODE_IBSS: operate as ad-hoc. - * @WL_MODE_AP: operate as access-point. - * @WL_MODE_P2P: provide P2P discovery. - */ +/* wi-fi mode */ enum wl_mode { WL_MODE_BSS, WL_MODE_IBSS, - WL_MODE_AP, - WL_MODE_P2P + WL_MODE_AP }; /* dongle configuration */ @@ -148,7 +108,6 @@ struct brcmf_cfg80211_profile { * @BRCMF_VIF_STATUS_READY: ready for operation. * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. - * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. */ @@ -156,7 +115,6 @@ enum brcmf_vif_status { BRCMF_VIF_STATUS_READY, BRCMF_VIF_STATUS_CONNECTING, BRCMF_VIF_STATUS_CONNECTED, - BRCMF_VIF_STATUS_DISCONNECTING, BRCMF_VIF_STATUS_AP_CREATING, BRCMF_VIF_STATUS_AP_CREATED }; @@ -164,22 +122,16 @@ enum brcmf_vif_status { /** * struct vif_saved_ie - holds saved IEs for a virtual interface. * - * @probe_req_ie: IE info for probe request. * @probe_res_ie: IE info for probe response. * @beacon_ie: IE info for beacon frame. - * @probe_req_ie_len: IE info length for probe request. * @probe_res_ie_len: IE info length for probe response. * @beacon_ie_len: IE info length for beacon frame. */ struct vif_saved_ie { - u8 probe_req_ie[IE_MAX_LEN]; u8 probe_res_ie[IE_MAX_LEN]; u8 beacon_ie[IE_MAX_LEN]; - u8 assoc_req_ie[IE_MAX_LEN]; - u32 probe_req_ie_len; u32 probe_res_ie_len; u32 beacon_ie_len; - u32 assoc_req_ie_len; }; /** @@ -193,7 +145,6 @@ struct vif_saved_ie { * @sme_state: SME state using enum brcmf_vif_status bits. * @pm_block: power-management blocked. * @list: linked list. - * @mgmt_rx_reg: registered rx mgmt frame types. */ struct brcmf_cfg80211_vif { struct brcmf_if *ifp; @@ -205,7 +156,6 @@ struct brcmf_cfg80211_vif { bool pm_block; struct vif_saved_ie saved_ie; struct list_head list; - u16 mgmt_rx_reg; }; /* association inform */ @@ -239,9 +189,6 @@ struct escan_info { u8 escan_buf[WL_ESCAN_BUF_SIZE]; struct wiphy *wiphy; struct net_device *ndev; - s32 (*run)(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - struct cfg80211_scan_request *request, u16 action); }; /** @@ -325,28 +272,11 @@ struct brcmf_pno_scanresults_le { __le32 count; }; -/** - * struct brcmf_cfg80211_vif_event - virtual interface event information. - * - * @vif_wq: waitqueue awaiting interface event from firmware. - * @vif_event_lock: protects other members in this structure. - * @vif_complete: completion for net attach. - * @action: either add, change, or delete. - * @vif: virtual interface object related to the event. - */ -struct brcmf_cfg80211_vif_event { - wait_queue_head_t vif_wq; - struct mutex vif_event_lock; - u8 action; - struct brcmf_cfg80211_vif *vif; -}; - /** * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface * * @wiphy: wiphy object for cfg80211 interface. * @conf: dongle configuration. - * @p2p: peer-to-peer specific information. * @scan_request: cfg80211 scan request object. * @usr_sync: mainly for dongle up/down synchronization. * @bss_list: bss_list holding scanned ap information. @@ -374,12 +304,10 @@ struct brcmf_cfg80211_vif_event { * @escan_ioctl_buf: dongle command buffer for escan commands. * @vif_list: linked list of vif instances. * @vif_cnt: number of vif instances. - * @vif_event: vif event signalling. */ struct brcmf_cfg80211_info { struct wiphy *wiphy; struct brcmf_cfg80211_conf *conf; - struct brcmf_p2p_info p2p; struct cfg80211_scan_request *scan_request; struct mutex usr_sync; struct brcmf_scan_results *bss_list; @@ -407,21 +335,6 @@ struct brcmf_cfg80211_info { u8 *escan_ioctl_buf; struct list_head vif_list; u8 vif_cnt; - struct brcmf_cfg80211_vif_event vif_event; - struct completion vif_disabled; -}; - -/** - * struct brcmf_tlv - tag_ID/length/value_buffer tuple. - * - * @id: tag identifier. - * @len: number of bytes in value buffer. - * @data: value buffer. - */ -struct brcmf_tlv { - u8 id; - u8 len; - u8 data[1]; }; static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) @@ -476,26 +389,4 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); s32 brcmf_cfg80211_up(struct net_device *ndev); s32 brcmf_cfg80211_down(struct net_device *ndev); -struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - enum nl80211_iftype type, - bool pm_block); -void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); - -s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, - const u8 *vndr_ie_buf, u32 vndr_ie_len); -s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); -struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); -u16 channel_to_chanspec(struct ieee80211_channel *ch); -u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); -void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, - struct brcmf_cfg80211_vif *vif); -bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); -int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, - u8 action, ulong timeout); -s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - bool aborted, bool fw_abort); -void brcmf_set_mpc(struct net_device *ndev, int mpc); -void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); - #endif /* _wl_cfg80211_h_ */ diff --git a/trunk/drivers/net/wireless/brcm80211/brcmsmac/main.c b/trunk/drivers/net/wireless/brcm80211/brcmsmac/main.c index 0985925cd3f4..c26992a60e6c 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -101,6 +101,8 @@ #define DOT11_RTS_LEN 16 #define DOT11_CTS_LEN 10 #define DOT11_BA_BITMAP_LEN 128 +#define DOT11_MIN_BEACON_PERIOD 1 +#define DOT11_MAX_BEACON_PERIOD 0xFFFF #define DOT11_MAXNUMFRAGS 16 #define DOT11_MAX_FRAG_LEN 2346 @@ -5553,7 +5555,8 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) { - if (period == 0) + if (period < DOT11_MIN_BEACON_PERIOD || + period > DOT11_MAX_BEACON_PERIOD) return -EINVAL; wlc->default_bss->beacon_period = period; @@ -7405,13 +7408,9 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg, bool suspend) { - u16 *prb_resp; + u16 prb_resp[BCN_TMPL_LEN / 2]; int len = BCN_TMPL_LEN; - prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC); - if (!prb_resp) - return; - /* * write the probe response to hardware, or save in * the config structure @@ -7445,8 +7444,6 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, if (suspend) brcms_c_enable_mac(wlc); - - kfree(prb_resp); } void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) diff --git a/trunk/drivers/net/wireless/iwlegacy/3945-mac.c b/trunk/drivers/net/wireless/iwlegacy/3945-mac.c index 83856d1a6101..050ce7c70d74 100644 --- a/trunk/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/trunk/drivers/net/wireless/iwlegacy/3945-mac.c @@ -1001,12 +1001,12 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) struct list_head *element; struct il_rx_buf *rxb; struct page *page; - dma_addr_t page_dma; unsigned long flags; gfp_t gfp_mask = priority; while (1) { spin_lock_irqsave(&rxq->lock, flags); + if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); return; @@ -1035,34 +1035,26 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority) break; } - /* Get physical address of RB/SKB */ - page_dma = - pci_map_page(il->pci_dev, page, 0, - PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - - if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { - __free_pages(page, il->hw_params.rx_page_order); - break; - } - spin_lock_irqsave(&rxq->lock, flags); - if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - pci_unmap_page(il->pci_dev, page_dma, - PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); __free_pages(page, il->hw_params.rx_page_order); return; } - element = rxq->rx_used.next; rxb = list_entry(element, struct il_rx_buf, list); list_del(element); + spin_unlock_irqrestore(&rxq->lock, flags); rxb->page = page; - rxb->page_dma = page_dma; + /* Get physical address of RB/SKB */ + rxb->page_dma = + pci_map_page(il->pci_dev, page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; il->alloc_rxb_page++; @@ -1292,15 +1284,8 @@ il3945_rx_handle(struct il_priv *il) pci_map_page(il->pci_dev, rxb->page, 0, PAGE_SIZE << il->hw_params. rx_page_order, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, - rxb->page_dma))) { - __il_free_pages(il, rxb->page); - rxb->page = NULL; - list_add_tail(&rxb->list, &rxq->rx_used); - } else { - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; } else list_add_tail(&rxb->list, &rxq->rx_used); diff --git a/trunk/drivers/net/wireless/iwlegacy/4965-mac.c b/trunk/drivers/net/wireless/iwlegacy/4965-mac.c index 835662a449da..d3cc776d2d34 100644 --- a/trunk/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/trunk/drivers/net/wireless/iwlegacy/4965-mac.c @@ -319,7 +319,6 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) struct list_head *element; struct il_rx_buf *rxb; struct page *page; - dma_addr_t page_dma; unsigned long flags; gfp_t gfp_mask = priority; @@ -357,35 +356,33 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority) return; } - /* Get physical address of the RB */ - page_dma = - pci_map_page(il->pci_dev, page, 0, - PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) { - __free_pages(page, il->hw_params.rx_page_order); - break; - } - spin_lock_irqsave(&rxq->lock, flags); if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - pci_unmap_page(il->pci_dev, page_dma, - PAGE_SIZE << il->hw_params.rx_page_order, - PCI_DMA_FROMDEVICE); __free_pages(page, il->hw_params.rx_page_order); return; } - element = rxq->rx_used.next; rxb = list_entry(element, struct il_rx_buf, list); list_del(element); - BUG_ON(rxb->page); + spin_unlock_irqrestore(&rxq->lock, flags); + BUG_ON(rxb->page); rxb->page = page; - rxb->page_dma = page_dma; + /* Get physical address of the RB */ + rxb->page_dma = + pci_map_page(il->pci_dev, page, 0, + PAGE_SIZE << il->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + /* dma address must be no more than 36 bits */ + BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); + /* and also 256 byte aligned! */ + BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); + + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; il->alloc_rxb_page++; @@ -728,16 +725,6 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status.flag |= RX_FLAG_SHORT_GI; - if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) { - /* We know which subframes of an A-MPDU belong - * together since we get a single PHY response - * from the firmware for all of them. - */ - - rx_status.flag |= RX_FLAG_AMPDU_DETAILS; - rx_status.ampdu_reference = il->_4965.ampdu_ref; - } - il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb, &rx_status); } @@ -749,7 +736,6 @@ il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb) { struct il_rx_pkt *pkt = rxb_addr(rxb); il->_4965.last_phy_res_valid = true; - il->_4965.ampdu_ref++; memcpy(&il->_4965.last_phy_res, pkt->u.raw, sizeof(struct il_rx_phy_res)); } @@ -4295,16 +4281,8 @@ il4965_rx_handle(struct il_priv *il) pci_map_page(il->pci_dev, rxb->page, 0, PAGE_SIZE << il->hw_params. rx_page_order, PCI_DMA_FROMDEVICE); - - if (unlikely(pci_dma_mapping_error(il->pci_dev, - rxb->page_dma))) { - __il_free_pages(il, rxb->page); - rxb->page = NULL; - list_add_tail(&rxb->list, &rxq->rx_used); - } else { - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; } else list_add_tail(&rxb->list, &rxq->rx_used); @@ -6595,6 +6573,9 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free_eeprom; + if (err) + goto out_free_eeprom; + /* extract MAC Address */ il4965_eeprom_get_mac(il, il->addresses[0].addr); D_INFO("MAC address: %pM\n", il->addresses[0].addr); diff --git a/trunk/drivers/net/wireless/iwlegacy/4965.c b/trunk/drivers/net/wireless/iwlegacy/4965.c index 91eb2d07fdb8..5db11714e047 100644 --- a/trunk/drivers/net/wireless/iwlegacy/4965.c +++ b/trunk/drivers/net/wireless/iwlegacy/4965.c @@ -1748,6 +1748,7 @@ static void il4965_post_associate(struct il_priv *il) { struct ieee80211_vif *vif = il->vif; + struct ieee80211_conf *conf = NULL; int ret = 0; if (!vif || !il->is_open) @@ -1758,6 +1759,8 @@ il4965_post_associate(struct il_priv *il) il_scan_cancel_timeout(il, 200); + conf = &il->hw->conf; + il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; il_commit_rxon(il); diff --git a/trunk/drivers/net/wireless/iwlegacy/commands.h b/trunk/drivers/net/wireless/iwlegacy/commands.h index 3b6c99400892..25dd7d28d022 100644 --- a/trunk/drivers/net/wireless/iwlegacy/commands.h +++ b/trunk/drivers/net/wireless/iwlegacy/commands.h @@ -1134,9 +1134,8 @@ struct il_wep_cmd { #define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0x70 +#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0xf0 #define RX_RES_PHY_FLAGS_ANTENNA_POS 4 -#define RX_RES_PHY_FLAGS_AGG_MSK cpu_to_le16(1 << 7) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) diff --git a/trunk/drivers/net/wireless/iwlegacy/common.h b/trunk/drivers/net/wireless/iwlegacy/common.h index 96f2025d936e..37fe553b25e0 100644 --- a/trunk/drivers/net/wireless/iwlegacy/common.h +++ b/trunk/drivers/net/wireless/iwlegacy/common.h @@ -1356,7 +1356,6 @@ struct il_priv { struct { struct il_rx_phy_res last_phy_res; bool last_phy_res_valid; - u32 ampdu_ref; struct completion firmware_loading_complete; diff --git a/trunk/drivers/net/wireless/iwlwifi/Kconfig b/trunk/drivers/net/wireless/iwlwifi/Kconfig index ba319cba3f1e..5cf43236421e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Kconfig +++ b/trunk/drivers/net/wireless/iwlwifi/Kconfig @@ -43,20 +43,8 @@ config IWLWIFI module will be called iwlwifi. config IWLDVM - tristate "Intel Wireless WiFi DVM Firmware support" + tristate "Intel Wireless WiFi" depends on IWLWIFI - help - This is the driver supporting the DVM firmware which is - currently the only firmware available for existing devices. - -config IWLMVM - tristate "Intel Wireless WiFi MVM Firmware support" - depends on IWLWIFI - help - This is the driver supporting the MVM firmware which is - currently only available for 7000 series devices. - - Say yes if you have such a device. menu "Debugging Options" depends on IWLWIFI diff --git a/trunk/drivers/net/wireless/iwlwifi/Makefile b/trunk/drivers/net/wireless/iwlwifi/Makefile index 6c7800044a04..170ec330d2a9 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Makefile +++ b/trunk/drivers/net/wireless/iwlwifi/Makefile @@ -5,10 +5,8 @@ iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-debug.o iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o -iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o -iwlwifi-objs += pcie/7000.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o @@ -17,6 +15,5 @@ ccflags-y += -D__CHECK_ENDIAN__ -I$(src) obj-$(CONFIG_IWLDVM) += dvm/ -obj-$(CONFIG_IWLMVM) += mvm/ CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/agn.h b/trunk/drivers/net/wireless/iwlwifi/dvm/agn.h index f41ae79e6bc0..33b3ad2e546b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/calib.c b/trunk/drivers/net/wireless/iwlwifi/dvm/calib.c index 6468de8634b0..de54713b680c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/calib.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/calib.h b/trunk/drivers/net/wireless/iwlwifi/dvm/calib.h index 65e920cab2b7..2349f393cc42 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/calib.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/commands.h b/trunk/drivers/net/wireless/iwlwifi/dvm/commands.h index 8bce4b0148e0..0ca99c13f7f2 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/trunk/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 20806cae11b7..72c74af38138 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/dev.h b/trunk/drivers/net/wireless/iwlwifi/dvm/dev.h index 71ea77576d22..2653a891cc7e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/devices.c b/trunk/drivers/net/wireless/iwlwifi/dvm/devices.c index 15cca2ef9294..8c72be3f37c1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/devices.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/led.c b/trunk/drivers/net/wireless/iwlwifi/dvm/led.c index 33c7e15d24f5..844a17f99a18 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/led.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/led.h b/trunk/drivers/net/wireless/iwlwifi/dvm/led.h index 8749dcfe695f..b02a853103d3 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/led.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/lib.c b/trunk/drivers/net/wireless/iwlwifi/dvm/lib.c index 86ea5f4c3939..6ff46605ad4f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/trunk/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 75f6f6cfdd47..8e5c5c5ce06f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -459,12 +459,14 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) base = priv->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) { + spin_lock_irqsave(&priv->trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(priv->trans, true)) { iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); - iwl_trans_release_nic_access(priv->trans, &flags); + iwl_trans_release_nic_access(priv->trans); ret = 0; } + spin_unlock_irqrestore(&priv->trans->reg_lock, flags); #ifdef CONFIG_IWLWIFI_DEBUGFS if (ret == 0) { diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/main.c b/trunk/drivers/net/wireless/iwlwifi/dvm/main.c index b9e3517652d6..a64f361e341c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -353,8 +353,11 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); /* Make sure device is powered up for SRAM reads */ - if (!iwl_trans_grab_nic_access(priv->trans, false, ®_flags)) + spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); + if (!iwl_trans_grab_nic_access(priv->trans, false)) { + spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); return; + } /* Set starting address; reads will auto-increment */ iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); @@ -385,7 +388,8 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, } } /* Allow device to power down */ - iwl_trans_release_nic_access(priv->trans, ®_flags); + iwl_trans_release_nic_access(priv->trans); + spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); } static void iwl_continuous_event_trace(struct iwl_priv *priv) @@ -1713,8 +1717,9 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); /* Make sure device is powered up for SRAM reads */ - if (!iwl_trans_grab_nic_access(trans, false, ®_flags)) - return pos; + spin_lock_irqsave(&trans->reg_lock, reg_flags); + if (!iwl_trans_grab_nic_access(trans, false)) + goto out_unlock; /* Set starting address; reads will auto-increment */ iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); @@ -1752,7 +1757,9 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, } /* Allow device to power down */ - iwl_trans_release_nic_access(trans, ®_flags); + iwl_trans_release_nic_access(trans); +out_unlock: + spin_unlock_irqrestore(&trans->reg_lock, reg_flags); return pos; } @@ -1984,13 +1991,13 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); /* SKU Control */ - iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | - CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, - (CSR_HW_REV_STEP(priv->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | - (CSR_HW_REV_DASH(priv->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); + iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | + CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, + (CSR_HW_REV_STEP(priv->trans->hw_rev) << + CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | + (CSR_HW_REV_DASH(priv->trans->hw_rev) << + CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); /* write radio config values to register */ if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) { @@ -2002,11 +2009,10 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) priv->nvm_data->radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; - iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | - CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | - CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, - reg_val); + iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | + CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | + CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val); IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n", priv->nvm_data->radio_cfg_type, diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/power.c b/trunk/drivers/net/wireless/iwlwifi/dvm/power.c index bd69018d07a9..518cf3715809 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/power.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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. diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/power.h b/trunk/drivers/net/wireless/iwlwifi/dvm/power.h index 7b03e1342d47..a2cee7f04848 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/power.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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. diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/rs.c b/trunk/drivers/net/wireless/iwlwifi/dvm/rs.c index a131227c49e9..f3dd0da60d8a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 @@ -411,9 +411,8 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, * BT traffic, as they would just be disrupted by BT. */ if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) { - IWL_DEBUG_COEX(priv, - "BT traffic (%d), no aggregation allowed\n", - priv->bt_traffic_load); + IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n", + priv->bt_traffic_load); return ret; } diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/rs.h b/trunk/drivers/net/wireless/iwlwifi/dvm/rs.h index 5d83cab22d62..ad3aea8f626a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/rx.c b/trunk/drivers/net/wireless/iwlwifi/dvm/rx.c index e8d5b90abf5c..cac4f37cc427 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files. diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/rxon.c b/trunk/drivers/net/wireless/iwlwifi/dvm/rxon.c index 9fabd26997ca..9a891e6e60e8 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/scan.c b/trunk/drivers/net/wireless/iwlwifi/dvm/scan.c index 3a4aa5239c45..610ed2204e1f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/sta.c b/trunk/drivers/net/wireless/iwlwifi/dvm/sta.c index ab768045696b..bdba9543c351 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/testmode.c b/trunk/drivers/net/wireless/iwlwifi/dvm/testmode.c index dc6f965a123a..57b918ce3b5f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/testmode.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/testmode.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 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) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/tt.c b/trunk/drivers/net/wireless/iwlwifi/dvm/tt.c index 67e2e1321b40..b28cfc8553d7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/tt.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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. @@ -185,8 +185,10 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) priv->thermal_throttle.ct_kill_toggle = true; } iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); - if (iwl_trans_grab_nic_access(priv->trans, false, &flags)) - iwl_trans_release_nic_access(priv->trans, &flags); + spin_lock_irqsave(&priv->trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(priv->trans, false)) + iwl_trans_release_nic_access(priv->trans); + spin_unlock_irqrestore(&priv->trans->reg_lock, flags); /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/tt.h b/trunk/drivers/net/wireless/iwlwifi/dvm/tt.h index 9356c4b908ca..44c7c8f30a2d 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/tt.h +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/tt.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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. diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/tx.c b/trunk/drivers/net/wireless/iwlwifi/dvm/tx.c index 7b0550d35a91..6b01fc195940 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/dvm/ucode.c b/trunk/drivers/net/wireless/iwlwifi/dvm/ucode.c index 736fe9bb140e..ebec13a3329f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/trunk/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index e9975c54c276..7960a52f6ad4 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-config.h b/trunk/drivers/net/wireless/iwlwifi/iwl-config.h index 743b48343358..864219d2136a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-config.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,7 +83,6 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_6030, IWL_DEVICE_FAMILY_6050, IWL_DEVICE_FAMILY_6150, - IWL_DEVICE_FAMILY_7000, }; /* diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h b/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h index df3463a38704..b419a1efac0a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h index 8cf5db7fb5c9..42b20b0e83bc 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -116,7 +116,6 @@ do { \ #define IWL_DL_HCMD 0x00000004 #define IWL_DL_STATE 0x00000008 /* 0x000000F0 - 0x00000010 */ -#define IWL_DL_TE 0x00000020 #define IWL_DL_EEPROM 0x00000040 #define IWL_DL_RADIO 0x00000080 /* 0x00000F00 - 0x00000100 */ @@ -157,7 +156,6 @@ do { \ #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) -#define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a) #define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a) #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) #define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 8f61c717f619..70191ddbd8f6 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 9a0f45ec9e01..dc7e26b2f383 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c index 6f228bb2b844..d3549f493a17 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -139,10 +139,8 @@ struct iwl_drv { #endif }; -enum { - DVM_OP_MODE = 0, - MVM_OP_MODE = 1, -}; +#define DVM_OP_MODE 0 +#define MVM_OP_MODE 1 /* Protects the table contents, i.e. the ops pointer & drv list */ static struct mutex iwlwifi_opmode_table_mtx; @@ -151,8 +149,8 @@ static struct iwlwifi_opmode_table { const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */ struct list_head drv; /* list of devices using this op_mode */ } iwlwifi_opmode_table[] = { /* ops set when driver is initialized */ - [DVM_OP_MODE] = { .name = "iwldvm", .ops = NULL }, - [MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL }, + { .name = "iwldvm", .ops = NULL }, + { .name = "iwlmvm", .ops = NULL }, }; /* @@ -270,7 +268,7 @@ struct fw_sec_parsing { */ struct iwl_tlv_calib_data { __le32 ucode_type; - struct iwl_tlv_calib_ctrl calib; + __le64 calib; } __packed; struct iwl_firmware_pieces { @@ -360,11 +358,7 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data) ucode_type); return -EINVAL; } - drv->fw.default_calib[ucode_type].flow_trigger = - def_calib->calib.flow_trigger; - drv->fw.default_calib[ucode_type].event_trigger = - def_calib->calib.event_trigger; - + drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib); return 0; } @@ -965,10 +959,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) release_firmware(ucode_raw); mutex_lock(&iwlwifi_opmode_table_mtx); - if (fw->mvm_fw) - op = &iwlwifi_opmode_table[MVM_OP_MODE]; - else - op = &iwlwifi_opmode_table[DVM_OP_MODE]; + op = &iwlwifi_opmode_table[DVM_OP_MODE]; /* add this device to the list of devices using this op_mode */ list_add_tail(&drv->list, &op->drv); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h index 594a5c71b272..285de5f68c05 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ /* for all modules */ #define DRV_NAME "iwlwifi" #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2013 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2012 Intel Corporation" #define DRV_AUTHOR "" diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 034f2ff4f43d..471986690cf0 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -703,9 +703,9 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, return n_channels; } -int iwl_init_sband_channels(struct iwl_nvm_data *data, - struct ieee80211_supported_band *sband, - int n_channels, enum ieee80211_band band) +static int iwl_init_sband_channels(struct iwl_nvm_data *data, + struct ieee80211_supported_band *sband, + int n_channels, enum ieee80211_band band) { struct ieee80211_channel *chan = &data->channels[0]; int n = 0, idx = 0; @@ -728,10 +728,10 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data, #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ -void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, - struct ieee80211_sta_ht_cap *ht_info, - enum ieee80211_band band) +static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + struct ieee80211_sta_ht_cap *ht_info, + enum ieee80211_band band) { int max_bit_rate = 0; u8 rx_chains; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index 683fe6a8c58f..555f0eb61d48 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -126,13 +126,4 @@ static inline void iwl_free_nvm_data(struct iwl_nvm_data *data) int iwl_nvm_check_version(struct iwl_nvm_data *data, struct iwl_trans *trans); -int iwl_init_sband_channels(struct iwl_nvm_data *data, - struct ieee80211_supported_band *sband, - int n_channels, enum ieee80211_band band); - -void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, - struct ieee80211_sta_ht_cap *ht_info, - enum ieee80211_band band); - #endif /* __iwl_eeprom_parse_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c index ef4806f27cf8..27c7da3c6ed1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h index b2588c5cbf93..1337c9d36fee 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h b/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h index f5592fb3b1ed..c646a90b725e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -414,7 +414,6 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) * uCode/driver must write "1" in order to clear this flag */ #define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018) -#define FH_TSSR_TX_MSG_CONFIG_REG (FH_TSSR_LOWER_BOUND + 0x008) #define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 90873eca35f7..e71564053e7f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h index de3c24a5a620..d1a86b66bc51 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -139,19 +139,6 @@ struct fw_img { #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) -/* - * Calibration control struct. - * Sent as part of the phy configuration command. - * @flow_trigger: bitmap for which calibrations to perform according to - * flow triggers. - * @event_trigger: bitmap for which calibrations to perform according to - * event triggers. - */ -struct iwl_tlv_calib_ctrl { - __le32 flow_trigger; - __le32 event_trigger; -} __packed; - /** * struct iwl_fw - variables associated with the firmware * @@ -166,7 +153,6 @@ struct iwl_tlv_calib_ctrl { * @inst_evtlog_ptr: event log offset for runtime ucode. * @inst_evtlog_size: event log size for runtime ucode. * @inst_errlog_ptr: error log offfset for runtime ucode. - * @mvm_fw: indicates this is MVM firmware */ struct iwl_fw { u32 ucode_ver; @@ -182,7 +168,7 @@ struct iwl_fw { u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; + u64 default_calib[IWL_UCODE_TYPE_MAX]; u32 phy_config; bool mvm_fw; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-io.c b/trunk/drivers/net/wireless/iwlwifi/iwl-io.c index 276410d82de4..bff3ac96c00b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -35,6 +35,54 @@ #define IWL_POLL_INTERVAL 10 /* microseconds */ +void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) +{ + iwl_write32(trans, reg, iwl_read32(trans, reg) | mask); +} + +void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) +{ + iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask); +} + +void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&trans->reg_lock, flags); + __iwl_set_bit(trans, reg, mask); + spin_unlock_irqrestore(&trans->reg_lock, flags); +} +EXPORT_SYMBOL_GPL(iwl_set_bit); + +void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&trans->reg_lock, flags); + __iwl_clear_bit(trans, reg, mask); + spin_unlock_irqrestore(&trans->reg_lock, flags); +} +EXPORT_SYMBOL_GPL(iwl_clear_bit); + +void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) +{ + unsigned long flags; + u32 v; + +#ifdef CONFIG_IWLWIFI_DEBUG + WARN_ON_ONCE(value & ~mask); +#endif + + spin_lock_irqsave(&trans->reg_lock, flags); + v = iwl_read32(trans, reg); + v &= ~mask; + v |= value; + iwl_write32(trans, reg, v); + spin_unlock_irqrestore(&trans->reg_lock, flags); +} +EXPORT_SYMBOL_GPL(iwl_set_bits_mask); + int iwl_poll_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout) { @@ -55,10 +103,13 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) { u32 value = 0x5a5a5a5a; unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { value = iwl_read32(trans, reg); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); return value; } @@ -68,10 +119,12 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { iwl_write32(trans, reg, value); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); } EXPORT_SYMBOL_GPL(iwl_write_direct32); @@ -109,10 +162,12 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) unsigned long flags; u32 val = 0x5a5a5a5a; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { val = __iwl_read_prph(trans, ofs); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); return val; } EXPORT_SYMBOL_GPL(iwl_read_prph); @@ -121,10 +176,12 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { __iwl_write_prph(trans, ofs, val); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); } EXPORT_SYMBOL_GPL(iwl_write_prph); @@ -132,11 +189,13 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { __iwl_write_prph(trans, ofs, __iwl_read_prph(trans, ofs) | mask); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); } EXPORT_SYMBOL_GPL(iwl_set_bits_prph); @@ -145,11 +204,13 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { __iwl_write_prph(trans, ofs, (__iwl_read_prph(trans, ofs) & mask) | bits); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); } EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph); @@ -158,10 +219,12 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) unsigned long flags; u32 val; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { val = __iwl_read_prph(trans, ofs); __iwl_write_prph(trans, ofs, (val & ~mask)); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } + spin_unlock_irqrestore(&trans->reg_lock, flags); } EXPORT_SYMBOL_GPL(iwl_clear_bits_prph); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-io.h b/trunk/drivers/net/wireless/iwlwifi/iwl-io.h index fd9f5b97fff3..dc478068596b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -51,15 +51,12 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs) return val; } -static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) -{ - iwl_trans_set_bits_mask(trans, reg, mask, mask); -} +void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); +void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); +void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); -static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) -{ - iwl_trans_set_bits_mask(trans, reg, mask, 0); -} +void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); int iwl_poll_bit(struct iwl_trans *trans, u32 addr, u32 bits, u32 mask, int timeout); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h b/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h index e5e3a79eae2f..d9a86d6b2bd7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index c3affbc62cdf..c61f2070f15a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index c2ce764463a3..821523100cf1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/trunk/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c deleted file mode 100644 index a70213bdb83c..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ /dev/null @@ -1,346 +0,0 @@ -/****************************************************************************** - * - * 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 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2013 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 -#include -#include -#include "iwl-modparams.h" -#include "iwl-nvm-parse.h" - -/* NVM offsets (in words) definitions */ -enum wkp_nvm_offsets { - /* NVM HW-Section offset (in words) definitions */ - HW_ADDR = 0x15, - -/* NVM SW-Section offset (in words) definitions */ - NVM_SW_SECTION = 0x1C0, - NVM_VERSION = 0, - RADIO_CFG = 1, - SKU = 2, - N_HW_ADDRS = 3, - NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, - -/* NVM calibration section offset (in words) definitions */ - NVM_CALIB_SECTION = 0x2B8, - XTAL_CALIB = 0x316 - NVM_CALIB_SECTION -}; - -/* SKU Capabilities (actual values from NVM definition) */ -enum nvm_sku_bits { - NVM_SKU_CAP_BAND_24GHZ = BIT(0), - NVM_SKU_CAP_BAND_52GHZ = BIT(1), - NVM_SKU_CAP_11N_ENABLE = BIT(2), -}; - -/* radio config bits (actual values from NVM definition) */ -#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ -#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ -#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ -#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ -#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ -#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ - -/* - * These are the channel numbers in the order that they are stored in the NVM - */ -static const u8 iwl_nvm_channels[] = { - /* 2.4 GHz */ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - /* 5 GHz */ - 36, 40, 44 , 48, 52, 56, 60, 64, - 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, - 149, 153, 157, 161, 165 -}; - -#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) -#define NUM_2GHZ_CHANNELS 14 -#define FIRST_2GHZ_HT_MINUS 5 -#define LAST_2GHZ_HT_PLUS 9 -#define LAST_5GHZ_HT 161 - - -/* rate data (static) */ -static struct ieee80211_rate iwl_cfg80211_rates[] = { - { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, - { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1, - .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, - { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2, - .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, - { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3, - .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, - { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, }, - { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, }, - { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, }, - { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, }, - { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, }, - { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, }, - { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, }, - { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, }, -}; -#define RATES_24_OFFS 0 -#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates) -#define RATES_52_OFFS 4 -#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) - -/** - * enum iwl_nvm_channel_flags - channel flags in NVM - * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo - * @NVM_CHANNEL_IBSS: usable as an IBSS channel - * @NVM_CHANNEL_ACTIVE: active scanning allowed - * @NVM_CHANNEL_RADAR: radar detection required - * @NVM_CHANNEL_DFS: dynamic freq selection candidate - * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?) - * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) - */ -enum iwl_nvm_channel_flags { - NVM_CHANNEL_VALID = BIT(0), - NVM_CHANNEL_IBSS = BIT(1), - NVM_CHANNEL_ACTIVE = BIT(3), - NVM_CHANNEL_RADAR = BIT(4), - NVM_CHANNEL_DFS = BIT(7), - NVM_CHANNEL_WIDE = BIT(8), - NVM_CHANNEL_40MHZ = BIT(9), -}; - -#define CHECK_AND_PRINT_I(x) \ - ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") - -static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, - const __le16 * const nvm_ch_flags) -{ - int ch_idx; - int n_channels = 0; - struct ieee80211_channel *channel; - u16 ch_flags; - bool is_5ghz; - - for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { - ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); - if (!(ch_flags & NVM_CHANNEL_VALID)) { - IWL_DEBUG_EEPROM(dev, - "Ch. %d Flags %x [%sGHz] - No traffic\n", - iwl_nvm_channels[ch_idx], - ch_flags, - (ch_idx >= NUM_2GHZ_CHANNELS) ? - "5.2" : "2.4"); - continue; - } - - channel = &data->channels[n_channels]; - n_channels++; - - channel->hw_value = iwl_nvm_channels[ch_idx]; - channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - channel->center_freq = - ieee80211_channel_to_frequency( - channel->hw_value, channel->band); - - /* TODO: Need to be dependent to the NVM */ - channel->flags = IEEE80211_CHAN_NO_HT40; - if (ch_idx < NUM_2GHZ_CHANNELS && - (ch_flags & NVM_CHANNEL_40MHZ)) { - if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS) - channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; - if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS) - channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; - } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT && - (ch_flags & NVM_CHANNEL_40MHZ)) { - if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) - channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; - else - channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; - } - - if (!(ch_flags & NVM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IBSS; - - if (!(ch_flags & NVM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - if (ch_flags & NVM_CHANNEL_RADAR) - channel->flags |= IEEE80211_CHAN_RADAR; - - /* Initialize regulatory-based run-time data */ - - /* TODO: read the real value from the NVM */ - channel->max_power = 0; - is_5ghz = channel->band == IEEE80211_BAND_5GHZ; - IWL_DEBUG_EEPROM(dev, - "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", - channel->hw_value, - is_5ghz ? "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(DFS), - ch_flags, - channel->max_power, - ((ch_flags & NVM_CHANNEL_IBSS) && - !(ch_flags & NVM_CHANNEL_RADAR)) - ? "" : "not "); - } - - return n_channels; -} - -static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, const __le16 *nvm_sw) -{ - int n_channels = iwl_init_channel_map(dev, cfg, data, - &nvm_sw[NVM_CHANNELS]); - int n_used = 0; - struct ieee80211_supported_band *sband; - - sband = &data->bands[IEEE80211_BAND_2GHZ]; - sband->band = IEEE80211_BAND_2GHZ; - sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; - sband->n_bitrates = N_RATES_24; - n_used += iwl_init_sband_channels(data, sband, n_channels, - IEEE80211_BAND_2GHZ); - iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ); - - sband = &data->bands[IEEE80211_BAND_5GHZ]; - sband->band = IEEE80211_BAND_5GHZ; - sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; - sband->n_bitrates = N_RATES_52; - n_used += iwl_init_sband_channels(data, sband, n_channels, - IEEE80211_BAND_5GHZ); - iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ); - - if (n_channels != n_used) - IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", - n_used, n_channels); -} - -struct iwl_nvm_data * -iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, - const __le16 *nvm_hw, const __le16 *nvm_sw, - const __le16 *nvm_calib) -{ - struct iwl_nvm_data *data; - u8 hw_addr[ETH_ALEN]; - u16 radio_cfg, sku; - - data = kzalloc(sizeof(*data) + - sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, - GFP_KERNEL); - if (!data) - return NULL; - - data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION); - - radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG); - data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); - data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); - data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); - data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); - data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg); - data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg); - - sku = le16_to_cpup(nvm_sw + SKU); - data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; - data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; - data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) - data->sku_cap_11n_enable = false; - - /* check overrides (some devices have wrong NVM) */ - if (cfg->valid_tx_ant) - data->valid_tx_ant = cfg->valid_tx_ant; - if (cfg->valid_rx_ant) - data->valid_rx_ant = cfg->valid_rx_ant; - - if (!data->valid_tx_ant || !data->valid_rx_ant) { - IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n", - data->valid_tx_ant, data->valid_rx_ant); - kfree(data); - return NULL; - } - - data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS); - - data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); - data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); - - /* The byte order is little endian 16 bit, meaning 214365 */ - memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN); - data->hw_addr[0] = hw_addr[1]; - data->hw_addr[1] = hw_addr[0]; - data->hw_addr[2] = hw_addr[3]; - data->hw_addr[3] = hw_addr[2]; - data->hw_addr[4] = hw_addr[5]; - data->hw_addr[5] = hw_addr[4]; - - iwl_init_sbands(dev, cfg, data, nvm_sw); - - data->calib_version = 255; /* TODO: - this value will prevent some checks from - failing, we need to check if this - field is still needed, and if it does, - where is it in the NVM*/ - - return data; -} -EXPORT_SYMBOL_GPL(iwl_parse_nvm_data); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/trunk/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h deleted file mode 100644 index b2692bd287fa..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ /dev/null @@ -1,80 +0,0 @@ -/****************************************************************************** - * - * 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 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2013 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_nvm_parse_h__ -#define __iwl_nvm_parse_h__ - -#include "iwl-eeprom-parse.h" - -/** - * iwl_parse_nvm_data - parse NVM data and return values - * - * This function parses all NVM values we need and then - * returns a (newly allocated) struct containing all the - * relevant values for driver use. The struct must be freed - * later with iwl_free_nvm_data(). - */ -struct iwl_nvm_data * -iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, - const __le16 *nvm_hw, const __le16 *nvm_sw, - const __le16 *nvm_calib); - -#endif /* __iwl_nvm_parse_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h index dc792584f401..c8d9b9517468 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,8 +63,6 @@ #ifndef __iwl_op_mode_h__ #define __iwl_op_mode_h__ -#include - struct iwl_op_mode; struct iwl_trans; struct sk_buff; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c deleted file mode 100644 index 14fc8d39fc28..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ /dev/null @@ -1,514 +0,0 @@ -/****************************************************************************** - * - * 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) 2007 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2013 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 -#include -#include - -#include "iwl-phy-db.h" -#include "iwl-debug.h" -#include "iwl-op-mode.h" -#include "iwl-trans.h" - -#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ -#define IWL_NUM_PAPD_CH_GROUPS 4 -#define IWL_NUM_TXP_CH_GROUPS 9 - -struct iwl_phy_db_entry { - u16 size; - u8 *data; -}; - -/** - * struct iwl_phy_db - stores phy configuration and calibration data. - * - * @cfg: phy configuration. - * @calib_nch: non channel specific calibration data. - * @calib_ch: channel specific calibration data. - * @calib_ch_group_papd: calibration data related to papd channel group. - * @calib_ch_group_txp: calibration data related to tx power chanel group. - */ -struct iwl_phy_db { - struct iwl_phy_db_entry cfg; - struct iwl_phy_db_entry calib_nch; - struct iwl_phy_db_entry calib_ch; - struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS]; - struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS]; - - u32 channel_num; - u32 channel_size; - - struct iwl_trans *trans; -}; - -enum iwl_phy_db_section_type { - IWL_PHY_DB_CFG = 1, - IWL_PHY_DB_CALIB_NCH, - IWL_PHY_DB_CALIB_CH, - IWL_PHY_DB_CALIB_CHG_PAPD, - IWL_PHY_DB_CALIB_CHG_TXP, - IWL_PHY_DB_MAX -}; - -#define PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */ - -/* - * phy db - configure operational ucode - */ -struct iwl_phy_db_cmd { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - -/* for parsing of tx power channel group data that comes from the firmware*/ -struct iwl_phy_db_chg_txp { - __le32 space; - __le16 max_channel_idx; -} __packed; - -/* - * phy db - Receieve phy db chunk after calibrations - */ -struct iwl_calib_res_notif_phy_db { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - -#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587) -static inline void iwl_phy_db_test_pic(__le32 pic) -{ - WARN_ON(IWL_PHY_DB_STATIC_PIC != pic); -} - -struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) -{ - struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), - GFP_KERNEL); - - if (!phy_db) - return phy_db; - - phy_db->trans = trans; - - /* TODO: add default values of the phy db. */ - return phy_db; -} -EXPORT_SYMBOL(iwl_phy_db_init); - -/* - * get phy db section: returns a pointer to a phy db section specified by - * type and channel group id. - */ -static struct iwl_phy_db_entry * -iwl_phy_db_get_section(struct iwl_phy_db *phy_db, - enum iwl_phy_db_section_type type, - u16 chg_id) -{ - if (!phy_db || type >= IWL_PHY_DB_MAX) - return NULL; - - switch (type) { - case IWL_PHY_DB_CFG: - return &phy_db->cfg; - case IWL_PHY_DB_CALIB_NCH: - return &phy_db->calib_nch; - case IWL_PHY_DB_CALIB_CH: - return &phy_db->calib_ch; - case IWL_PHY_DB_CALIB_CHG_PAPD: - if (chg_id >= IWL_NUM_PAPD_CH_GROUPS) - return NULL; - return &phy_db->calib_ch_group_papd[chg_id]; - case IWL_PHY_DB_CALIB_CHG_TXP: - if (chg_id >= IWL_NUM_TXP_CH_GROUPS) - return NULL; - return &phy_db->calib_ch_group_txp[chg_id]; - default: - return NULL; - } - return NULL; -} - -static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, - enum iwl_phy_db_section_type type, - u16 chg_id) -{ - struct iwl_phy_db_entry *entry = - iwl_phy_db_get_section(phy_db, type, chg_id); - if (!entry) - return; - - kfree(entry->data); - entry->data = NULL; - entry->size = 0; -} - -void iwl_phy_db_free(struct iwl_phy_db *phy_db) -{ - int i; - - if (!phy_db) - return; - - iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); - iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); - iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CH, 0); - for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++) - iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); - for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) - iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); - - kfree(phy_db); -} -EXPORT_SYMBOL(iwl_phy_db_free); - -int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, - gfp_t alloc_ctx) -{ - struct iwl_calib_res_notif_phy_db *phy_db_notif = - (struct iwl_calib_res_notif_phy_db *)pkt->data; - enum iwl_phy_db_section_type type = le16_to_cpu(phy_db_notif->type); - u16 size = le16_to_cpu(phy_db_notif->length); - struct iwl_phy_db_entry *entry; - u16 chg_id = 0; - - if (!phy_db) - return -EINVAL; - - if (type == IWL_PHY_DB_CALIB_CHG_PAPD || - type == IWL_PHY_DB_CALIB_CHG_TXP) - chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); - - entry = iwl_phy_db_get_section(phy_db, type, chg_id); - if (!entry) - return -EINVAL; - - kfree(entry->data); - entry->data = kmemdup(phy_db_notif->data, size, alloc_ctx); - if (!entry->data) { - entry->size = 0; - return -ENOMEM; - } - - entry->size = size; - - if (type == IWL_PHY_DB_CALIB_CH) { - phy_db->channel_num = - le32_to_cpup((__le32 *)phy_db_notif->data); - phy_db->channel_size = - (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; - } - - /* Test PIC */ - if (type != IWL_PHY_DB_CFG) - iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) + - (size / sizeof(__le32)) - 1)); - - IWL_DEBUG_INFO(phy_db->trans, - "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", - __func__, __LINE__, type, size); - - return 0; -} -EXPORT_SYMBOL(iwl_phy_db_set_section); - -static int is_valid_channel(u16 ch_id) -{ - if (ch_id <= 14 || - (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || - (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || - (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) - return 1; - return 0; -} - -static u8 ch_id_to_ch_index(u16 ch_id) -{ - if (WARN_ON(!is_valid_channel(ch_id))) - return 0xff; - - if (ch_id <= 14) - return ch_id - 1; - if (ch_id <= 64) - return (ch_id + 20) / 4; - if (ch_id <= 140) - return (ch_id - 12) / 4; - return (ch_id - 13) / 4; -} - - -static u16 channel_id_to_papd(u16 ch_id) -{ - if (WARN_ON(!is_valid_channel(ch_id))) - return 0xff; - - if (1 <= ch_id && ch_id <= 14) - return 0; - if (36 <= ch_id && ch_id <= 64) - return 1; - if (100 <= ch_id && ch_id <= 140) - return 2; - return 3; -} - -static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) -{ - struct iwl_phy_db_chg_txp *txp_chg; - int i; - u8 ch_index = ch_id_to_ch_index(ch_id); - if (ch_index == 0xff) - return 0xff; - - for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) { - txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; - if (!txp_chg) - return 0xff; - /* - * Looking for the first channel group that its max channel is - * higher then wanted channel. - */ - if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) - return i; - } - return 0xff; -} -static -int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, - u32 type, u8 **data, u16 *size, u16 ch_id) -{ - struct iwl_phy_db_entry *entry; - u32 channel_num; - u32 channel_size; - u16 ch_group_id = 0; - u16 index; - - if (!phy_db) - return -EINVAL; - - /* find wanted channel group */ - if (type == IWL_PHY_DB_CALIB_CHG_PAPD) - ch_group_id = channel_id_to_papd(ch_id); - else if (type == IWL_PHY_DB_CALIB_CHG_TXP) - ch_group_id = channel_id_to_txp(phy_db, ch_id); - - entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); - if (!entry) - return -EINVAL; - - if (type == IWL_PHY_DB_CALIB_CH) { - index = ch_id_to_ch_index(ch_id); - channel_num = phy_db->channel_num; - channel_size = phy_db->channel_size; - if (index >= channel_num) { - IWL_ERR(phy_db->trans, "Wrong channel number %d\n", - ch_id); - return -EINVAL; - } - *data = entry->data + CHANNEL_NUM_SIZE + index * channel_size; - *size = channel_size; - } else { - *data = entry->data; - *size = entry->size; - } - - /* Test PIC */ - if (type != IWL_PHY_DB_CFG) - iwl_phy_db_test_pic(*(((__le32 *)*data) + - (*size / sizeof(__le32)) - 1)); - - IWL_DEBUG_INFO(phy_db->trans, - "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", - __func__, __LINE__, type, *size); - - return 0; -} - -static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, - u16 length, void *data) -{ - struct iwl_phy_db_cmd phy_db_cmd; - struct iwl_host_cmd cmd = { - .id = PHY_DB_CMD, - .flags = CMD_SYNC, - }; - - IWL_DEBUG_INFO(phy_db->trans, - "Sending PHY-DB hcmd of type %d, of length %d\n", - type, length); - - /* Set phy db cmd variables */ - phy_db_cmd.type = cpu_to_le16(type); - phy_db_cmd.length = cpu_to_le16(length); - - /* Set hcmd variables */ - cmd.data[0] = &phy_db_cmd; - cmd.len[0] = sizeof(struct iwl_phy_db_cmd); - cmd.data[1] = data; - cmd.len[1] = length; - cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; - - return iwl_trans_send_cmd(phy_db->trans, &cmd); -} - -static int iwl_phy_db_send_all_channel_groups( - struct iwl_phy_db *phy_db, - enum iwl_phy_db_section_type type, - u8 max_ch_groups) -{ - u16 i; - int err; - struct iwl_phy_db_entry *entry; - - /* Send all the channel specific groups to operational fw */ - for (i = 0; i < max_ch_groups; i++) { - entry = iwl_phy_db_get_section(phy_db, - type, - i); - if (!entry) - return -EINVAL; - - /* Send the requested PHY DB section */ - err = iwl_send_phy_db_cmd(phy_db, - type, - entry->size, - entry->data); - if (err) { - IWL_ERR(phy_db->trans, - "Can't SEND phy_db section %d (%d), err %d", - type, i, err); - return err; - } - - IWL_DEBUG_INFO(phy_db->trans, - "Sent PHY_DB HCMD, type = %d num = %d", - type, i); - } - - return 0; -} - -int iwl_send_phy_db_data(struct iwl_phy_db *phy_db) -{ - u8 *data = NULL; - u16 size = 0; - int err; - - IWL_DEBUG_INFO(phy_db->trans, - "Sending phy db data and configuration to runtime image\n"); - - /* Send PHY DB CFG section */ - err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG, - &data, &size, 0); - if (err) { - IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); - return err; - } - - err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); - if (err) { - IWL_ERR(phy_db->trans, - "Cannot send HCMD of Phy DB cfg section\n"); - return err; - } - - err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH, - &data, &size, 0); - if (err) { - IWL_ERR(phy_db->trans, - "Cannot get Phy DB non specific channel section\n"); - return err; - } - - err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); - if (err) { - IWL_ERR(phy_db->trans, - "Cannot send HCMD of Phy DB non specific channel section\n"); - return err; - } - - /* Send all the TXP channel specific data */ - err = iwl_phy_db_send_all_channel_groups(phy_db, - IWL_PHY_DB_CALIB_CHG_PAPD, - IWL_NUM_PAPD_CH_GROUPS); - if (err) { - IWL_ERR(phy_db->trans, - "Cannot send channel specific PAPD groups"); - return err; - } - - /* Send all the TXP channel specific data */ - err = iwl_phy_db_send_all_channel_groups(phy_db, - IWL_PHY_DB_CALIB_CHG_TXP, - IWL_NUM_TXP_CH_GROUPS); - if (err) { - IWL_ERR(phy_db->trans, - "Cannot send channel specific TX power groups"); - return err; - } - - IWL_DEBUG_INFO(phy_db->trans, - "Finished sending phy db non channel data\n"); - return 0; -} -EXPORT_SYMBOL(iwl_send_phy_db_data); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h deleted file mode 100644 index d0e43d96ab38..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h +++ /dev/null @@ -1,82 +0,0 @@ -/****************************************************************************** - * - * 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) 2007 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2013 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_PHYDB_H__ -#define __IWL_PHYDB_H__ - -#include - -#include "iwl-op-mode.h" -#include "iwl-trans.h" - -struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans); - -void iwl_phy_db_free(struct iwl_phy_db *phy_db); - -int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, - gfp_t alloc_ctx); - - -int iwl_send_phy_db_data(struct iwl_phy_db *phy_db); - -#endif /* __IWL_PHYDB_H__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h b/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h index f76e9cad7757..c3a4bb41e533 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -97,9 +97,6 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) -/* Device system time */ -#define DEVICE_SYSTEM_TIME_REG 0xA0206C - /** * Tx Scheduler * diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-test.c b/trunk/drivers/net/wireless/iwlwifi/iwl-test.c index ce0c67b425ee..1a226114fe73 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-test.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-test.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 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) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -466,7 +466,9 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) /* Hard-coded periphery absolute address */ if (IWL_ABS_PRPH_START <= addr && addr < IWL_ABS_PRPH_START + PRPH_END) { - if (!iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (!iwl_trans_grab_nic_access(trans, false)) { + spin_unlock_irqrestore(&trans->reg_lock, flags); return -EIO; } iwl_write32(trans, HBUS_TARG_PRPH_RADDR, @@ -474,7 +476,8 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) for (i = 0; i < size; i += 4) *(u32 *)(tst->mem.addr + i) = iwl_read32(trans, HBUS_TARG_PRPH_RDAT); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); + spin_unlock_irqrestore(&trans->reg_lock, flags); } else { /* target memory (SRAM) */ iwl_trans_read_mem(trans, addr, tst->mem.addr, tst->mem.size / 4); @@ -503,13 +506,19 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr, /* Periphery writes can be 1-3 bytes long, or DWORDs */ if (size < 4) { memcpy(&val, buf, size); - if (!iwl_trans_grab_nic_access(trans, false, &flags)) + spin_lock_irqsave(&trans->reg_lock, flags); + if (!iwl_trans_grab_nic_access(trans, false)) { + spin_unlock_irqrestore(&trans->reg_lock, flags); return -EIO; + } iwl_write32(trans, HBUS_TARG_PRPH_WADDR, (addr & 0x0000FFFF) | ((size - 1) << 24)); iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); + /* needed after consecutive writes w/o read */ + mmiowb(); + spin_unlock_irqrestore(&trans->reg_lock, flags); } else { if (size % 4) return -EINVAL; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-test.h b/trunk/drivers/net/wireless/iwlwifi/iwl-test.h index 7fbf4d717caa..e13ffa8acc02 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-test.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-test.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 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) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.h b/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.h index a963f45c6849..6ba211b09426 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 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) 2010 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h b/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h index 0a3d4df5f434..0f85eb305878 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -193,11 +193,11 @@ struct iwl_rx_packet { * @CMD_ON_DEMAND: This command is sent by the test mode pipe. */ enum CMD_MODE { - CMD_SYNC = 0, - CMD_ASYNC = BIT(0), - CMD_WANT_SKB = BIT(1), - CMD_WANT_HCMD = BIT(2), - CMD_ON_DEMAND = BIT(3), + CMD_SYNC = 0, + CMD_ASYNC = BIT(0), + CMD_WANT_SKB = BIT(1), + CMD_WANT_HCMD = BIT(2), + CMD_ON_DEMAND = BIT(3), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -274,7 +274,6 @@ struct iwl_rx_cmd_buffer { struct page *_page; int _offset; bool _page_stolen; - u32 _rx_page_order; unsigned int truesize; }; @@ -295,11 +294,6 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) return r->_page; } -static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) -{ - __free_pages(r->_page, r->_rx_page_order); -} - #define MAX_NO_RECLAIM_CMDS 6 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) @@ -416,12 +410,8 @@ struct iwl_trans; * the op_mode. May be called several times before start_fw, can't be * called after that. * @set_pmi: set the power pmi state - * @grab_nic_access: wake the NIC to be able to access non-HBUS regs. - * Sleeping is not allowed between grab_nic_access and - * release_nic_access. - * @release_nic_access: let the NIC go to sleep. The "flags" parameter - * must be the same one that was sent before to the grab_nic_access. - * @set_bits_mask - set SRAM register according to value and mask. + * @grab_nic_access: wake the NIC to be able to access non-HBUS regs + * @release_nic_access: let the NIC go to sleep */ struct iwl_trans_ops { @@ -464,12 +454,8 @@ struct iwl_trans_ops { void (*configure)(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg); void (*set_pmi)(struct iwl_trans *trans, bool state); - bool (*grab_nic_access)(struct iwl_trans *trans, bool silent, - unsigned long *flags); - void (*release_nic_access)(struct iwl_trans *trans, - unsigned long *flags); - void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, - u32 value); + bool (*grab_nic_access)(struct iwl_trans *trans, bool silent); + void (*release_nic_access)(struct iwl_trans *trans); }; /** @@ -489,6 +475,7 @@ enum iwl_trans_state { * @ops - pointer to iwl_trans_ops * @op_mode - pointer to the op_mode * @cfg - pointer to the configuration + * @reg_lock - protect hw register access * @dev - pointer to struct device * that represents the device * @hw_id: a u32 with the ID of the device / subdevice. * Set during transport allocation. @@ -509,6 +496,7 @@ struct iwl_trans { struct iwl_op_mode *op_mode; const struct iwl_cfg *cfg; enum iwl_trans_state state; + spinlock_t reg_lock; struct device *dev; u32 hw_rev; @@ -768,20 +756,14 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) trans->ops->set_pmi(trans, state); } -static inline void -iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) -{ - trans->ops->set_bits_mask(trans, reg, mask, value); -} - -#define iwl_trans_grab_nic_access(trans, silent, flags) \ +#define iwl_trans_grab_nic_access(trans, silent) \ __cond_lock(nic_access, \ - likely((trans)->ops->grab_nic_access(trans, silent, flags))) + likely((trans)->ops->grab_nic_access(trans, silent))) static inline void __releases(nic_access) -iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) +iwl_trans_release_nic_access(struct iwl_trans *trans) { - trans->ops->release_nic_access(trans, flags); + trans->ops->release_nic_access(trans); __release(nic_access); } diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/Makefile b/trunk/drivers/net/wireless/iwlwifi/mvm/Makefile deleted file mode 100644 index 807b250ec396..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -obj-$(CONFIG_IWLMVM) += iwlmvm.o -iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o -iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o -iwlmvm-y += scan.o time-event.o rs.o -iwlmvm-y += power.o -iwlmvm-y += led.o -iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o -iwlmvm-$(CONFIG_PM_SLEEP) += d3.o - -ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/binding.c b/trunk/drivers/net/wireless/iwlwifi/mvm/binding.c deleted file mode 100644 index 73d24aacb90a..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/binding.c +++ /dev/null @@ -1,197 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include "fw-api.h" -#include "mvm.h" - -struct iwl_mvm_iface_iterator_data { - struct ieee80211_vif *ignore_vif; - int idx; - - struct iwl_mvm_phy_ctxt *phyctxt; - - u16 ids[MAX_MACS_IN_BINDING]; - u16 colors[MAX_MACS_IN_BINDING]; -}; - -static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action, - struct iwl_mvm_iface_iterator_data *data) -{ - struct iwl_binding_cmd cmd; - struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt; - int i, ret; - u32 status; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id, - phyctxt->color)); - cmd.action = cpu_to_le32(action); - cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id, - phyctxt->color)); - - for (i = 0; i < MAX_MACS_IN_BINDING; i++) - cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID); - for (i = 0; i < data->idx; i++) - cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i], - data->colors[i])); - - status = 0; - ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, - sizeof(cmd), &cmd, &status); - if (ret) { - IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n", - action, ret); - return ret; - } - - if (status) { - IWL_ERR(mvm, "Binding command failed: %u\n", status); - ret = -EIO; - } - - return ret; -} - -static void iwl_mvm_iface_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_iface_iterator_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (vif == data->ignore_vif) - return; - - if (mvmvif->phy_ctxt != data->phyctxt) - return; - - if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING)) - return; - - data->ids[data->idx] = mvmvif->id; - data->colors[data->idx] = mvmvif->color; - data->idx++; -} - -static int iwl_mvm_binding_update(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_mvm_phy_ctxt *phyctxt, - bool add) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_iface_iterator_data data = { - .ignore_vif = vif, - .phyctxt = phyctxt, - }; - u32 action = FW_CTXT_ACTION_MODIFY; - - lockdep_assert_held(&mvm->mutex); - - ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_iface_iterator, - &data); - - /* - * If there are no other interfaces yet we - * need to create a new binding. - */ - if (data.idx == 0) { - if (add) - action = FW_CTXT_ACTION_ADD; - else - action = FW_CTXT_ACTION_REMOVE; - } - - if (add) { - if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING)) - return -EINVAL; - - data.ids[data.idx] = mvmvif->id; - data.colors[data.idx] = mvmvif->color; - data.idx++; - } - - return iwl_mvm_binding_cmd(mvm, action, &data); -} - -int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) - return -EINVAL; - - return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true); -} - -int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) - return -EINVAL; - - return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/d3.c b/trunk/drivers/net/wireless/iwlwifi/mvm/d3.c deleted file mode 100644 index 9a95c374990d..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/d3.c +++ /dev/null @@ -1,841 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include -#include "iwl-modparams.h" -#include "fw-api.h" -#include "mvm.h" - -void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_gtk_rekey_data *data) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (iwlwifi_mod_params.sw_crypto) - return; - - mutex_lock(&mvm->mutex); - - memcpy(mvmvif->rekey_data.kek, data->kek, NL80211_KEK_LEN); - memcpy(mvmvif->rekey_data.kck, data->kck, NL80211_KCK_LEN); - mvmvif->rekey_data.replay_ctr = - cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr)); - mvmvif->rekey_data.valid = true; - - mutex_unlock(&mvm->mutex); -} - -#if IS_ENABLED(CONFIG_IPV6) -void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct inet6_dev *idev) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct inet6_ifaddr *ifa; - int idx = 0; - - read_lock(&idev->lock); - list_for_each_entry(ifa, &idev->addr_list, if_list) { - mvmvif->target_ipv6_addrs[idx] = ifa->addr; - idx++; - if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) - break; - } - read_unlock(&idev->lock); - - mvmvif->num_target_ipv6_addrs = idx; -} -#endif - -void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int idx) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - mvmvif->tx_key_idx = idx; -} - -static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out) -{ - int i; - - for (i = 0; i < IWL_P1K_SIZE; i++) - out[i] = cpu_to_le16(p1k[i]); -} - -struct wowlan_key_data { - struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; - struct iwl_wowlan_tkip_params_cmd *tkip; - bool error, use_rsc_tsc, use_tkip; - int gtk_key_idx; -}; - -static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *_data) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct wowlan_key_data *data = _data; - struct aes_sc *aes_sc, *aes_tx_sc = NULL; - struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; - struct iwl_p1k_cache *rx_p1ks; - u8 *rx_mic_key; - struct ieee80211_key_seq seq; - u32 cur_rx_iv32 = 0; - u16 p1k[IWL_P1K_SIZE]; - int ret, i; - - mutex_lock(&mvm->mutex); - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */ - struct { - struct iwl_mvm_wep_key_cmd wep_key_cmd; - struct iwl_mvm_wep_key wep_key; - } __packed wkc = { - .wep_key_cmd.mac_id_n_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)), - .wep_key_cmd.num_keys = 1, - /* firmware sets STA_KEY_FLG_WEP_13BYTES */ - .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP, - .wep_key.key_index = key->keyidx, - .wep_key.key_size = key->keylen, - }; - - /* - * This will fail -- the key functions don't set support - * pairwise WEP keys. However, that's better than silently - * failing WoWLAN. Or maybe not? - */ - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) - break; - - memcpy(&wkc.wep_key.key[3], key->key, key->keylen); - if (key->keyidx == mvmvif->tx_key_idx) { - /* TX key must be at offset 0 */ - wkc.wep_key.key_offset = 0; - } else { - /* others start at 1 */ - data->gtk_key_idx++; - wkc.wep_key.key_offset = data->gtk_key_idx; - } - - ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC, - sizeof(wkc), &wkc); - data->error = ret != 0; - - /* don't upload key again */ - goto out_unlock; - } - default: - data->error = true; - goto out_unlock; - case WLAN_CIPHER_SUITE_AES_CMAC: - /* - * Ignore CMAC keys -- the WoWLAN firmware doesn't support them - * but we also shouldn't abort suspend due to that. It does have - * support for the IGTK key renewal, but doesn't really use the - * IGTK for anything. This means we could spuriously wake up or - * be deauthenticated, but that was considered acceptable. - */ - goto out_unlock; - case WLAN_CIPHER_SUITE_TKIP: - if (sta) { - tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc; - tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc; - - rx_p1ks = data->tkip->rx_uni; - - ieee80211_get_key_tx_seq(key, &seq); - tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16); - tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32); - - ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k); - iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k); - - memcpy(data->tkip->mic_keys.tx, - &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], - IWL_MIC_KEY_SIZE); - - rx_mic_key = data->tkip->mic_keys.rx_unicast; - } else { - tkip_sc = - data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc; - rx_p1ks = data->tkip->rx_multi; - rx_mic_key = data->tkip->mic_keys.rx_mcast; - } - - /* - * For non-QoS this relies on the fact that both the uCode and - * mac80211 use TID 0 (as they need to to avoid replay attacks) - * for checking the IV in the frames. - */ - for (i = 0; i < IWL_NUM_RSC; i++) { - ieee80211_get_key_rx_seq(key, i, &seq); - tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16); - tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); - /* wrapping isn't allowed, AP must rekey */ - if (seq.tkip.iv32 > cur_rx_iv32) - cur_rx_iv32 = seq.tkip.iv32; - } - - ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, - cur_rx_iv32, p1k); - iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k); - ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid, - cur_rx_iv32 + 1, p1k); - iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k); - - memcpy(rx_mic_key, - &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], - IWL_MIC_KEY_SIZE); - - data->use_tkip = true; - data->use_rsc_tsc = true; - break; - case WLAN_CIPHER_SUITE_CCMP: - if (sta) { - u8 *pn = seq.ccmp.pn; - - aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc; - aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc; - - ieee80211_get_key_tx_seq(key, &seq); - aes_tx_sc->pn = cpu_to_le64((u64)pn[5] | - ((u64)pn[4] << 8) | - ((u64)pn[3] << 16) | - ((u64)pn[2] << 24) | - ((u64)pn[1] << 32) | - ((u64)pn[0] << 40)); - } else { - aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc; - } - - /* - * For non-QoS this relies on the fact that both the uCode and - * mac80211 use TID 0 for checking the IV in the frames. - */ - for (i = 0; i < IWL_NUM_RSC; i++) { - u8 *pn = seq.ccmp.pn; - - ieee80211_get_key_rx_seq(key, i, &seq); - aes_sc->pn = cpu_to_le64((u64)pn[5] | - ((u64)pn[4] << 8) | - ((u64)pn[3] << 16) | - ((u64)pn[2] << 24) | - ((u64)pn[1] << 32) | - ((u64)pn[0] << 40)); - } - data->use_rsc_tsc = true; - break; - } - - /* - * The D3 firmware hardcodes the key offset 0 as the key it uses - * to transmit packets to the AP, i.e. the PTK. - */ - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - key->hw_key_idx = 0; - } else { - data->gtk_key_idx++; - key->hw_key_idx = data->gtk_key_idx; - } - - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); - data->error = ret != 0; -out_unlock: - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, - struct cfg80211_wowlan *wowlan) -{ - struct iwl_wowlan_patterns_cmd *pattern_cmd; - struct iwl_host_cmd cmd = { - .id = WOWLAN_PATTERNS, - .dataflags[0] = IWL_HCMD_DFL_NOCOPY, - .flags = CMD_SYNC, - }; - int i, err; - - if (!wowlan->n_patterns) - return 0; - - cmd.len[0] = sizeof(*pattern_cmd) + - wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern); - - pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL); - if (!pattern_cmd) - return -ENOMEM; - - pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns); - - for (i = 0; i < wowlan->n_patterns; i++) { - int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); - - memcpy(&pattern_cmd->patterns[i].mask, - wowlan->patterns[i].mask, mask_len); - memcpy(&pattern_cmd->patterns[i].pattern, - wowlan->patterns[i].pattern, - wowlan->patterns[i].pattern_len); - pattern_cmd->patterns[i].mask_size = mask_len; - pattern_cmd->patterns[i].pattern_size = - wowlan->patterns[i].pattern_len; - } - - cmd.data[0] = pattern_cmd; - err = iwl_mvm_send_cmd(mvm, &cmd); - kfree(pattern_cmd); - return err; -} - -static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_proto_offload_cmd cmd = {}; -#if IS_ENABLED(CONFIG_IPV6) - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int i; - - if (mvmvif->num_target_ipv6_addrs) { - cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS); - memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN); - } - - BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) != - sizeof(mvmvif->target_ipv6_addrs[i])); - - for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++) - memcpy(cmd.target_ipv6_addr[i], - &mvmvif->target_ipv6_addrs[i], - sizeof(cmd.target_ipv6_addr[i])); -#endif - - if (vif->bss_conf.arp_addr_cnt) { - cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP); - cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; - memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN); - } - - if (!cmd.enabled) - return 0; - - return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, - sizeof(cmd), &cmd); -} - -struct iwl_d3_iter_data { - struct iwl_mvm *mvm; - struct ieee80211_vif *vif; - bool error; -}; - -static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_d3_iter_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return; - - if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) - return; - - if (data->vif) { - IWL_ERR(data->mvm, "More than one managed interface active!\n"); - data->error = true; - return; - } - - data->vif = vif; -} - -static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *ap_sta) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct ieee80211_chanctx_conf *ctx; - u8 chains_static, chains_dynamic; - struct cfg80211_chan_def chandef; - int ret, i; - struct iwl_binding_cmd binding_cmd = {}; - struct iwl_time_quota_cmd quota_cmd = {}; - u32 status; - - /* add back the PHY */ - if (WARN_ON(!mvmvif->phy_ctxt)) - return -EINVAL; - - rcu_read_lock(); - ctx = rcu_dereference(vif->chanctx_conf); - if (WARN_ON(!ctx)) { - rcu_read_unlock(); - return -EINVAL; - } - chandef = ctx->def; - chains_static = ctx->rx_chains_static; - chains_dynamic = ctx->rx_chains_dynamic; - rcu_read_unlock(); - - ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, &chandef, - chains_static, chains_dynamic); - if (ret) - return ret; - - /* add back the MAC */ - mvmvif->uploaded = false; - - if (WARN_ON(!vif->bss_conf.assoc)) - return -EINVAL; - /* hack */ - vif->bss_conf.assoc = false; - ret = iwl_mvm_mac_ctxt_add(mvm, vif); - vif->bss_conf.assoc = true; - if (ret) - return ret; - - /* add back binding - XXX refactor? */ - binding_cmd.id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, - mvmvif->phy_ctxt->color)); - binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); - binding_cmd.phy = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, - mvmvif->phy_ctxt->color)); - binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)); - for (i = 1; i < MAX_MACS_IN_BINDING; i++) - binding_cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID); - - status = 0; - ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, - sizeof(binding_cmd), &binding_cmd, - &status); - if (ret) { - IWL_ERR(mvm, "Failed to add binding: %d\n", ret); - return ret; - } - - if (status) { - IWL_ERR(mvm, "Binding command failed: %u\n", status); - return -EIO; - } - - ret = iwl_mvm_sta_add_to_fw(mvm, ap_sta); - if (ret) - return ret; - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); - - ret = iwl_mvm_mac_ctxt_changed(mvm, vif); - if (ret) - return ret; - - /* and some quota */ - quota_cmd.quotas[0].id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, - mvmvif->phy_ctxt->color)); - quota_cmd.quotas[0].quota = cpu_to_le32(100); - quota_cmd.quotas[0].max_duration = cpu_to_le32(1000); - - for (i = 1; i < MAX_BINDINGS; i++) - quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); - - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, - sizeof(quota_cmd), "a_cmd); - if (ret) - IWL_ERR(mvm, "Failed to send quota: %d\n", ret); - - return 0; -} - -int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_d3_iter_data suspend_iter_data = { - .mvm = mvm, - }; - struct ieee80211_vif *vif; - struct iwl_mvm_vif *mvmvif; - struct ieee80211_sta *ap_sta; - struct iwl_mvm_sta *mvm_ap_sta; - struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; - struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; - struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; - struct iwl_d3_manager_config d3_cfg_cmd = {}; - struct wowlan_key_data key_data = { - .use_rsc_tsc = false, - .tkip = &tkip_cmd, - .use_tkip = false, - }; - int ret, i; - u16 seq; - u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; - - if (WARN_ON(!wowlan)) - return -EINVAL; - - key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); - if (!key_data.rsc_tsc) - return -ENOMEM; - - mutex_lock(&mvm->mutex); - - old_aux_sta_id = mvm->aux_sta.sta_id; - - /* see if there's only a single BSS vif and it's associated */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_iface_iterator, &suspend_iter_data); - - if (suspend_iter_data.error || !suspend_iter_data.vif) { - ret = 1; - goto out_noreset; - } - - vif = suspend_iter_data.vif; - mvmvif = iwl_mvm_vif_from_mac80211(vif); - - ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(ap_sta)) { - ret = -EINVAL; - goto out_noreset; - } - - mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; - - /* - * The D3 firmware still hardcodes the AP station ID for the - * BSS we're associated with as 0. Store the real STA ID here - * and assign 0. When we leave this function, we'll restore - * the original value for the resume code. - */ - old_ap_sta_id = mvm_ap_sta->sta_id; - mvm_ap_sta->sta_id = 0; - mvmvif->ap_sta_id = 0; - - /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ - - wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; - - /* - * We know the last used seqno, and the uCode expects to know that - * one, it will increment before TX. - */ - seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ; - wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq); - - /* - * For QoS counters, we store the one to use next, so subtract 0x10 - * since the uCode will add 0x10 *before* using the value while we - * increment after using the value (i.e. store the next value to use). - */ - for (i = 0; i < IWL_MAX_TID_COUNT; i++) { - seq = mvm_ap_sta->tid_data[i].seq_number; - seq -= 0x10; - wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); - } - - if (wowlan->disconnect) - wowlan_config_cmd.wakeup_filter |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | - IWL_WOWLAN_WAKEUP_LINK_CHANGE); - if (wowlan->magic_pkt) - wowlan_config_cmd.wakeup_filter |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); - if (wowlan->gtk_rekey_failure) - wowlan_config_cmd.wakeup_filter |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); - if (wowlan->eap_identity_req) - wowlan_config_cmd.wakeup_filter |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); - if (wowlan->four_way_handshake) - wowlan_config_cmd.wakeup_filter |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); - if (wowlan->n_patterns) - wowlan_config_cmd.wakeup_filter |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); - - if (wowlan->rfkill_release) - d3_cfg_cmd.wakeup_flags |= - cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); - - iwl_mvm_cancel_scan(mvm); - - iwl_trans_stop_device(mvm->trans); - - /* - * Set the HW restart bit -- this is mostly true as we're - * going to load new firmware and reprogram that, though - * the reprogramming is going to be manual to avoid adding - * all the MACs that aren't support. - * We don't have to clear up everything though because the - * reprogramming is manual. When we resume, we'll actually - * go through a proper restart sequence again to switch - * back to the runtime firmware image. - */ - set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - - /* We reprogram keys and shouldn't allocate new key indices */ - memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); - - /* - * The D3 firmware still hardcodes the AP station ID for the - * BSS we're associated with as 0. As a result, we have to move - * the auxiliary station to ID 1 so the ID 0 remains free for - * the AP station for later. - * We set the sta_id to 1 here, and reset it to its previous - * value (that we stored above) later. - */ - mvm->aux_sta.sta_id = 1; - - ret = iwl_mvm_load_d3_fw(mvm); - if (ret) - goto out; - - ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); - if (ret) - goto out; - - if (!iwlwifi_mod_params.sw_crypto) { - /* - * This needs to be unlocked due to lock ordering - * constraints. Since we're in the suspend path - * that isn't really a problem though. - */ - mutex_unlock(&mvm->mutex); - ieee80211_iter_keys(mvm->hw, vif, - iwl_mvm_wowlan_program_keys, - &key_data); - mutex_lock(&mvm->mutex); - if (key_data.error) { - ret = -EIO; - goto out; - } - - if (key_data.use_rsc_tsc) { - struct iwl_host_cmd rsc_tsc_cmd = { - .id = WOWLAN_TSC_RSC_PARAM, - .flags = CMD_SYNC, - .data[0] = key_data.rsc_tsc, - .dataflags[0] = IWL_HCMD_DFL_NOCOPY, - .len[0] = sizeof(*key_data.rsc_tsc), - }; - - ret = iwl_mvm_send_cmd(mvm, &rsc_tsc_cmd); - if (ret) - goto out; - } - - if (key_data.use_tkip) { - ret = iwl_mvm_send_cmd_pdu(mvm, - WOWLAN_TKIP_PARAM, - CMD_SYNC, sizeof(tkip_cmd), - &tkip_cmd); - if (ret) - goto out; - } - - if (mvmvif->rekey_data.valid) { - memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); - memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, - NL80211_KCK_LEN); - kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN); - memcpy(kek_kck_cmd.kek, mvmvif->rekey_data.kek, - NL80211_KEK_LEN); - kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN); - kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; - - ret = iwl_mvm_send_cmd_pdu(mvm, - WOWLAN_KEK_KCK_MATERIAL, - CMD_SYNC, - sizeof(kek_kck_cmd), - &kek_kck_cmd); - if (ret) - goto out; - } - } - - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, - CMD_SYNC, sizeof(wowlan_config_cmd), - &wowlan_config_cmd); - if (ret) - goto out; - - ret = iwl_mvm_send_patterns(mvm, wowlan); - if (ret) - goto out; - - ret = iwl_mvm_send_proto_offload(mvm, vif); - if (ret) - goto out; - - /* must be last -- this switches firmware state */ - ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, - sizeof(d3_cfg_cmd), &d3_cfg_cmd); - if (ret) - goto out; - - clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - - iwl_trans_d3_suspend(mvm->trans); - out: - mvm->aux_sta.sta_id = old_aux_sta_id; - mvm_ap_sta->sta_id = old_ap_sta_id; - mvmvif->ap_sta_id = old_ap_sta_id; - out_noreset: - kfree(key_data.rsc_tsc); - if (ret < 0) - ieee80211_restart_hw(mvm->hw); - - mutex_unlock(&mvm->mutex); - - return ret; -} - -int iwl_mvm_resume(struct ieee80211_hw *hw) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_d3_iter_data resume_iter_data = { - .mvm = mvm, - }; - struct ieee80211_vif *vif = NULL; - u32 base; - int ret; - enum iwl_d3_status d3_status; - struct error_table_start { - /* cf. struct iwl_error_event_table */ - u32 valid; - u32 error_id; - } err_info; - - mutex_lock(&mvm->mutex); - - /* get the BSS vif pointer again */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_iface_iterator, &resume_iter_data); - - if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif)) - goto out_unlock; - - vif = resume_iter_data.vif; - - ret = iwl_trans_d3_resume(mvm->trans, &d3_status); - if (ret) - goto out_unlock; - - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(mvm, "Device was reset during suspend\n"); - goto out_unlock; - } - - base = mvm->error_event_table; - - iwl_trans_read_mem_bytes(mvm->trans, base, - &err_info, sizeof(err_info)); - - if (err_info.valid) { - IWL_INFO(mvm, "error table is valid (%d)\n", - err_info.valid); - if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) - IWL_ERR(mvm, "this was due to RF-kill\n"); - goto out_unlock; - } - - /* TODO: get status and whatever else ... */ - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL); - if (ret) - IWL_ERR(mvm, "failed to query status (%d)\n", ret); - - ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); - if (ret) - IWL_ERR(mvm, "failed to query offloads (%d)\n", ret); - - out_unlock: - mutex_unlock(&mvm->mutex); - - if (vif) - ieee80211_resume_disconnect(vif); - - /* return 1 to reconfigure the device */ - set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - return 1; -} - -void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - device_set_wakeup_enable(mvm->trans->dev, enabled); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/trunk/drivers/net/wireless/iwlwifi/mvm/debugfs.c deleted file mode 100644 index c1bdb5582126..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ /dev/null @@ -1,378 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 "mvm.h" -#include "sta.h" -#include "iwl-io.h" - -struct iwl_dbgfs_mvm_ctx { - struct iwl_mvm *mvm; - struct ieee80211_vif *vif; -}; - -static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - - char buf[16]; - int buf_size, ret; - u32 scd_q_msk; - - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) - return -EIO; - - 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", &scd_q_msk) != 1) - return -EINVAL; - - IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk); - - mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count; - mutex_unlock(&mvm->mutex); - - return ret; -} - -static ssize_t iwl_dbgfs_sta_drain_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - struct ieee80211_sta *sta; - - char buf[8]; - int buf_size, sta_id, drain, ret; - - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) - return -EIO; - - 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, "%d %d", &sta_id, &drain) != 2) - return -EINVAL; - - mutex_lock(&mvm->mutex); - - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(sta)) - ret = -ENOENT; - else - ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? : - count; - - mutex_unlock(&mvm->mutex); - - return ret; -} - -static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - const struct fw_img *img; - int ofs, len, pos = 0; - size_t bufsz, ret; - char *buf; - u8 *ptr; - - /* default is to dump the entire data segment */ - if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) { - mvm->dbgfs_sram_offset = 0x800000; - if (!mvm->ucode_loaded) - return -EINVAL; - img = &mvm->fw->img[mvm->cur_ucode]; - mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; - } - len = mvm->dbgfs_sram_len; - - bufsz = len * 4 + 256; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ptr = kzalloc(len, GFP_KERNEL); - if (!ptr) { - kfree(buf); - return -ENOMEM; - } - - pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len); - pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", - mvm->dbgfs_sram_offset); - - iwl_trans_read_mem_bytes(mvm->trans, - mvm->dbgfs_sram_offset, - ptr, len); - for (ofs = 0; ofs < len; ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, - bufsz - pos, false); - pos += strlen(buf + pos); - if (bufsz - pos > 0) - buf[pos++] = '\n'; - } - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - - kfree(buf); - kfree(ptr); - - 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_mvm *mvm = 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) { - if ((offset & 0x3) || (len & 0x3)) - return -EINVAL; - mvm->dbgfs_sram_offset = offset; - mvm->dbgfs_sram_len = len; - } else { - mvm->dbgfs_sram_offset = 0; - mvm->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_mvm *mvm = file->private_data; - struct ieee80211_sta *sta; - char buf[400]; - int i, pos = 0, bufsz = sizeof(buf); - - mutex_lock(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i); - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta) - pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); - else if (IS_ERR(sta)) - pos += scnprintf(buf + pos, bufsz - pos, "%ld\n", - PTR_ERR(sta)); - else - pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", - sta->addr); - } - - mutex_unlock(&mvm->mutex); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - char buf[8] = {}; - int allow; - - if (!mvm->ucode_loaded) - return -EIO; - - if (copy_from_user(buf, user_buf, sizeof(buf))) - return -EFAULT; - - if (sscanf(buf, "%d", &allow) != 1) - return -EINVAL; - - IWL_DEBUG_POWER(mvm, "%s device power down\n", - allow ? "allow" : "prevent"); - - /* - * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it - */ - - return count; -} - -static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - char buf[8] = {}; - int allow; - - if (copy_from_user(buf, user_buf, sizeof(buf))) - return -EFAULT; - - if (sscanf(buf, "%d", &allow) != 1) - return -EINVAL; - - IWL_DEBUG_POWER(mvm, "%s device power down in d3\n", - allow ? "allow" : "prevent"); - - /* - * TODO: When WoWLAN FW alive notification happens, driver will send - * REPLY_DEBUG_CMD setting power_down_allow flag according to - * mvm->prevent_power_down_d3 - */ - mvm->prevent_power_down_d3 = !allow; - - return count; -} - -#define MVM_DEBUGFS_READ_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .read = iwl_dbgfs_##name##_read, \ - .open = iwl_dbgfs_open_file_generic, \ - .llseek = generic_file_llseek, \ -} - -#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(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, \ - .llseek = generic_file_llseek, \ -}; - -#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ -static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .write = iwl_dbgfs_##name##_write, \ - .open = iwl_dbgfs_open_file_generic, \ - .llseek = generic_file_llseek, \ -}; - -#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, mvm, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ - } while (0) - -#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, vif, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ - } while (0) - -/* Device wide debugfs entries */ -MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush); -MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); -MVM_DEBUGFS_READ_FILE_OPS(stations); -MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); -MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); - -int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) -{ - char buf[100]; - - mvm->debugfs_dir = dbgfs_dir; - - MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); - - /* - * Create a symlink with mac80211. It will be removed when mac80211 - * exists (before the opmode exists which removes the target.) - */ - snprintf(buf, 100, "../../%s/%s", - dbgfs_dir->d_parent->d_parent->d_name.name, - dbgfs_dir->d_parent->d_name.name); - if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf)) - goto err; - - return 0; -err: - IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); - return -ENOMEM; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h deleted file mode 100644 index cf6f9a02fb74..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ /dev/null @@ -1,282 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_d3_h__ -#define __fw_api_d3_h__ - -/** - * enum iwl_d3_wakeup_flags - D3 manager wakeup flags - * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert - */ -enum iwl_d3_wakeup_flags { - IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0), -}; /* D3_MANAGER_WAKEUP_CONFIG_API_E_VER_3 */ - -/** - * struct iwl_d3_manager_config - D3 manager configuration command - * @min_sleep_time: minimum sleep time (in usec) - * @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags - * - * The structure is used for the D3_CONFIG_CMD command. - */ -struct iwl_d3_manager_config { - __le32 min_sleep_time; - __le32 wakeup_flags; -} __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_3 */ - - -/* TODO: OFFLOADS_QUERY_API_S_VER_1 */ - -/** - * enum iwl_d3_proto_offloads - enabled protocol offloads - * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled - * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled - */ -enum iwl_proto_offloads { - IWL_D3_PROTO_OFFLOAD_ARP = BIT(0), - IWL_D3_PROTO_OFFLOAD_NS = BIT(1), -}; - -#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2 - -/** - * struct iwl_proto_offload_cmd - ARP/NS offload configuration - * @enabled: enable flags - * @remote_ipv4_addr: remote address to answer to (or zero if all) - * @host_ipv4_addr: our IPv4 address to respond to queries for - * @arp_mac_addr: our MAC address for ARP responses - * @remote_ipv6_addr: remote address to answer to (or zero if all) - * @solicited_node_ipv6_addr: broken -- solicited node address exists - * for each target address - * @target_ipv6_addr: our target addresses - * @ndp_mac_addr: neighbor soliciation response MAC address - */ -struct iwl_proto_offload_cmd { - __le32 enabled; - __be32 remote_ipv4_addr; - __be32 host_ipv4_addr; - u8 arp_mac_addr[ETH_ALEN]; - __le16 reserved1; - - u8 remote_ipv6_addr[16]; - u8 solicited_node_ipv6_addr[16]; - u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16]; - u8 ndp_mac_addr[ETH_ALEN]; - __le16 reserved2; -} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ - - -/* - * WOWLAN_PATTERNS - */ -#define IWL_WOWLAN_MIN_PATTERN_LEN 16 -#define IWL_WOWLAN_MAX_PATTERN_LEN 128 - -struct iwl_wowlan_pattern { - u8 mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; - u8 pattern[IWL_WOWLAN_MAX_PATTERN_LEN]; - u8 mask_size; - u8 pattern_size; - __le16 reserved; -} __packed; /* WOWLAN_PATTERN_API_S_VER_1 */ - -#define IWL_WOWLAN_MAX_PATTERNS 20 - -struct iwl_wowlan_patterns_cmd { - __le32 n_patterns; - struct iwl_wowlan_pattern patterns[]; -} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_1 */ - -enum iwl_wowlan_wakeup_filters { - IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0), - IWL_WOWLAN_WAKEUP_PATTERN_MATCH = BIT(1), - IWL_WOWLAN_WAKEUP_BEACON_MISS = BIT(2), - IWL_WOWLAN_WAKEUP_LINK_CHANGE = BIT(3), - IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL = BIT(4), - IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ = BIT(5), - IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE = BIT(6), - IWL_WOWLAN_WAKEUP_ENABLE_NET_DETECT = BIT(7), - IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8), - IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9), - IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10), - /* BIT(11) reserved */ - IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12), -}; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ - -struct iwl_wowlan_config_cmd { - __le32 wakeup_filter; - __le16 non_qos_seq; - __le16 qos_seq[8]; - u8 wowlan_ba_teardown_tids; - u8 is_11n_connection; -} __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ - -/* - * WOWLAN_TSC_RSC_PARAMS - */ -#define IWL_NUM_RSC 16 - -struct tkip_sc { - __le16 iv16; - __le16 pad; - __le32 iv32; -} __packed; /* TKIP_SC_API_U_VER_1 */ - -struct iwl_tkip_rsc_tsc { - struct tkip_sc unicast_rsc[IWL_NUM_RSC]; - struct tkip_sc multicast_rsc[IWL_NUM_RSC]; - struct tkip_sc tsc; -} __packed; /* TKIP_TSC_RSC_API_S_VER_1 */ - -struct aes_sc { - __le64 pn; -} __packed; /* TKIP_AES_SC_API_U_VER_1 */ - -struct iwl_aes_rsc_tsc { - struct aes_sc unicast_rsc[IWL_NUM_RSC]; - struct aes_sc multicast_rsc[IWL_NUM_RSC]; - struct aes_sc tsc; -} __packed; /* AES_TSC_RSC_API_S_VER_1 */ - -union iwl_all_tsc_rsc { - struct iwl_tkip_rsc_tsc tkip; - struct iwl_aes_rsc_tsc aes; -}; /* ALL_TSC_RSC_API_S_VER_2 */ - -struct iwl_wowlan_rsc_tsc_params_cmd { - union iwl_all_tsc_rsc all_tsc_rsc; -} __packed; /* ALL_TSC_RSC_API_S_VER_2 */ - -#define IWL_MIC_KEY_SIZE 8 -struct iwl_mic_keys { - u8 tx[IWL_MIC_KEY_SIZE]; - u8 rx_unicast[IWL_MIC_KEY_SIZE]; - u8 rx_mcast[IWL_MIC_KEY_SIZE]; -} __packed; /* MIC_KEYS_API_S_VER_1 */ - -#define IWL_P1K_SIZE 5 -struct iwl_p1k_cache { - __le16 p1k[IWL_P1K_SIZE]; -} __packed; - -#define IWL_NUM_RX_P1K_CACHE 2 - -struct iwl_wowlan_tkip_params_cmd { - struct iwl_mic_keys mic_keys; - struct iwl_p1k_cache tx; - struct iwl_p1k_cache rx_uni[IWL_NUM_RX_P1K_CACHE]; - struct iwl_p1k_cache rx_multi[IWL_NUM_RX_P1K_CACHE]; -} __packed; /* WOWLAN_TKIP_SETTING_API_S_VER_1 */ - -#define IWL_KCK_MAX_SIZE 32 -#define IWL_KEK_MAX_SIZE 32 - -struct iwl_wowlan_kek_kck_material_cmd { - u8 kck[IWL_KCK_MAX_SIZE]; - u8 kek[IWL_KEK_MAX_SIZE]; - __le16 kck_len; - __le16 kek_len; - __le64 replay_ctr; -} __packed; /* KEK_KCK_MATERIAL_API_S_VER_2 */ - -#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 - -enum iwl_wowlan_rekey_status { - IWL_WOWLAN_REKEY_POST_REKEY = 0, - IWL_WOWLAN_REKEY_WHILE_REKEY = 1, -}; /* WOWLAN_REKEY_STATUS_API_E_VER_1 */ - -enum iwl_wowlan_wakeup_reason { - IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS = 0, - IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET = BIT(0), - IWL_WOWLAN_WAKEUP_BY_PATTERN = BIT(1), - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON = BIT(2), - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH = BIT(3), - IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE = BIT(4), - IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED = BIT(5), - IWL_WOWLAN_WAKEUP_BY_UCODE_ERROR = BIT(6), - IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST = BIT(7), - IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), - IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), - IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), - IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11), - IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), -}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ - -struct iwl_wowlan_status { - __le64 replay_ctr; - __le16 pattern_number; - __le16 non_qos_seq_ctr; - __le16 qos_seq_ctr[8]; - __le32 wakeup_reasons; - __le32 rekey_status; - __le32 num_of_gtk_rekeys; - __le32 transmitted_ndps; - __le32 received_beacons; - __le32 wake_packet_length; - __le32 wake_packet_bufsize; - u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ - -/* TODO: NetDetect API */ - -#endif /* __fw_api_d3_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h deleted file mode 100644 index ae39b7dfda7b..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ /dev/null @@ -1,369 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_mac_h__ -#define __fw_api_mac_h__ - -/* - * The first MAC indices (starting from 0) - * are available to the driver, AUX follows - */ -#define MAC_INDEX_AUX 4 -#define MAC_INDEX_MIN_DRIVER 0 -#define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX - -#define AC_NUM 4 /* Number of access categories */ - -/** - * enum iwl_mac_protection_flags - MAC context flags - * @MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames, - * this will require CCK RTS/CTS2self. - * RTS/CTS will protect full burst time. - * @MAC_PROT_FLG_HT_PROT: enable HT protection - * @MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions - * @MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self - */ -enum iwl_mac_protection_flags { - MAC_PROT_FLG_TGG_PROTECT = BIT(3), - MAC_PROT_FLG_HT_PROT = BIT(23), - MAC_PROT_FLG_FAT_PROT = BIT(24), - MAC_PROT_FLG_SELF_CTS_EN = BIT(30), -}; - -#define MAC_FLG_SHORT_SLOT BIT(4) -#define MAC_FLG_SHORT_PREAMBLE BIT(5) - -/** - * enum iwl_mac_types - Supported MAC types - * @FW_MAC_TYPE_FIRST: lowest supported MAC type - * @FW_MAC_TYPE_AUX: Auxiliary MAC (internal) - * @FW_MAC_TYPE_LISTENER: monitor MAC type (?) - * @FW_MAC_TYPE_PIBSS: Pseudo-IBSS - * @FW_MAC_TYPE_IBSS: IBSS - * @FW_MAC_TYPE_BSS_STA: BSS (managed) station - * @FW_MAC_TYPE_P2P_DEVICE: P2P Device - * @FW_MAC_TYPE_P2P_STA: P2P client - * @FW_MAC_TYPE_GO: P2P GO - * @FW_MAC_TYPE_TEST: ? - * @FW_MAC_TYPE_MAX: highest support MAC type - */ -enum iwl_mac_types { - FW_MAC_TYPE_FIRST = 1, - FW_MAC_TYPE_AUX = FW_MAC_TYPE_FIRST, - FW_MAC_TYPE_LISTENER, - FW_MAC_TYPE_PIBSS, - FW_MAC_TYPE_IBSS, - FW_MAC_TYPE_BSS_STA, - FW_MAC_TYPE_P2P_DEVICE, - FW_MAC_TYPE_P2P_STA, - FW_MAC_TYPE_GO, - FW_MAC_TYPE_TEST, - FW_MAC_TYPE_MAX = FW_MAC_TYPE_TEST -}; /* MAC_CONTEXT_TYPE_API_E_VER_1 */ - -/** - * enum iwl_tsf_id - TSF hw timer ID - * @TSF_ID_A: use TSF A - * @TSF_ID_B: use TSF B - * @TSF_ID_C: use TSF C - * @TSF_ID_D: use TSF D - * @NUM_TSF_IDS: number of TSF timers available - */ -enum iwl_tsf_id { - TSF_ID_A = 0, - TSF_ID_B = 1, - TSF_ID_C = 2, - TSF_ID_D = 3, - NUM_TSF_IDS = 4, -}; /* TSF_ID_API_E_VER_1 */ - -/** - * struct iwl_mac_data_ap - configuration data for AP MAC context - * @beacon_time: beacon transmit time in system time - * @beacon_tsf: beacon transmit time in TSF - * @bi: beacon interval in TU - * @bi_reciprocal: 2^32 / bi - * @dtim_interval: dtim transmit time in TU - * @dtim_reciprocal: 2^32 / dtim_interval - * @mcast_qid: queue ID for multicast traffic - * @beacon_template: beacon template ID - */ -struct iwl_mac_data_ap { - __le32 beacon_time; - __le64 beacon_tsf; - __le32 bi; - __le32 bi_reciprocal; - __le32 dtim_interval; - __le32 dtim_reciprocal; - __le32 mcast_qid; - __le32 beacon_template; -} __packed; /* AP_MAC_DATA_API_S_VER_1 */ - -/** - * struct iwl_mac_data_ibss - configuration data for IBSS MAC context - * @beacon_time: beacon transmit time in system time - * @beacon_tsf: beacon transmit time in TSF - * @bi: beacon interval in TU - * @bi_reciprocal: 2^32 / bi - */ -struct iwl_mac_data_ibss { - __le32 beacon_time; - __le64 beacon_tsf; - __le32 bi; - __le32 bi_reciprocal; -} __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ - -/** - * struct iwl_mac_data_sta - configuration data for station MAC context - * @is_assoc: 1 for associated state, 0 otherwise - * @dtim_time: DTIM arrival time in system time - * @dtim_tsf: DTIM arrival time in TSF - * @bi: beacon interval in TU, applicable only when associated - * @bi_reciprocal: 2^32 / bi , applicable only when associated - * @dtim_interval: DTIM interval in TU, applicable only when associated - * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated - * @listen_interval: in beacon intervals, applicable only when associated - * @assoc_id: unique ID assigned by the AP during association - */ -struct iwl_mac_data_sta { - __le32 is_assoc; - __le32 dtim_time; - __le64 dtim_tsf; - __le32 bi; - __le32 bi_reciprocal; - __le32 dtim_interval; - __le32 dtim_reciprocal; - __le32 listen_interval; - __le32 assoc_id; - __le32 assoc_beacon_arrive_time; -} __packed; /* STA_MAC_DATA_API_S_VER_1 */ - -/** - * struct iwl_mac_data_go - configuration data for P2P GO MAC context - * @ap: iwl_mac_data_ap struct with most config data - * @ctwin: client traffic window in TU (period after TBTT when GO is present). - * 0 indicates that there is no CT window. - * @opp_ps_enabled: indicate that opportunistic PS allowed - */ -struct iwl_mac_data_go { - struct iwl_mac_data_ap ap; - __le32 ctwin; - __le32 opp_ps_enabled; -} __packed; /* GO_MAC_DATA_API_S_VER_1 */ - -/** - * struct iwl_mac_data_p2p_sta - configuration data for P2P client MAC context - * @sta: iwl_mac_data_sta struct with most config data - * @ctwin: client traffic window in TU (period after TBTT when GO is present). - * 0 indicates that there is no CT window. - */ -struct iwl_mac_data_p2p_sta { - struct iwl_mac_data_sta sta; - __le32 ctwin; -} __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */ - -/** - * struct iwl_mac_data_pibss - Pseudo IBSS config data - * @stats_interval: interval in TU between statistics notifications to host. - */ -struct iwl_mac_data_pibss { - __le32 stats_interval; -} __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */ - -/* - * struct iwl_mac_data_p2p_dev - configuration data for the P2P Device MAC - * context. - * @is_disc_extended: if set to true, P2P Device discoverability is enabled on - * other channels as well. This should be to true only in case that the - * device is discoverable and there is an active GO. Note that setting this - * field when not needed, will increase the number of interrupts and have - * effect on the platform power, as this setting opens the Rx filters on - * all macs. - */ -struct iwl_mac_data_p2p_dev { - __le32 is_disc_extended; -} __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */ - -/** - * enum iwl_mac_filter_flags - MAC context filter flags - * @MAC_FILTER_IN_PROMISC: accept all data frames - * @MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and - * control frames to the host - * @MAC_FILTER_ACCEPT_GRP: accept multicast frames - * @MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames - * @MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames - * @MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host - * (in station mode when associated) - * @MAC_FILTER_OUT_BCAST: filter out all broadcast frames - * @MAC_FILTER_IN_CRC32: extract FCS and append it to frames - * @MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host - */ -enum iwl_mac_filter_flags { - MAC_FILTER_IN_PROMISC = BIT(0), - MAC_FILTER_IN_CONTROL_AND_MGMT = BIT(1), - MAC_FILTER_ACCEPT_GRP = BIT(2), - MAC_FILTER_DIS_DECRYPT = BIT(3), - MAC_FILTER_DIS_GRP_DECRYPT = BIT(4), - MAC_FILTER_IN_BEACON = BIT(6), - MAC_FILTER_OUT_BCAST = BIT(8), - MAC_FILTER_IN_CRC32 = BIT(11), - MAC_FILTER_IN_PROBE_REQUEST = BIT(12), -}; - -/** - * enum iwl_mac_qos_flags - QoS flags - * @MAC_QOS_FLG_UPDATE_EDCA: ? - * @MAC_QOS_FLG_TGN: HT is enabled - * @MAC_QOS_FLG_TXOP_TYPE: ? - * - */ -enum iwl_mac_qos_flags { - MAC_QOS_FLG_UPDATE_EDCA = BIT(0), - MAC_QOS_FLG_TGN = BIT(1), - MAC_QOS_FLG_TXOP_TYPE = BIT(4), -}; - -/** - * struct iwl_ac_qos - QOS timing params for MAC_CONTEXT_CMD - * @cw_min: Contention window, start value in numbers of slots. - * Should be a power-of-2, minus 1. Device's default is 0x0f. - * @cw_max: Contention window, max value in numbers of slots. - * Should be a power-of-2, minus 1. Device's default is 0x3f. - * @aifsn: Number of slots in Arbitration Interframe Space (before - * performing random backoff timing prior to Tx). Device default 1. - * @fifos_mask: FIFOs used by this MAC for this AC - * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. - * - * One instance of this config struct for each of 4 EDCA access categories - * in struct iwl_qosparam_cmd. - * - * Device will automatically increase contention window by (2*CW) + 1 for each - * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW - * value, to cap the CW value. - */ -struct iwl_ac_qos { - __le16 cw_min; - __le16 cw_max; - u8 aifsn; - u8 fifos_mask; - __le16 edca_txop; -} __packed; /* AC_QOS_API_S_VER_2 */ - -/** - * struct iwl_mac_ctx_cmd - command structure to configure MAC contexts - * ( MAC_CONTEXT_CMD = 0x28 ) - * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* - * @mac_type: one of FW_MAC_TYPE_* - * @tsd_id: TSF HW timer, one of TSF_ID_* - * @node_addr: MAC address - * @bssid_addr: BSSID - * @cck_rates: basic rates available for CCK - * @ofdm_rates: basic rates available for OFDM - * @protection_flags: combination of MAC_PROT_FLG_FLAG_* - * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise - * @short_slot: 0x10 for enabling short slots, 0 otherwise - * @filter_flags: combination of MAC_FILTER_* - * @qos_flags: from MAC_QOS_FLG_* - * @ac: one iwl_mac_qos configuration for each AC - * @mac_specific: one of struct iwl_mac_data_*, according to mac_type - */ -struct iwl_mac_ctx_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - /* MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */ - __le32 mac_type; - __le32 tsf_id; - u8 node_addr[6]; - __le16 reserved_for_node_addr; - u8 bssid_addr[6]; - __le16 reserved_for_bssid_addr; - __le32 cck_rates; - __le32 ofdm_rates; - __le32 protection_flags; - __le32 cck_short_preamble; - __le32 short_slot; - __le32 filter_flags; - /* MAC_QOS_PARAM_API_S_VER_1 */ - __le32 qos_flags; - struct iwl_ac_qos ac[AC_NUM+1]; - /* MAC_CONTEXT_COMMON_DATA_API_S */ - union { - struct iwl_mac_data_ap ap; - struct iwl_mac_data_go go; - struct iwl_mac_data_sta sta; - struct iwl_mac_data_p2p_sta p2p_sta; - struct iwl_mac_data_p2p_dev p2p_dev; - struct iwl_mac_data_pibss pibss; - struct iwl_mac_data_ibss ibss; - }; -} __packed; /* MAC_CONTEXT_CMD_API_S_VER_1 */ - -static inline u32 iwl_mvm_reciprocal(u32 v) -{ - if (!v) - return 0; - return 0xFFFFFFFF / v; -} - -#endif /* __fw_api_mac_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h deleted file mode 100644 index be36b7604b7f..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ /dev/null @@ -1,140 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_power_h__ -#define __fw_api_power_h__ - -/* Power Management Commands, Responses, Notifications */ - -/** - * enum iwl_scan_flags - masks for power table command flags - * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, - * '1' Driver enables PM (use rest of parameters) - * @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, - * '1' PM could sleep over DTIM till listen Interval. - * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. - * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all - * access categories are both delivery and trigger enabled. - * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and - * PBW Snoozing enabled - * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask -*/ -enum iwl_power_flags { - POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(0), - POWER_FLAGS_SLEEP_OVER_DTIM_MSK = BIT(1), - POWER_FLAGS_LPRX_ENA_MSK = BIT(2), - POWER_FLAGS_SNOOZE_ENA_MSK = BIT(3), - POWER_FLAGS_BT_SCO_ENA = BIT(4), - POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(5) -}; - -/** - * struct iwl_powertable_cmd - Power Table Command - * POWER_TABLE_CMD = 0x77 (command, has simple generic response) - * - * @id_and_color: MAC contex identifier - * @action: Action on context - no action, add new, - * modify existent, remove - * @flags: Power table command flags from POWER_FLAGS_* - * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. - * Minimum allowed:- 3 * DTIM - * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to - * PSM transition - legacy PM - * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to - * PSM transition - legacy PM - * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to - * PSM transition - uAPSD - * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to - * PSM transition - uAPSD - * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. - * Default: 80dbm - * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set - * @snooze_interval: TBD - * @snooze_window: TBD - * @snooze_step: TBD - * @qndp_tid: TBD - * @uapsd_ac_flags: TBD - * @uapsd_max_sp: TBD - */ -struct iwl_powertable_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - __le16 flags; - u8 reserved; - __le16 keep_alive_seconds; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 rx_data_timeout_uapsd; - __le32 tx_data_timeout_uapsd; - u8 lprx_rssi_threshold; - u8 num_skip_dtim; - __le16 snooze_interval; - __le16 snooze_window; - u8 snooze_step; - u8 qndp_tid; - u8 uapsd_ac_flags; - u8 uapsd_max_sp; -} __packed; - -#endif diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h deleted file mode 100644 index aa3474d08231..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ /dev/null @@ -1,312 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_rs_h__ -#define __fw_api_rs_h__ - -#include "fw-api-mac.h" - -/* - * These serve as indexes into - * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT]; - */ -enum { - IWL_RATE_1M_INDEX = 0, - IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, - IWL_RATE_2M_INDEX, - IWL_RATE_5M_INDEX, - IWL_RATE_11M_INDEX, - IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, - IWL_RATE_6M_INDEX, - IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, - IWL_RATE_9M_INDEX, - IWL_RATE_12M_INDEX, - IWL_RATE_18M_INDEX, - IWL_RATE_24M_INDEX, - IWL_RATE_36M_INDEX, - IWL_RATE_48M_INDEX, - IWL_RATE_54M_INDEX, - IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX, - IWL_RATE_60M_INDEX, - IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, - IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1, - IWL_RATE_COUNT, -}; - -#define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX) - -/* fw API values for legacy bit rates, both OFDM and CCK */ -enum { - IWL_RATE_6M_PLCP = 13, - IWL_RATE_9M_PLCP = 15, - IWL_RATE_12M_PLCP = 5, - IWL_RATE_18M_PLCP = 7, - IWL_RATE_24M_PLCP = 9, - IWL_RATE_36M_PLCP = 11, - IWL_RATE_48M_PLCP = 1, - IWL_RATE_54M_PLCP = 3, - IWL_RATE_1M_PLCP = 10, - IWL_RATE_2M_PLCP = 20, - IWL_RATE_5M_PLCP = 55, - IWL_RATE_11M_PLCP = 110, -}; - -/* - * rate_n_flags bit fields - * - * The 32-bit value has different layouts in the low 8 bites depending on the - * format. There are three formats, HT, VHT and legacy (11abg, with subformats - * for CCK and OFDM). - * - * High-throughput (HT) rate format - * bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM) - * Very High-throughput (VHT) rate format - * bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM) - * Legacy OFDM rate format for bits 7:0 - * bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM) - * Legacy CCK rate format for bits 7:0: - * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK) - */ - -/* Bit 8: (1) HT format, (0) legacy or VHT format */ -#define RATE_MCS_HT_POS 8 -#define RATE_MCS_HT_MSK (1 << RATE_MCS_HT_POS) - -/* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ -#define RATE_MCS_CCK_POS 9 -#define RATE_MCS_CCK_MSK (1 << RATE_MCS_CCK_POS) - -/* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */ -#define RATE_MCS_VHT_POS 26 -#define RATE_MCS_VHT_MSK (1 << RATE_MCS_VHT_POS) - - -/* - * High-throughput (HT) rate format for bits 7:0 - * - * 2-0: MCS rate base - * 0) 6 Mbps - * 1) 12 Mbps - * 2) 18 Mbps - * 3) 24 Mbps - * 4) 36 Mbps - * 5) 48 Mbps - * 6) 54 Mbps - * 7) 60 Mbps - * 4-3: 0) Single stream (SISO) - * 1) Dual stream (MIMO) - * 2) Triple stream (MIMO) - * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data - * (bits 7-6 are zero) - * - * Together the low 5 bits work out to the MCS index because we don't - * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two - * streams and 16-23 have three streams. We could also support MCS 32 - * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) - */ -#define RATE_HT_MCS_RATE_CODE_MSK 0x7 - -/* Bit 10: (1) Use Green Field preamble */ -#define RATE_HT_MCS_GF_POS 10 -#define RATE_HT_MCS_GF_MSK (1 << RATE_HT_MCS_GF_POS) - -#define RATE_HT_MCS_INDEX_MSK 0x3f - -/* - * Very High-throughput (VHT) rate format for bits 7:0 - * - * 3-0: VHT MCS (0-9) - * 5-4: number of streams - 1: - * 0) Single stream (SISO) - * 1) Dual stream (MIMO) - * 2) Triple stream (MIMO) - */ - -/* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */ -#define RATE_VHT_MCS_RATE_CODE_MSK 0xf -#define RATE_VHT_MCS_NSS_POS 4 -#define RATE_VHT_MCS_NSS_MSK (3 << RATE_VHT_MCS_NSS_POS) - -/* - * Legacy OFDM rate format for bits 7:0 - * - * 3-0: 0xD) 6 Mbps - * 0xF) 9 Mbps - * 0x5) 12 Mbps - * 0x7) 18 Mbps - * 0x9) 24 Mbps - * 0xB) 36 Mbps - * 0x1) 48 Mbps - * 0x3) 54 Mbps - * (bits 7-4 are 0) - * - * Legacy CCK rate format for bits 7:0: - * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK): - * - * 6-0: 10) 1 Mbps - * 20) 2 Mbps - * 55) 5.5 Mbps - * 110) 11 Mbps - * (bit 7 is 0) - */ -#define RATE_LEGACY_RATE_MSK 0xff - - -/* - * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz - * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT - */ -#define RATE_MCS_CHAN_WIDTH_POS 11 -#define RATE_MCS_CHAN_WIDTH_MSK (3 << RATE_MCS_CHAN_WIDTH_POS) -#define RATE_MCS_CHAN_WIDTH_20 (0 << RATE_MCS_CHAN_WIDTH_POS) -#define RATE_MCS_CHAN_WIDTH_40 (1 << RATE_MCS_CHAN_WIDTH_POS) -#define RATE_MCS_CHAN_WIDTH_80 (2 << RATE_MCS_CHAN_WIDTH_POS) -#define RATE_MCS_CHAN_WIDTH_160 (3 << RATE_MCS_CHAN_WIDTH_POS) - -/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ -#define RATE_MCS_SGI_POS 13 -#define RATE_MCS_SGI_MSK (1 << RATE_MCS_SGI_POS) - -/* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */ -#define RATE_MCS_ANT_POS 14 -#define RATE_MCS_ANT_A_MSK (1 << RATE_MCS_ANT_POS) -#define RATE_MCS_ANT_B_MSK (2 << RATE_MCS_ANT_POS) -#define RATE_MCS_ANT_C_MSK (4 << RATE_MCS_ANT_POS) -#define RATE_MCS_ANT_AB_MSK (RATE_MCS_ANT_A_MSK | \ - RATE_MCS_ANT_B_MSK) -#define RATE_MCS_ANT_ABC_MSK (RATE_MCS_ANT_AB_MSK | \ - RATE_MCS_ANT_C_MSK) -#define RATE_MCS_ANT_MSK RATE_MCS_ANT_ABC_MSK -#define RATE_MCS_ANT_NUM 3 - -/* Bit 17-18: (0) SS, (1) SS*2 */ -#define RATE_MCS_STBC_POS 17 -#define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS) - -/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ -#define RATE_MCS_BF_POS 19 -#define RATE_MCS_BF_MSK (1 << RATE_MCS_BF_POS) - -/* Bit 20: (0) ZLF is off, (1) ZLF is on */ -#define RATE_MCS_ZLF_POS 20 -#define RATE_MCS_ZLF_MSK (1 << RATE_MCS_ZLF_POS) - -/* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */ -#define RATE_MCS_DUP_POS 24 -#define RATE_MCS_DUP_MSK (3 << RATE_MCS_DUP_POS) - -/* Bit 27: (1) LDPC enabled, (0) LDPC disabled */ -#define RATE_MCS_LDPC_POS 27 -#define RATE_MCS_LDPC_MSK (1 << RATE_MCS_LDPC_POS) - - -/* Link Quality definitions */ - -/* # entries in rate scale table to support Tx retries */ -#define LQ_MAX_RETRY_NUM 16 - -/* Link quality command flags, only this one is available */ -#define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0) - -/** - * struct iwl_lq_cmd - link quality command - * @sta_id: station to update - * @control: not used - * @flags: combination of LQ_FLAG_* - * @mimo_delim: the first SISO index in rs_table, which separates MIMO - * and SISO rates - * @single_stream_ant_msk: best antenna for SISO (can be dual in CDD). - * Should be ANT_[ABC] - * @dual_stream_ant_msk: best antennas for MIMO, combination of ANT_[ABC] - * @initial_rate_index: first index from rs_table per AC category - * @agg_time_limit: aggregation max time threshold in usec/100, meaning - * value of 100 is one usec. Range is 100 to 8000 - * @agg_disable_start_th: try-count threshold for starting aggregation. - * If a frame has higher try-count, it should not be selected for - * starting an aggregation sequence. - * @agg_frame_cnt_limit: max frame count in an aggregation. - * 0: no limit - * 1: no aggregation (one frame per aggregation) - * 2 - 0x3f: maximal number of frames (up to 3f == 63) - * @rs_table: array of rates for each TX try, each is rate_n_flags, - * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP - * @bf_params: beam forming params, currently not used - */ -struct iwl_lq_cmd { - u8 sta_id; - u8 reserved1; - u16 control; - /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ - u8 flags; - u8 mimo_delim; - u8 single_stream_ant_msk; - u8 dual_stream_ant_msk; - u8 initial_rate_index[AC_NUM]; - /* LINK_QUAL_AGG_PARAMS_API_S_VER_1 */ - __le16 agg_time_limit; - u8 agg_disable_start_th; - u8 agg_frame_cnt_limit; - __le32 reserved2; - __le32 rs_table[LQ_MAX_RETRY_NUM]; - __le32 bf_params; -}; /* LINK_QUALITY_CMD_API_S_VER_1 */ -#endif /* __fw_api_rs_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h deleted file mode 100644 index 670ac8f95e26..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ /dev/null @@ -1,561 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_scan_h__ -#define __fw_api_scan_h__ - -#include "fw-api.h" - -/* Scan Commands, Responses, Notifications */ - -/* Masks for iwl_scan_channel.type flags */ -#define SCAN_CHANNEL_TYPE_PASSIVE 0 -#define SCAN_CHANNEL_TYPE_ACTIVE BIT(0) -#define SCAN_CHANNEL_NARROW_BAND BIT(22) - -/* Max number of IEs for direct SSID scans in a command */ -#define PROBE_OPTION_MAX 20 - -/** - * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table - * @channel: band is selected by iwl_scan_cmd "flags" field - * @tx_gain: gain for analog radio - * @dsp_atten: gain for DSP - * @active_dwell: dwell time for active scan in TU, typically 5-50 - * @passive_dwell: dwell time for passive scan in TU, typically 20-500 - * @type: type is broken down to these bits: - * bit 0: 0 = passive, 1 = active - * bits 1-20: SSID direct bit map. If any of these bits is set then - * the corresponding SSID IE is transmitted in probe request - * (bit i adds IE in position i to the probe request) - * bit 22: channel width, 0 = regular, 1 = TGj narrow channel - * - * @iteration_count: - * @iteration_interval: - * This struct is used once for each channel in the scan list. - * Each channel can independently select: - * 1) SSID for directed active scans - * 2) Txpower setting (for rate specified within Tx command) - * 3) How long to stay on-channel (behavior may be modified by quiet_time, - * quiet_plcp_th, good_CRC_th) - * - * To avoid uCode errors, make sure the following are true (see comments - * under struct iwl_scan_cmd about max_out_time and quiet_time): - * 1) If using passive_dwell (i.e. passive_dwell != 0): - * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) - * 2) quiet_time <= active_dwell - * 3) If restricting off-channel time (i.e. max_out_time !=0): - * passive_dwell < max_out_time - * active_dwell < max_out_time - */ -struct iwl_scan_channel { - __le32 type; - __le16 channel; - __le16 iteration_count; - __le32 iteration_interval; - __le16 active_dwell; - __le16 passive_dwell; -} __packed; /* SCAN_CHANNEL_CONTROL_API_S_VER_1 */ - -/** - * struct iwl_ssid_ie - directed scan network information element - * - * Up to 20 of these may appear in REPLY_SCAN_CMD, - * selected by "type" bit field in struct iwl_scan_channel; - * each channel may select different ssids from among the 20 entries. - * SSID IEs get transmitted in reverse order of entry. - */ -struct iwl_ssid_ie { - u8 id; - u8 len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; -} __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ - -/** - * iwl_scan_flags - masks for scan command flags - *@SCAN_FLAGS_PERIODIC_SCAN: - *@SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX: - *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND: - *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND: - *@SCAN_FLAGS_FRAGMENTED_SCAN: - */ -enum iwl_scan_flags { - SCAN_FLAGS_PERIODIC_SCAN = BIT(0), - SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX = BIT(1), - SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2), - SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3), - SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4), -}; - -/** - * enum iwl_scan_type - Scan types for scan command - * @SCAN_TYPE_FORCED: - * @SCAN_TYPE_BACKGROUND: - * @SCAN_TYPE_OS: - * @SCAN_TYPE_ROAMING: - * @SCAN_TYPE_ACTION: - * @SCAN_TYPE_DISCOVERY: - * @SCAN_TYPE_DISCOVERY_FORCED: - */ -enum iwl_scan_type { - SCAN_TYPE_FORCED = 0, - SCAN_TYPE_BACKGROUND = 1, - SCAN_TYPE_OS = 2, - SCAN_TYPE_ROAMING = 3, - SCAN_TYPE_ACTION = 4, - SCAN_TYPE_DISCOVERY = 5, - SCAN_TYPE_DISCOVERY_FORCED = 6, -}; /* SCAN_ACTIVITY_TYPE_E_VER_1 */ - -/* Maximal number of channels to scan */ -#define MAX_NUM_SCAN_CHANNELS 0x24 - -/** - * struct iwl_scan_cmd - scan request command - * ( SCAN_REQUEST_CMD = 0x80 ) - * @len: command length in bytes - * @scan_flags: scan flags from SCAN_FLAGS_* - * @channel_count: num of channels in channel list (1 - MAX_NUM_SCAN_CHANNELS) - * @quiet_time: in msecs, dwell this time for active scan on quiet channels - * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than - * this number of packets were received (typically 1) - * @passive2active: is auto switching from passive to active allowed (0 or 1) - * @rxchain_sel_flags: RXON_RX_CHAIN_* - * @max_out_time: in usecs, max out of serving channel time - * @suspend_time: how long to pause scan when returning to service channel: - * bits 0-19: beacon interal in usecs (suspend before executing) - * bits 20-23: reserved - * bits 24-31: number of beacons (suspend between channels) - * @rxon_flags: RXON_FLG_* - * @filter_flags: RXON_FILTER_* - * @tx_cmd: for active scans (zero for passive), w/o payload, - * no RS so specify TX rate - * @direct_scan: direct scan SSIDs - * @type: one of SCAN_TYPE_* - * @repeats: how many time to repeat the scan - */ -struct iwl_scan_cmd { - __le16 len; - u8 scan_flags; - u8 channel_count; - __le16 quiet_time; - __le16 quiet_plcp_th; - __le16 passive2active; - __le16 rxchain_sel_flags; - __le32 max_out_time; - __le32 suspend_time; - /* RX_ON_FLAGS_API_S_VER_1 */ - __le32 rxon_flags; - __le32 filter_flags; - struct iwl_tx_cmd tx_cmd; - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; - __le32 type; - __le32 repeats; - - /* - * Probe request frame, followed by channel list. - * - * Size of probe request frame is specified by byte count in tx_cmd. - * Channel list follows immediately after probe request frame. - * Number of channels in list is specified by channel_count. - * Each channel in list is of type: - * - * struct iwl_scan_channel channels[0]; - * - * NOTE: Only one band of channels can be scanned per pass. You - * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait - * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) - * before requesting another scan. - */ - u8 data[0]; -} __packed; /* SCAN_REQUEST_FIXED_PART_API_S_VER_5 */ - -/* Response to scan request contains only status with one of these values */ -#define SCAN_RESPONSE_OK 0x1 -#define SCAN_RESPONSE_ERROR 0x2 - -/* - * SCAN_ABORT_CMD = 0x81 - * When scan abort is requested, the command has no fields except the common - * header. The response contains only a status with one of these values. - */ -#define SCAN_ABORT_POSSIBLE 0x1 -#define SCAN_ABORT_IGNORED 0x2 /* no pending scans */ - -/* TODO: complete documentation */ -#define SCAN_OWNER_STATUS 0x1 -#define MEASURE_OWNER_STATUS 0x2 - -/** - * struct iwl_scan_start_notif - notifies start of scan in the device - * ( SCAN_START_NOTIFICATION = 0x82 ) - * @tsf_low: TSF timer (lower half) in usecs - * @tsf_high: TSF timer (higher half) in usecs - * @beacon_timer: structured as follows: - * bits 0:19 - beacon interval in usecs - * bits 20:23 - reserved (0) - * bits 24:31 - number of beacons - * @channel: which channel is scanned - * @band: 0 for 5.2 GHz, 1 for 2.4 GHz - * @status: one of *_OWNER_STATUS - */ -struct iwl_scan_start_notif { - __le32 tsf_low; - __le32 tsf_high; - __le32 beacon_timer; - u8 channel; - u8 band; - u8 reserved[2]; - __le32 status; -} __packed; /* SCAN_START_NTF_API_S_VER_1 */ - -/* scan results probe_status first bit indicates success */ -#define SCAN_PROBE_STATUS_OK 0 -#define SCAN_PROBE_STATUS_TX_FAILED BIT(0) -/* error statuses combined with TX_FAILED */ -#define SCAN_PROBE_STATUS_FAIL_TTL BIT(1) -#define SCAN_PROBE_STATUS_FAIL_BT BIT(2) - -/* How many statistics are gathered for each channel */ -#define SCAN_RESULTS_STATISTICS 1 - -/** - * enum iwl_scan_complete_status - status codes for scan complete notifications - * @SCAN_COMP_STATUS_OK: scan completed successfully - * @SCAN_COMP_STATUS_ABORT: scan was aborted by user - * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed - * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready - * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed - * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed - * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command - * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort - * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax - * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful - * (not an error!) - * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver - * asked for - * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events -*/ -enum iwl_scan_complete_status { - SCAN_COMP_STATUS_OK = 0x1, - SCAN_COMP_STATUS_ABORT = 0x2, - SCAN_COMP_STATUS_ERR_SLEEP = 0x3, - SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4, - SCAN_COMP_STATUS_ERR_PROBE = 0x5, - SCAN_COMP_STATUS_ERR_WAKEUP = 0x6, - SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7, - SCAN_COMP_STATUS_ERR_INTERNAL = 0x8, - SCAN_COMP_STATUS_ERR_COEX = 0x9, - SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA, - SCAN_COMP_STATUS_ITERATION_END = 0x0B, - SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, -}; - -/** - * struct iwl_scan_results_notif - scan results for one channel - * ( SCAN_RESULTS_NOTIFICATION = 0x83 ) - * @channel: which channel the results are from - * @band: 0 for 5.2 GHz, 1 for 2.4 GHz - * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request - * @num_probe_not_sent: # of request that weren't sent due to not enough time - * @duration: duration spent in channel, in usecs - * @statistics: statistics gathered for this channel - */ -struct iwl_scan_results_notif { - u8 channel; - u8 band; - u8 probe_status; - u8 num_probe_not_sent; - __le32 duration; - __le32 statistics[SCAN_RESULTS_STATISTICS]; -} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */ - -/** - * struct iwl_scan_complete_notif - notifies end of scanning (all channels) - * ( SCAN_COMPLETE_NOTIFICATION = 0x84 ) - * @scanned_channels: number of channels scanned (and number of valid results) - * @status: one of SCAN_COMP_STATUS_* - * @bt_status: BT on/off status - * @last_channel: last channel that was scanned - * @tsf_low: TSF timer (lower half) in usecs - * @tsf_high: TSF timer (higher half) in usecs - * @results: all scan results, only "scanned_channels" of them are valid - */ -struct iwl_scan_complete_notif { - u8 scanned_channels; - u8 status; - u8 bt_status; - u8 last_channel; - __le32 tsf_low; - __le32 tsf_high; - struct iwl_scan_results_notif results[MAX_NUM_SCAN_CHANNELS]; -} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */ - -/* scan offload */ -#define IWL_MAX_SCAN_CHANNELS 40 -#define IWL_SCAN_MAX_BLACKLIST_LEN 64 -#define IWL_SCAN_MAX_PROFILES 11 -#define SCAN_OFFLOAD_PROBE_REQ_SIZE 512 - -/* Default watchdog (in MS) for scheduled scan iteration */ -#define IWL_SCHED_SCAN_WATCHDOG cpu_to_le16(15000) - -#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1) -#define CAN_ABORT_STATUS 1 - -#define IWL_FULL_SCAN_MULTIPLIER 5 -#define IWL_FAST_SCHED_SCAN_ITERATIONS 3 - -/** - * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 - * @scan_flags: see enum iwl_scan_flags - * @channel_count: channels in channel list - * @quiet_time: dwell time, in milisiconds, on quiet channel - * @quiet_plcp_th: quiet channel num of packets threshold - * @good_CRC_th: passive to active promotion threshold - * @rx_chain: RXON rx chain. - * @max_out_time: max uSec to be out of assoceated channel - * @suspend_time: pause scan this long when returning to service channel - * @flags: RXON flags - * @filter_flags: RXONfilter - * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz. - * @direct_scan: list of SSIDs for directed active scan - * @scan_type: see enum iwl_scan_type. - * @rep_count: repetition count for each scheduled scan iteration. - */ -struct iwl_scan_offload_cmd { - __le16 len; - u8 scan_flags; - u8 channel_count; - __le16 quiet_time; - __le16 quiet_plcp_th; - __le16 good_CRC_th; - __le16 rx_chain; - __le32 max_out_time; - __le32 suspend_time; - /* RX_ON_FLAGS_API_S_VER_1 */ - __le32 flags; - __le32 filter_flags; - struct iwl_tx_cmd tx_cmd[2]; - /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; - __le32 scan_type; - __le32 rep_count; -} __packed; - -enum iwl_scan_offload_channel_flags { - IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE = BIT(0), - IWL_SCAN_OFFLOAD_CHANNEL_NARROW = BIT(22), - IWL_SCAN_OFFLOAD_CHANNEL_FULL = BIT(24), - IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25), -}; - -/** - * iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S - * @type: bitmap - see enum iwl_scan_offload_channel_flags. - * 0: passive (0) or active (1) scan. - * 1-20: directed scan to i'th ssid. - * 22: channel width configuation - 1 for narrow. - * 24: full scan. - * 25: partial scan. - * @channel_number: channel number 1-13 etc. - * @iter_count: repetition count for the channel. - * @iter_interval: interval between two innteration on one channel. - * @dwell_time: entry 0 - active scan, entry 1 - passive scan. - */ -struct iwl_scan_channel_cfg { - __le32 type[IWL_MAX_SCAN_CHANNELS]; - __le16 channel_number[IWL_MAX_SCAN_CHANNELS]; - __le16 iter_count[IWL_MAX_SCAN_CHANNELS]; - __le32 iter_interval[IWL_MAX_SCAN_CHANNELS]; - u8 dwell_time[IWL_MAX_SCAN_CHANNELS][2]; -} __packed; - -/** - * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S - * @scan_cmd: scan command fixed part - * @channel_cfg: scan channel configuration - * @data: probe request frames (one per band) - */ -struct iwl_scan_offload_cfg { - struct iwl_scan_offload_cmd scan_cmd; - struct iwl_scan_channel_cfg channel_cfg; - u8 data[0]; -} __packed; - -/** - * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S - * @ssid: MAC address to filter out - * @reported_rssi: AP rssi reported to the host - */ -struct iwl_scan_offload_blacklist { - u8 ssid[ETH_ALEN]; - u8 reported_rssi; - u8 reserved; -} __packed; - -enum iwl_scan_offload_network_type { - IWL_NETWORK_TYPE_BSS = 1, - IWL_NETWORK_TYPE_IBSS = 2, - IWL_NETWORK_TYPE_ANY = 3, -}; - -enum iwl_scan_offload_band_selection { - IWL_SCAN_OFFLOAD_SELECT_2_4 = 0x4, - IWL_SCAN_OFFLOAD_SELECT_5_2 = 0x8, - IWL_SCAN_OFFLOAD_SELECT_ANY = 0xc, -}; - -/** - * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S - * @ssid_index: index to ssid list in fixed part - * @unicast_cipher: encryption olgorithm to match - bitmap - * @aut_alg: authentication olgorithm to match - bitmap - * @network_type: enum iwl_scan_offload_network_type - * @band_selection: enum iwl_scan_offload_band_selection - */ -struct iwl_scan_offload_profile { - u8 ssid_index; - u8 unicast_cipher; - u8 auth_alg; - u8 network_type; - u8 band_selection; - u8 reserved[3]; -} __packed; - -/** - * iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 - * @blaclist: AP list to filter off from scan results - * @profiles: profiles to search for match - * @blacklist_len: length of blacklist - * @num_profiles: num of profiles in the list - */ -struct iwl_scan_offload_profile_cfg { - struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN]; - struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; - u8 blacklist_len; - u8 num_profiles; - u8 reserved[2]; -} __packed; - -/** - * iwl_scan_offload_schedule - schedule of scan offload - * @delay: delay between iterations, in seconds. - * @iterations: num of scan iterations - * @full_scan_mul: number of partial scans before each full scan - */ -struct iwl_scan_offload_schedule { - u16 delay; - u8 iterations; - u8 full_scan_mul; -} __packed; - -/* - * iwl_scan_offload_flags - * - * IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match - * ssid list. - * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan. - * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan - * on A band. - */ -enum iwl_scan_offload_flags { - IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID = BIT(0), - IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2), - IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3), -}; - -/** - * iwl_scan_offload_req - scan offload request command - * @flags: bitmap - enum iwl_scan_offload_flags. - * @watchdog: maximum scan duration in TU. - * @delay: delay in seconds before first iteration. - * @schedule_line: scan offload schedule, for fast and regular scan. - */ -struct iwl_scan_offload_req { - __le16 flags; - __le16 watchdog; - __le16 delay; - __le16 reserved; - struct iwl_scan_offload_schedule schedule_line[2]; -} __packed; - -enum iwl_scan_offload_compleate_status { - IWL_SCAN_OFFLOAD_COMPLETED = 1, - IWL_SCAN_OFFLOAD_ABORTED = 2, -}; - -/** - * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1 - * @last_schedule_line: last schedule line executed (fast or regular) - * @last_schedule_iteration: last scan iteration executed before scan abort - * @status: enum iwl_scan_offload_compleate_status - */ -struct iwl_scan_offload_complete { - u8 last_schedule_line; - u8 last_schedule_iteration; - u8 status; - u8 reserved; -} __packed; - -#endif diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h deleted file mode 100644 index 0acb53dda22d..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ /dev/null @@ -1,380 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_sta_h__ -#define __fw_api_sta_h__ - -/** - * enum iwl_sta_flags - flags for the ADD_STA host command - * @STA_FLG_REDUCED_TX_PWR_CTRL: - * @STA_FLG_REDUCED_TX_PWR_DATA: - * @STA_FLG_FLG_ANT_MSK: Antenna selection - * @STA_FLG_PS: set if STA is in Power Save - * @STA_FLG_INVALID: set if STA is invalid - * @STA_FLG_DLP_EN: Direct Link Protocol is enabled - * @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs - * @STA_FLG_DRAIN_FLOW: drain flow - * @STA_FLG_PAN: STA is for PAN interface - * @STA_FLG_CLASS_AUTH: - * @STA_FLG_CLASS_ASSOC: - * @STA_FLG_CLASS_MIMO_PROT: - * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU - * @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation - * @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is - * initialised by driver and can be updated by fw upon reception of - * action frames that can change the channel width. When cleared the fw - * will send all the frames in 20MHz even when FAT channel is requested. - * @STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the - * driver and can be updated by fw upon reception of action frames. - * @STA_FLG_MFP_EN: Management Frame Protection - */ -enum iwl_sta_flags { - STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3), - STA_FLG_REDUCED_TX_PWR_DATA = BIT(6), - - STA_FLG_FLG_ANT_A = (1 << 4), - STA_FLG_FLG_ANT_B = (2 << 4), - STA_FLG_FLG_ANT_MSK = (STA_FLG_FLG_ANT_A | - STA_FLG_FLG_ANT_B), - - STA_FLG_PS = BIT(8), - STA_FLG_INVALID = BIT(9), - STA_FLG_DLP_EN = BIT(10), - STA_FLG_SET_ALL_KEYS = BIT(11), - STA_FLG_DRAIN_FLOW = BIT(12), - STA_FLG_PAN = BIT(13), - STA_FLG_CLASS_AUTH = BIT(14), - STA_FLG_CLASS_ASSOC = BIT(15), - STA_FLG_RTS_MIMO_PROT = BIT(17), - - STA_FLG_MAX_AGG_SIZE_SHIFT = 19, - STA_FLG_MAX_AGG_SIZE_8K = (0 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_16K = (1 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_32K = (2 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_64K = (3 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_128K = (4 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_256K = (5 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_512K = (6 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_1024K = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_MSK = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT), - - STA_FLG_AGG_MPDU_DENS_SHIFT = 23, - STA_FLG_AGG_MPDU_DENS_2US = (4 << STA_FLG_AGG_MPDU_DENS_SHIFT), - STA_FLG_AGG_MPDU_DENS_4US = (5 << STA_FLG_AGG_MPDU_DENS_SHIFT), - STA_FLG_AGG_MPDU_DENS_8US = (6 << STA_FLG_AGG_MPDU_DENS_SHIFT), - STA_FLG_AGG_MPDU_DENS_16US = (7 << STA_FLG_AGG_MPDU_DENS_SHIFT), - STA_FLG_AGG_MPDU_DENS_MSK = (7 << STA_FLG_AGG_MPDU_DENS_SHIFT), - - STA_FLG_FAT_EN_20MHZ = (0 << 26), - STA_FLG_FAT_EN_40MHZ = (1 << 26), - STA_FLG_FAT_EN_80MHZ = (2 << 26), - STA_FLG_FAT_EN_160MHZ = (3 << 26), - STA_FLG_FAT_EN_MSK = (3 << 26), - - STA_FLG_MIMO_EN_SISO = (0 << 28), - STA_FLG_MIMO_EN_MIMO2 = (1 << 28), - STA_FLG_MIMO_EN_MIMO3 = (2 << 28), - STA_FLG_MIMO_EN_MSK = (3 << 28), -}; - -/** - * enum iwl_sta_key_flag - key flags for the ADD_STA host command - * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm - * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from - * station info array (1 - n 1X mode) - * @STA_KEY_FLG_KEYID_MSK: the index of the key - * @STA_KEY_NOT_VALID: key is invalid - * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key - * @STA_KEY_MULTICAST: set for multical key - * @STA_KEY_MFP: key is used for Management Frame Protection - */ -enum iwl_sta_key_flag { - STA_KEY_FLG_NO_ENC = (0 << 0), - STA_KEY_FLG_WEP = (1 << 0), - STA_KEY_FLG_CCM = (2 << 0), - STA_KEY_FLG_TKIP = (3 << 0), - STA_KEY_FLG_CMAC = (6 << 0), - STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), - STA_KEY_FLG_EN_MSK = (7 << 0), - - STA_KEY_FLG_WEP_KEY_MAP = BIT(3), - STA_KEY_FLG_KEYID_POS = 8, - STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS), - STA_KEY_NOT_VALID = BIT(11), - STA_KEY_FLG_WEP_13BYTES = BIT(12), - STA_KEY_MULTICAST = BIT(14), - STA_KEY_MFP = BIT(15), -}; - -/** - * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed - * @STA_MODIFY_KEY: this command modifies %key - * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx - * @STA_MODIFY_TX_RATE: unused - * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid - * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid - * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count - * @STA_MODIFY_PROT_TH: - * @STA_MODIFY_QUEUES: modify the queues used by this station - */ -enum iwl_sta_modify_flag { - STA_MODIFY_KEY = BIT(0), - STA_MODIFY_TID_DISABLE_TX = BIT(1), - STA_MODIFY_TX_RATE = BIT(2), - STA_MODIFY_ADD_BA_TID = BIT(3), - STA_MODIFY_REMOVE_BA_TID = BIT(4), - STA_MODIFY_SLEEPING_STA_TX_COUNT = BIT(5), - STA_MODIFY_PROT_TH = BIT(6), - STA_MODIFY_QUEUES = BIT(7), -}; - -#define STA_MODE_MODIFY 1 - -/** - * enum iwl_sta_sleep_flag - type of sleep of the station - * @STA_SLEEP_STATE_AWAKE: - * @STA_SLEEP_STATE_PS_POLL: - * @STA_SLEEP_STATE_UAPSD: - */ -enum iwl_sta_sleep_flag { - STA_SLEEP_STATE_AWAKE = 0, - STA_SLEEP_STATE_PS_POLL = BIT(0), - STA_SLEEP_STATE_UAPSD = BIT(1), -}; - -/* STA ID and color bits definitions */ -#define STA_ID_SEED (0x0f) -#define STA_ID_POS (0) -#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS) - -#define STA_COLOR_SEED (0x7) -#define STA_COLOR_POS (4) -#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS) - -#define STA_ID_N_COLOR_GET_COLOR(id_n_color) \ - (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS) -#define STA_ID_N_COLOR_GET_ID(id_n_color) \ - (((id_n_color) & STA_ID_MSK) >> STA_ID_POS) - -#define STA_KEY_MAX_NUM (16) -#define STA_KEY_IDX_INVALID (0xff) -#define STA_KEY_MAX_DATA_KEY_NUM (4) -#define IWL_MAX_GLOBAL_KEYS (4) -#define STA_KEY_LEN_WEP40 (5) -#define STA_KEY_LEN_WEP104 (13) - -/** - * struct iwl_mvm_keyinfo - key information - * @key_flags: type %iwl_sta_key_flag - * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection - * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx - * @key_offset: key offset in the fw's key table - * @key: 16-byte unicast decryption key - * @tx_secur_seq_cnt: initial RSC / PN needed for replay check - * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only - * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only - */ -struct iwl_mvm_keyinfo { - __le16 key_flags; - u8 tkip_rx_tsc_byte2; - u8 reserved1; - __le16 tkip_rx_ttak[5]; - u8 key_offset; - u8 reserved2; - u8 key[16]; - __le64 tx_secur_seq_cnt; - __le64 hw_tkip_mic_rx_key; - __le64 hw_tkip_mic_tx_key; -} __packed; - -/** - * struct iwl_mvm_add_sta_cmd - Add / modify a station in the fw's station table - * ( REPLY_ADD_STA = 0x18 ) - * @add_modify: 1: modify existing, 0: add new station - * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent - * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key - * sent - * @mac_id_n_color: the Mac context this station belongs to - * @addr[ETH_ALEN]: station's MAC address - * @sta_id: index of station in uCode's station table - * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave - * alone. 1 - modify, 0 - don't change. - * @key: look at %iwl_mvm_keyinfo - * @station_flags: look at %iwl_sta_flags - * @station_flags_msk: what of %station_flags have changed - * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable - * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. - * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) - * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set - * add_immediate_ba_ssn. - * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) - * Set %STA_MODIFY_REMOVE_BA_TID to use this field - * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with - * add_immediate_ba_tid. - * @sleep_tx_count: number of packets to transmit to station even though it is - * asleep. Used to synchronise PS-poll and u-APSD responses while ucode - * keeps track of STA sleep state. - * @sleep_state_flags: Look at %iwl_sta_sleep_flag. - * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP - * mac-addr. - * @beamform_flags: beam forming controls - * @tfd_queue_msk: tfd queues used by this station - * - * The device contains an internal table of per-station information, with info - * on security keys, aggregation parameters, and Tx rates for initial Tx - * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). - * - * ADD_STA sets up the table entry for one station, either creating a new - * entry, or modifying a pre-existing one. - */ -struct iwl_mvm_add_sta_cmd { - u8 add_modify; - u8 unicast_tx_key_id; - u8 multicast_tx_key_id; - u8 reserved1; - __le32 mac_id_n_color; - u8 addr[ETH_ALEN]; - __le16 reserved2; - u8 sta_id; - u8 modify_mask; - __le16 reserved3; - struct iwl_mvm_keyinfo key; - __le32 station_flags; - __le32 station_flags_msk; - __le16 tid_disable_tx; - __le16 reserved4; - u8 add_immediate_ba_tid; - u8 remove_immediate_ba_tid; - __le16 add_immediate_ba_ssn; - __le16 sleep_tx_count; - __le16 sleep_state_flags; - __le16 assoc_id; - __le16 beamform_flags; - __le32 tfd_queue_msk; -} __packed; /* ADD_STA_CMD_API_S_VER_5 */ - -/** - * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command - * @ADD_STA_SUCCESS: operation was executed successfully - * @ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table - * @ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session - * @ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station that - * doesn't exist. - */ -enum iwl_mvm_add_sta_rsp_status { - ADD_STA_SUCCESS = 0x1, - ADD_STA_STATIONS_OVERLOAD = 0x2, - ADD_STA_IMMEDIATE_BA_FAILURE = 0x4, - ADD_STA_MODIFY_NON_EXISTING_STA = 0x8, -}; - -/** - * struct iwl_mvm_rm_sta_cmd - Add / modify a station in the fw's station table - * ( REMOVE_STA = 0x19 ) - * @sta_id: the station id of the station to be removed - */ -struct iwl_mvm_rm_sta_cmd { - u8 sta_id; - u8 reserved[3]; -} __packed; /* REMOVE_STA_CMD_API_S_VER_2 */ - -/** - * struct iwl_mvm_mgmt_mcast_key_cmd - * ( MGMT_MCAST_KEY = 0x1f ) - * @ctrl_flags: %iwl_sta_key_flag - * @IGTK: - * @K1: IGTK master key - * @K2: IGTK sub key - * @sta_id: station ID that support IGTK - * @key_id: - * @receive_seq_cnt: initial RSC/PN needed for replay check - */ -struct iwl_mvm_mgmt_mcast_key_cmd { - __le32 ctrl_flags; - u8 IGTK[16]; - u8 K1[16]; - u8 K2[16]; - __le32 key_id; - __le32 sta_id; - __le64 receive_seq_cnt; -} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ - -struct iwl_mvm_wep_key { - u8 key_index; - u8 key_offset; - __le16 reserved1; - u8 key_size; - u8 reserved2[3]; - u8 key[16]; -} __packed; - -struct iwl_mvm_wep_key_cmd { - __le32 mac_id_n_color; - u8 num_keys; - u8 decryption_type; - u8 flags; - u8 reserved; - struct iwl_mvm_wep_key wep_key[0]; -} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ - - -#endif /* __fw_api_sta_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h deleted file mode 100644 index 2677914bf0a6..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ /dev/null @@ -1,580 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_tx_h__ -#define __fw_api_tx_h__ - -/** - * enum iwl_tx_flags - bitmasks for tx_flags in TX command - * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame - * @TX_CMD_FLG_ACK: expect ACK from receiving station - * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. - * Otherwise, use rate_n_flags from the TX command - * @TX_CMD_FLG_BA: this frame is a block ack - * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected - * Must set TX_CMD_FLG_ACK with this flag. - * @TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection - * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence - * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence - * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) - * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame - * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. - * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command - * @TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU - * @TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame - * @TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame - * Should be set for beacons and probe responses - * @TX_CMD_FLG_CALIB: activate PA TX power calibrations - * @TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count - * @TX_CMD_FLG_AGG_START: allow this frame to start aggregation - * @TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header. - * Should be set for 26/30 length MAC headers - * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW - * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration - * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation - * @TX_CMD_FLG_CTS_ONLY: send CTS only, no data after that - * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id - * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped - * @TX_CMD_FLG_EXEC_PAPD: execute PAPD - * @TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power - * @TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk - */ -enum iwl_tx_flags { - TX_CMD_FLG_PROT_REQUIRE = BIT(0), - TX_CMD_FLG_ACK = BIT(3), - TX_CMD_FLG_STA_RATE = BIT(4), - TX_CMD_FLG_BA = BIT(5), - TX_CMD_FLG_BAR = BIT(6), - TX_CMD_FLG_TXOP_PROT = BIT(7), - TX_CMD_FLG_VHT_NDPA = BIT(8), - TX_CMD_FLG_HT_NDPA = BIT(9), - TX_CMD_FLG_CSI_FDBK2HOST = BIT(10), - TX_CMD_FLG_BT_DIS = BIT(12), - TX_CMD_FLG_SEQ_CTL = BIT(13), - TX_CMD_FLG_MORE_FRAG = BIT(14), - TX_CMD_FLG_NEXT_FRAME = BIT(15), - TX_CMD_FLG_TSF = BIT(16), - TX_CMD_FLG_CALIB = BIT(17), - TX_CMD_FLG_KEEP_SEQ_CTL = BIT(18), - TX_CMD_FLG_AGG_START = BIT(19), - TX_CMD_FLG_MH_PAD = BIT(20), - TX_CMD_FLG_RESP_TO_DRV = BIT(21), - TX_CMD_FLG_CCMP_AGG = BIT(22), - TX_CMD_FLG_TKIP_MIC_DONE = BIT(23), - TX_CMD_FLG_CTS_ONLY = BIT(24), - TX_CMD_FLG_DUR = BIT(25), - TX_CMD_FLG_FW_DROP = BIT(26), - TX_CMD_FLG_EXEC_PAPD = BIT(27), - TX_CMD_FLG_PAPD_TYPE = BIT(28), - TX_CMD_FLG_HCCA_CHUNK = BIT(31) -}; /* TX_FLAGS_BITS_API_S_VER_1 */ - -/* - * TX command security control - */ -#define TX_CMD_SEC_WEP 0x01 -#define TX_CMD_SEC_CCM 0x02 -#define TX_CMD_SEC_TKIP 0x03 -#define TX_CMD_SEC_WEP_KEY_IDX_POS 6 -#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 -#define TX_CMD_SEC_KEY128 0x08 - -/* TODO: how does these values are OK with only 16 bit variable??? */ -/* - * TX command next frame info - * - * bits 0:2 - security control (TX_CMD_SEC_*) - * bit 3 - immediate ACK required - * bit 4 - rate is taken from STA table - * bit 5 - frame belongs to BA stream - * bit 6 - immediate BA response expected - * bit 7 - unused - * bits 8:15 - Station ID - * bits 16:31 - rate - */ -#define TX_CMD_NEXT_FRAME_ACK_MSK (0x8) -#define TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) -#define TX_CMD_NEXT_FRAME_BA_MSK (0x20) -#define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) -#define TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) -#define TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) -#define TX_CMD_NEXT_FRAME_STA_ID_POS (8) -#define TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) -#define TX_CMD_NEXT_FRAME_RATE_POS (16) - -/* - * TX command Frame life time in us - to be written in pm_frame_timeout - */ -#define TX_CMD_LIFE_TIME_INFINITE 0xFFFFFFFF -#define TX_CMD_LIFE_TIME_DEFAULT 2000000 /* 2000 ms*/ -#define TX_CMD_LIFE_TIME_PROBE_RESP 40000 /* 40 ms */ -#define TX_CMD_LIFE_TIME_EXPIRED_FRAME 0 - -/* - * TID for non QoS frames - to be written in tid_tspec - */ -#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT - -/* - * Limits on the retransmissions - to be written in {data,rts}_retry_limit - */ -#define IWL_DEFAULT_TX_RETRY 15 -#define IWL_MGMT_DFAULT_RETRY_LIMIT 3 -#define IWL_RTS_DFAULT_RETRY_LIMIT 60 -#define IWL_BAR_DFAULT_RETRY_LIMIT 60 -#define IWL_LOW_RETRY_LIMIT 7 - -/* TODO: complete documentation for try_cnt and btkill_cnt */ -/** - * struct iwl_tx_cmd - TX command struct to FW - * ( TX_CMD = 0x1c ) - * @len: in bytes of the payload, see below for details - * @next_frame_len: same as len, but for next frame (0 if not applicable) - * Used for fragmentation and bursting, but not in 11n aggregation. - * @tx_flags: combination of TX_CMD_FLG_* - * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is - * cleared. Combination of RATE_MCS_* - * @sta_id: index of destination station in FW station table - * @sec_ctl: security control, TX_CMD_SEC_* - * @initial_rate_index: index into the the rate table for initial TX attempt. - * Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. - * @key: security key - * @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_* - * @life_time: frame life time (usecs??) - * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt + - * btkill_cnd + reserved), first 32 bits. "0" disables usage. - * @dram_msb_ptr: upper bits of the scratch physical address - * @rts_retry_limit: max attempts for RTS - * @data_retry_limit: max attempts to send the data packet - * @tid_spec: TID/tspec - * @pm_frame_timeout: PM TX frame timeout - * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not - * specified by HCCA protocol - * - * The byte count (both len and next_frame_len) includes MAC header - * (24/26/30/32 bytes) - * + 2 bytes pad if 26/30 header size - * + 8 byte IV for CCM or TKIP (not used for WEP) - * + Data payload - * + 8-byte MIC (not used for CCM/WEP) - * It does not include post-MAC padding, i.e., - * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes. - * Range of len: 14-2342 bytes. - * - * After the struct fields the MAC header is placed, plus any padding, - * and then the actial payload. - */ -struct iwl_tx_cmd { - __le16 len; - __le16 next_frame_len; - __le32 tx_flags; - /* DRAM_SCRATCH_API_U_VER_1 */ - u8 try_cnt; - u8 btkill_cnt; - __le16 reserved; - __le32 rate_n_flags; - u8 sta_id; - u8 sec_ctl; - u8 initial_rate_index; - u8 reserved2; - u8 key[16]; - __le16 next_frame_flags; - __le16 reserved3; - __le32 life_time; - __le32 dram_lsb_ptr; - u8 dram_msb_ptr; - u8 rts_retry_limit; - u8 data_retry_limit; - u8 tid_tspec; - __le16 pm_frame_timeout; - __le16 driver_txop; - u8 payload[0]; - struct ieee80211_hdr hdr[0]; -} __packed; /* TX_CMD_API_S_VER_3 */ - -/* - * TX response related data - */ - -/* - * enum iwl_tx_status - status that is returned by the fw after attempts to Tx - * @TX_STATUS_SUCCESS: - * @TX_STATUS_DIRECT_DONE: - * @TX_STATUS_POSTPONE_DELAY: - * @TX_STATUS_POSTPONE_FEW_BYTES: - * @TX_STATUS_POSTPONE_BT_PRIO: - * @TX_STATUS_POSTPONE_QUIET_PERIOD: - * @TX_STATUS_POSTPONE_CALC_TTAK: - * @TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY: - * @TX_STATUS_FAIL_SHORT_LIMIT: - * @TX_STATUS_FAIL_LONG_LIMIT: - * @TX_STATUS_FAIL_UNDERRUN: - * @TX_STATUS_FAIL_DRAIN_FLOW: - * @TX_STATUS_FAIL_RFKILL_FLUSH: - * @TX_STATUS_FAIL_LIFE_EXPIRE: - * @TX_STATUS_FAIL_DEST_PS: - * @TX_STATUS_FAIL_HOST_ABORTED: - * @TX_STATUS_FAIL_BT_RETRY: - * @TX_STATUS_FAIL_STA_INVALID: - * @TX_TATUS_FAIL_FRAG_DROPPED: - * @TX_STATUS_FAIL_TID_DISABLE: - * @TX_STATUS_FAIL_FIFO_FLUSHED: - * @TX_STATUS_FAIL_SMALL_CF_POLL: - * @TX_STATUS_FAIL_FW_DROP: - * @TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and - * STA table - * @TX_FRAME_STATUS_INTERNAL_ABORT: - * @TX_MODE_MSK: - * @TX_MODE_NO_BURST: - * @TX_MODE_IN_BURST_SEQ: - * @TX_MODE_FIRST_IN_BURST: - * @TX_QUEUE_NUM_MSK: - * - * Valid only if frame_count =1 - * TODO: complete documentation - */ -enum iwl_tx_status { - TX_STATUS_MSK = 0x000000ff, - TX_STATUS_SUCCESS = 0x01, - TX_STATUS_DIRECT_DONE = 0x02, - /* postpone TX */ - TX_STATUS_POSTPONE_DELAY = 0x40, - TX_STATUS_POSTPONE_FEW_BYTES = 0x41, - TX_STATUS_POSTPONE_BT_PRIO = 0x42, - TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43, - TX_STATUS_POSTPONE_CALC_TTAK = 0x44, - /* abort TX */ - TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81, - TX_STATUS_FAIL_SHORT_LIMIT = 0x82, - TX_STATUS_FAIL_LONG_LIMIT = 0x83, - TX_STATUS_FAIL_UNDERRUN = 0x84, - TX_STATUS_FAIL_DRAIN_FLOW = 0x85, - TX_STATUS_FAIL_RFKILL_FLUSH = 0x86, - TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, - TX_STATUS_FAIL_DEST_PS = 0x88, - TX_STATUS_FAIL_HOST_ABORTED = 0x89, - TX_STATUS_FAIL_BT_RETRY = 0x8a, - TX_STATUS_FAIL_STA_INVALID = 0x8b, - TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, - TX_STATUS_FAIL_TID_DISABLE = 0x8d, - TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e, - TX_STATUS_FAIL_SMALL_CF_POLL = 0x8f, - TX_STATUS_FAIL_FW_DROP = 0x90, - TX_STATUS_FAIL_STA_COLOR_MISMATCH = 0x91, - TX_STATUS_INTERNAL_ABORT = 0x92, - TX_MODE_MSK = 0x00000f00, - TX_MODE_NO_BURST = 0x00000000, - TX_MODE_IN_BURST_SEQ = 0x00000100, - TX_MODE_FIRST_IN_BURST = 0x00000200, - TX_QUEUE_NUM_MSK = 0x0001f000, - TX_NARROW_BW_MSK = 0x00060000, - TX_NARROW_BW_1DIV2 = 0x00020000, - TX_NARROW_BW_1DIV4 = 0x00040000, - TX_NARROW_BW_1DIV8 = 0x00060000, -}; - -/* - * enum iwl_tx_agg_status - TX aggregation status - * @AGG_TX_STATE_STATUS_MSK: - * @AGG_TX_STATE_TRANSMITTED: - * @AGG_TX_STATE_UNDERRUN: - * @AGG_TX_STATE_BT_PRIO: - * @AGG_TX_STATE_FEW_BYTES: - * @AGG_TX_STATE_ABORT: - * @AGG_TX_STATE_LAST_SENT_TTL: - * @AGG_TX_STATE_LAST_SENT_TRY_CNT: - * @AGG_TX_STATE_LAST_SENT_BT_KILL: - * @AGG_TX_STATE_SCD_QUERY: - * @AGG_TX_STATE_TEST_BAD_CRC32: - * @AGG_TX_STATE_RESPONSE: - * @AGG_TX_STATE_DUMP_TX: - * @AGG_TX_STATE_DELAY_TX: - * @AGG_TX_STATE_TRY_CNT_MSK: Retry count for 1st frame in aggregation (retries - * occur if tx failed for this frame when it was a member of a previous - * aggregation block). If rate scaling is used, retry count indicates the - * rate table entry used for all frames in the new agg. - *@ AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for - * this frame - * - * TODO: complete documentation - */ -enum iwl_tx_agg_status { - AGG_TX_STATE_STATUS_MSK = 0x00fff, - AGG_TX_STATE_TRANSMITTED = 0x000, - AGG_TX_STATE_UNDERRUN = 0x001, - AGG_TX_STATE_BT_PRIO = 0x002, - AGG_TX_STATE_FEW_BYTES = 0x004, - AGG_TX_STATE_ABORT = 0x008, - AGG_TX_STATE_LAST_SENT_TTL = 0x010, - AGG_TX_STATE_LAST_SENT_TRY_CNT = 0x020, - AGG_TX_STATE_LAST_SENT_BT_KILL = 0x040, - AGG_TX_STATE_SCD_QUERY = 0x080, - AGG_TX_STATE_TEST_BAD_CRC32 = 0x0100, - AGG_TX_STATE_RESPONSE = 0x1ff, - AGG_TX_STATE_DUMP_TX = 0x200, - AGG_TX_STATE_DELAY_TX = 0x400, - AGG_TX_STATE_TRY_CNT_POS = 12, - AGG_TX_STATE_TRY_CNT_MSK = 0xf << AGG_TX_STATE_TRY_CNT_POS, -}; - -#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL| \ - AGG_TX_STATE_LAST_SENT_TRY_CNT| \ - AGG_TX_STATE_LAST_SENT_BT_KILL) - -/* - * The mask below describes a status where we are absolutely sure that the MPDU - * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've - * written the bytes to the TXE, but we know nothing about what the DSP did. - */ -#define AGG_TX_STAT_FRAME_NOT_SENT (AGG_TX_STATE_FEW_BYTES | \ - AGG_TX_STATE_ABORT | \ - AGG_TX_STATE_SCD_QUERY) - -/* - * REPLY_TX = 0x1c (response) - * - * This response may be in one of two slightly different formats, indicated - * by the frame_count field: - * - * 1) No aggregation (frame_count == 1). This reports Tx results for a single - * frame. Multiple attempts, at various bit rates, may have been made for - * this frame. - * - * 2) Aggregation (frame_count > 1). This reports Tx results for two or more - * frames that used block-acknowledge. All frames were transmitted at - * same rate. Rate scaling may have been used if first frame in this new - * agg block failed in previous agg block(s). - * - * Note that, for aggregation, ACK (block-ack) status is not delivered - * here; block-ack has not been received by the time the device records - * this status. - * This status relates to reasons the tx might have been blocked or aborted - * within the device, rather than whether it was received successfully by - * the destination station. - */ - -/** - * struct agg_tx_status - per packet TX aggregation status - * @status: enum iwl_tx_agg_status - * @sequence: Sequence # for this frame's Tx cmd (not SSN!) - */ -struct agg_tx_status { - __le16 status; - __le16 sequence; -} __packed; - -/* - * definitions for initial rate index field - * bits [3:0] initial rate index - * bits [6:4] rate table color, used for the initial rate - * bit-7 invalid rate indication - */ -#define TX_RES_INIT_RATE_INDEX_MSK 0x0f -#define TX_RES_RATE_TABLE_COLOR_MSK 0x70 -#define TX_RES_INV_RATE_INDEX_MSK 0x80 - -#define IWL_MVM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f) -#define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) - -/** - * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet - * ( REPLY_TX = 0x1c ) - * @frame_count: 1 no aggregation, >1 aggregation - * @bt_kill_count: num of times blocked by bluetooth (unused for agg) - * @failure_rts: num of failures due to unsuccessful RTS - * @failure_frame: num failures due to no ACK (unused for agg) - * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the - * Tx of all the batch. RATE_MCS_* - * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. - * for agg: RTS + CTS + aggregation tx time + block-ack time. - * in usec. - * @pa_status: tx power info - * @pa_integ_res_a: tx power info - * @pa_integ_res_b: tx power info - * @pa_integ_res_c: tx power info - * @measurement_req_id: tx power info - * @tfd_info: TFD information set by the FH - * @seq_ctl: sequence control from the Tx cmd - * @byte_cnt: byte count from the Tx cmd - * @tlc_info: TLC rate info - * @ra_tid: bits [3:0] = ra, bits [7:4] = tid - * @frame_ctrl: frame control - * @status: for non-agg: frame status TX_STATUS_* - * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields - * follow this one, up to frame_count. - * - * After the array of statuses comes the SSN of the SCD. Look at - * %iwl_mvm_get_scd_ssn for more details. - */ -struct iwl_mvm_tx_resp { - u8 frame_count; - u8 bt_kill_count; - u8 failure_rts; - u8 failure_frame; - __le32 initial_rate; - __le16 wireless_media_time; - - u8 pa_status; - u8 pa_integ_res_a[3]; - u8 pa_integ_res_b[3]; - u8 pa_integ_res_c[3]; - __le16 measurement_req_id; - __le16 reserved; - - __le32 tfd_info; - __le16 seq_ctl; - __le16 byte_cnt; - u8 tlc_info; - u8 ra_tid; - __le16 frame_ctrl; - - struct agg_tx_status status; -} __packed; /* TX_RSP_API_S_VER_3 */ - -/** - * struct iwl_mvm_ba_notif - notifies about reception of BA - * ( BA_NOTIF = 0xc5 ) - * @sta_addr_lo32: lower 32 bits of the MAC address - * @sta_addr_hi16: upper 16 bits of the MAC address - * @sta_id: Index of recipient (BA-sending) station in fw's station table - * @tid: tid of the session - * @seq_ctl: - * @bitmap: the bitmap of the BA notification as seen in the air - * @scd_flow: the tx queue this BA relates to - * @scd_ssn: the index of the last contiguously sent packet - * @txed: number of Txed frames in this batch - * @txed_2_done: number of Acked frames in this batch - */ -struct iwl_mvm_ba_notif { - __le32 sta_addr_lo32; - __le16 sta_addr_hi16; - __le16 reserved; - - u8 sta_id; - u8 tid; - __le16 seq_ctl; - __le64 bitmap; - __le16 scd_flow; - __le16 scd_ssn; - u8 txed; - u8 txed_2_done; - __le16 reserved1; -} __packed; - -/* - * struct iwl_mac_beacon_cmd - beacon template command - * @tx: the tx commands associated with the beacon frame - * @template_id: currently equal to the mac context id of the coresponding - * mac. - * @tim_idx: the offset of the tim IE in the beacon - * @tim_size: the length of the tim IE - * @frame: the template of the beacon frame - */ -struct iwl_mac_beacon_cmd { - struct iwl_tx_cmd tx; - __le32 template_id; - __le32 tim_idx; - __le32 tim_size; - struct ieee80211_hdr frame[0]; -} __packed; - -/** - * enum iwl_dump_control - dump (flush) control flags - * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty - * and the TFD queues are empty. - */ -enum iwl_dump_control { - DUMP_TX_FIFO_FLUSH = BIT(1), -}; - -/** - * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command - * @queues_ctl: bitmap of queues to flush - * @flush_ctl: control flags - * @reserved: reserved - */ -struct iwl_tx_path_flush_cmd { - __le32 queues_ctl; - __le16 flush_ctl; - __le16 reserved; -} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */ - -/** - * iwl_mvm_get_scd_ssn - returns the SSN of the SCD - * @tx_resp: the Tx response from the fw (agg or non-agg) - * - * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since - * it can't know that everything will go well until the end of the AMPDU, it - * can't know in advance the number of MPDUs that will be sent in the current - * batch. This is why it writes the agg Tx response while it fetches the MPDUs. - * Hence, it can't know in advance what the SSN of the SCD will be at the end - * of the batch. This is why the SSN of the SCD is written at the end of the - * whole struct at a variable offset. This function knows how to cope with the - * variable offset and returns the SSN of the SCD. - */ -static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp) -{ - return le32_to_cpup((__le32 *)&tx_resp->status + - tx_resp->frame_count) & 0xfff; -} - -#endif /* __fw_api_tx_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api.h deleted file mode 100644 index 9fd49db32a32..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ /dev/null @@ -1,949 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __fw_api_h__ -#define __fw_api_h__ - -#include "fw-api-rs.h" -#include "fw-api-tx.h" -#include "fw-api-sta.h" -#include "fw-api-mac.h" -#include "fw-api-power.h" -#include "fw-api-d3.h" - -/* queue and FIFO numbers by usage */ -enum { - IWL_MVM_OFFCHANNEL_QUEUE = 8, - IWL_MVM_CMD_QUEUE = 9, - IWL_MVM_AUX_QUEUE = 15, - IWL_MVM_FIRST_AGG_QUEUE = 16, - IWL_MVM_NUM_QUEUES = 20, - IWL_MVM_LAST_AGG_QUEUE = IWL_MVM_NUM_QUEUES - 1, - IWL_MVM_CMD_FIFO = 7 -}; - -#define IWL_MVM_STATION_COUNT 16 - -/* commands */ -enum { - MVM_ALIVE = 0x1, - REPLY_ERROR = 0x2, - - INIT_COMPLETE_NOTIF = 0x4, - - /* PHY context commands */ - PHY_CONTEXT_CMD = 0x8, - DBG_CFG = 0x9, - - /* station table */ - ADD_STA = 0x18, - REMOVE_STA = 0x19, - - /* TX */ - TX_CMD = 0x1c, - TXPATH_FLUSH = 0x1e, - MGMT_MCAST_KEY = 0x1f, - - /* global key */ - WEP_KEY = 0x20, - - /* MAC and Binding commands */ - MAC_CONTEXT_CMD = 0x28, - TIME_EVENT_CMD = 0x29, /* both CMD and response */ - TIME_EVENT_NOTIFICATION = 0x2a, - BINDING_CONTEXT_CMD = 0x2b, - TIME_QUOTA_CMD = 0x2c, - - LQ_CMD = 0x4e, - - /* Calibration */ - TEMPERATURE_NOTIFICATION = 0x62, - CALIBRATION_CFG_CMD = 0x65, - CALIBRATION_RES_NOTIFICATION = 0x66, - CALIBRATION_COMPLETE_NOTIFICATION = 0x67, - RADIO_VERSION_NOTIFICATION = 0x68, - - /* Scan offload */ - SCAN_OFFLOAD_REQUEST_CMD = 0x51, - SCAN_OFFLOAD_ABORT_CMD = 0x52, - SCAN_OFFLOAD_COMPLETE = 0x6D, - SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, - SCAN_OFFLOAD_CONFIG_CMD = 0x6f, - - /* Phy */ - PHY_CONFIGURATION_CMD = 0x6a, - CALIB_RES_NOTIF_PHY_DB = 0x6b, - /* PHY_DB_CMD = 0x6c, */ - - /* Power */ - POWER_TABLE_CMD = 0x77, - - /* Scanning */ - SCAN_REQUEST_CMD = 0x80, - SCAN_ABORT_CMD = 0x81, - SCAN_START_NOTIFICATION = 0x82, - SCAN_RESULTS_NOTIFICATION = 0x83, - SCAN_COMPLETE_NOTIFICATION = 0x84, - - /* NVM */ - NVM_ACCESS_CMD = 0x88, - - SET_CALIB_DEFAULT_CMD = 0x8e, - - BEACON_TEMPLATE_CMD = 0x91, - TX_ANT_CONFIGURATION_CMD = 0x98, - STATISTICS_NOTIFICATION = 0x9d, - - /* RF-KILL commands and notifications */ - CARD_STATE_CMD = 0xa0, - CARD_STATE_NOTIFICATION = 0xa1, - - REPLY_RX_PHY_CMD = 0xc0, - REPLY_RX_MPDU_CMD = 0xc1, - BA_NOTIF = 0xc5, - - REPLY_DEBUG_CMD = 0xf0, - DEBUG_LOG_MSG = 0xf7, - - /* D3 commands/notifications */ - D3_CONFIG_CMD = 0xd3, - PROT_OFFLOAD_CONFIG_CMD = 0xd4, - OFFLOADS_QUERY_CMD = 0xd5, - REMOTE_WAKE_CONFIG_CMD = 0xd6, - - /* for WoWLAN in particular */ - WOWLAN_PATTERNS = 0xe0, - WOWLAN_CONFIGURATION = 0xe1, - WOWLAN_TSC_RSC_PARAM = 0xe2, - WOWLAN_TKIP_PARAM = 0xe3, - WOWLAN_KEK_KCK_MATERIAL = 0xe4, - WOWLAN_GET_STATUSES = 0xe5, - WOWLAN_TX_POWER_PER_DB = 0xe6, - - /* and for NetDetect */ - NET_DETECT_CONFIG_CMD = 0x54, - NET_DETECT_PROFILES_QUERY_CMD = 0x56, - NET_DETECT_PROFILES_CMD = 0x57, - NET_DETECT_HOTSPOTS_CMD = 0x58, - NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59, - - REPLY_MAX = 0xff, -}; - -/** - * struct iwl_cmd_response - generic response struct for most commands - * @status: status of the command asked, changes for each one - */ -struct iwl_cmd_response { - __le32 status; -}; - -/* - * struct iwl_tx_ant_cfg_cmd - * @valid: valid antenna configuration - */ -struct iwl_tx_ant_cfg_cmd { - __le32 valid; -} __packed; - -/* - * Calibration control struct. - * Sent as part of the phy configuration command. - * @flow_trigger: bitmap for which calibrations to perform according to - * flow triggers. - * @event_trigger: bitmap for which calibrations to perform according to - * event triggers. - */ -struct iwl_calib_ctrl { - __le32 flow_trigger; - __le32 event_trigger; -} __packed; - -/* This enum defines the bitmap of various calibrations to enable in both - * init ucode and runtime ucode through CALIBRATION_CFG_CMD. - */ -enum iwl_calib_cfg { - IWL_CALIB_CFG_XTAL_IDX = BIT(0), - IWL_CALIB_CFG_TEMPERATURE_IDX = BIT(1), - IWL_CALIB_CFG_VOLTAGE_READ_IDX = BIT(2), - IWL_CALIB_CFG_PAPD_IDX = BIT(3), - IWL_CALIB_CFG_TX_PWR_IDX = BIT(4), - IWL_CALIB_CFG_DC_IDX = BIT(5), - IWL_CALIB_CFG_BB_FILTER_IDX = BIT(6), - IWL_CALIB_CFG_LO_LEAKAGE_IDX = BIT(7), - IWL_CALIB_CFG_TX_IQ_IDX = BIT(8), - IWL_CALIB_CFG_TX_IQ_SKEW_IDX = BIT(9), - IWL_CALIB_CFG_RX_IQ_IDX = BIT(10), - IWL_CALIB_CFG_RX_IQ_SKEW_IDX = BIT(11), - IWL_CALIB_CFG_SENSITIVITY_IDX = BIT(12), - IWL_CALIB_CFG_CHAIN_NOISE_IDX = BIT(13), - IWL_CALIB_CFG_DISCONNECTED_ANT_IDX = BIT(14), - IWL_CALIB_CFG_ANT_COUPLING_IDX = BIT(15), - IWL_CALIB_CFG_DAC_IDX = BIT(16), - IWL_CALIB_CFG_ABS_IDX = BIT(17), - IWL_CALIB_CFG_AGC_IDX = BIT(18), -}; - -/* - * Phy configuration command. - */ -struct iwl_phy_cfg_cmd { - __le32 phy_cfg; - struct iwl_calib_ctrl calib_control; -} __packed; - -#define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1)) -#define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3)) -#define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5)) -#define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7)) -#define PHY_CFG_TX_CHAIN_A BIT(8) -#define PHY_CFG_TX_CHAIN_B BIT(9) -#define PHY_CFG_TX_CHAIN_C BIT(10) -#define PHY_CFG_RX_CHAIN_A BIT(12) -#define PHY_CFG_RX_CHAIN_B BIT(13) -#define PHY_CFG_RX_CHAIN_C BIT(14) - - -/* Target of the NVM_ACCESS_CMD */ -enum { - NVM_ACCESS_TARGET_CACHE = 0, - NVM_ACCESS_TARGET_OTP = 1, - NVM_ACCESS_TARGET_EEPROM = 2, -}; - -/** - * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM. - * @op_code: 0 - read, 1 - write. - * @target: NVM_ACCESS_TARGET_*. should be 0 for read. - * @cache_refresh: 0 - None, 1- NVM. - * @offset: offset in the nvm data. - * @length: of the chunk. - * @data: empty on read, the NVM chunk on write - */ -struct iwl_nvm_access_cmd_ver1 { - u8 op_code; - u8 target; - u8 cache_refresh; - u8 reserved; - __le16 offset; - __le16 length; - u8 data[]; -} __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */ - -/** - * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD - * @offset: the offset in the nvm data - * @length: of the chunk - * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write - */ -struct iwl_nvm_access_resp_ver1 { - __le16 offset; - __le16 length; - u8 data[]; -} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */ - -/* Section types for NVM_ACCESS_CMD version 2 */ -enum { - NVM_SECTION_TYPE_HW = 0, - NVM_SECTION_TYPE_SW, - NVM_SECTION_TYPE_PAPD, - NVM_SECTION_TYPE_BT, - NVM_SECTION_TYPE_CALIBRATION, - NVM_SECTION_TYPE_PRODUCTION, - NVM_SECTION_TYPE_POST_FCS_CALIB, - NVM_NUM_OF_SECTIONS, -}; - -/** - * struct iwl_nvm_access_cmd_ver2 - Request the device to send an NVM section - * @op_code: 0 - read, 1 - write - * @target: NVM_ACCESS_TARGET_* - * @type: NVM_SECTION_TYPE_* - * @offset: offset in bytes into the section - * @length: in bytes, to read/write - * @data: if write operation, the data to write. On read its empty - */ -struct iwl_nvm_access_cmd_ver2 { - u8 op_code; - u8 target; - __le16 type; - __le16 offset; - __le16 length; - u8 data[]; -} __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ - -/** - * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD - * @offset: offset in bytes into the section - * @length: in bytes, either how much was written or read - * @type: NVM_SECTION_TYPE_* - * @status: 0 for success, fail otherwise - * @data: if read operation, the data returned. Empty on write. - */ -struct iwl_nvm_access_resp_ver2 { - __le16 offset; - __le16 length; - __le16 type; - __le16 status; - u8 data[]; -} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_2 */ - -/* MVM_ALIVE 0x1 */ - -/* alive response is_valid values */ -#define ALIVE_RESP_UCODE_OK BIT(0) -#define ALIVE_RESP_RFKILL BIT(1) - -/* alive response ver_type values */ -enum { - FW_TYPE_HW = 0, - FW_TYPE_PROT = 1, - FW_TYPE_AP = 2, - FW_TYPE_WOWLAN = 3, - FW_TYPE_TIMING = 4, - FW_TYPE_WIPAN = 5 -}; - -/* alive response ver_subtype values */ -enum { - FW_SUBTYPE_FULL_FEATURE = 0, - FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */ - FW_SUBTYPE_REDUCED = 2, - FW_SUBTYPE_ALIVE_ONLY = 3, - FW_SUBTYPE_WOWLAN = 4, - FW_SUBTYPE_AP_SUBTYPE = 5, - FW_SUBTYPE_WIPAN = 6, - FW_SUBTYPE_INITIALIZE = 9 -}; - -#define IWL_ALIVE_STATUS_ERR 0xDEAD -#define IWL_ALIVE_STATUS_OK 0xCAFE - -#define IWL_ALIVE_FLG_RFKILL BIT(0) - -struct mvm_alive_resp { - __le16 status; - __le16 flags; - u8 ucode_minor; - u8 ucode_major; - __le16 id; - u8 api_minor; - u8 api_major; - u8 ver_subtype; - u8 ver_type; - u8 mac; - u8 opt; - __le16 reserved2; - __le32 timestamp; - __le32 error_event_table_ptr; /* SRAM address for error log */ - __le32 log_event_table_ptr; /* SRAM address for event log */ - __le32 cpu_register_ptr; - __le32 dbgm_config_ptr; - __le32 alive_counter_ptr; - __le32 scd_base_ptr; /* SRAM address for SCD */ -} __packed; /* ALIVE_RES_API_S_VER_1 */ - -/* Error response/notification */ -enum { - FW_ERR_UNKNOWN_CMD = 0x0, - FW_ERR_INVALID_CMD_PARAM = 0x1, - FW_ERR_SERVICE = 0x2, - FW_ERR_ARC_MEMORY = 0x3, - FW_ERR_ARC_CODE = 0x4, - FW_ERR_WATCH_DOG = 0x5, - FW_ERR_WEP_GRP_KEY_INDX = 0x10, - FW_ERR_WEP_KEY_SIZE = 0x11, - FW_ERR_OBSOLETE_FUNC = 0x12, - FW_ERR_UNEXPECTED = 0xFE, - FW_ERR_FATAL = 0xFF -}; - -/** - * struct iwl_error_resp - FW error indication - * ( REPLY_ERROR = 0x2 ) - * @error_type: one of FW_ERR_* - * @cmd_id: the command ID for which the error occured - * @bad_cmd_seq_num: sequence number of the erroneous command - * @error_service: which service created the error, applicable only if - * error_type = 2, otherwise 0 - * @timestamp: TSF in usecs. - */ -struct iwl_error_resp { - __le32 error_type; - u8 cmd_id; - u8 reserved1; - __le16 bad_cmd_seq_num; - __le32 error_service; - __le64 timestamp; -} __packed; - - -/* Common PHY, MAC and Bindings definitions */ - -#define MAX_MACS_IN_BINDING (3) -#define MAX_BINDINGS (4) -#define AUX_BINDING_INDEX (3) -#define MAX_PHYS (4) - -/* Used to extract ID and color from the context dword */ -#define FW_CTXT_ID_POS (0) -#define FW_CTXT_ID_MSK (0xff << FW_CTXT_ID_POS) -#define FW_CTXT_COLOR_POS (8) -#define FW_CTXT_COLOR_MSK (0xff << FW_CTXT_COLOR_POS) -#define FW_CTXT_INVALID (0xffffffff) - -#define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\ - (_color << FW_CTXT_COLOR_POS)) - -/* Possible actions on PHYs, MACs and Bindings */ -enum { - FW_CTXT_ACTION_STUB = 0, - FW_CTXT_ACTION_ADD, - FW_CTXT_ACTION_MODIFY, - FW_CTXT_ACTION_REMOVE, - FW_CTXT_ACTION_NUM -}; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ - -/* Time Events */ - -/* Time Event types, according to MAC type */ -enum iwl_time_event_type { - /* BSS Station Events */ - TE_BSS_STA_AGGRESSIVE_ASSOC, - TE_BSS_STA_ASSOC, - TE_BSS_EAP_DHCP_PROT, - TE_BSS_QUIET_PERIOD, - - /* P2P Device Events */ - TE_P2P_DEVICE_DISCOVERABLE, - TE_P2P_DEVICE_LISTEN, - TE_P2P_DEVICE_ACTION_SCAN, - TE_P2P_DEVICE_FULL_SCAN, - - /* P2P Client Events */ - TE_P2P_CLIENT_AGGRESSIVE_ASSOC, - TE_P2P_CLIENT_ASSOC, - TE_P2P_CLIENT_QUIET_PERIOD, - - /* P2P GO Events */ - TE_P2P_GO_ASSOC_PROT, - TE_P2P_GO_REPETITIVE_NOA, - TE_P2P_GO_CT_WINDOW, - - /* WiDi Sync Events */ - TE_WIDI_TX_SYNC, - - TE_MAX -}; /* MAC_EVENT_TYPE_API_E_VER_1 */ - -/* Time Event dependencies: none, on another TE, or in a specific time */ -enum { - TE_INDEPENDENT = 0, - TE_DEP_OTHER = 1, - TE_DEP_TSF = 2, - TE_EVENT_SOCIOPATHIC = 4, -}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ - -/* When to send Time Event notifications and to whom (internal = FW) */ -enum { - TE_NOTIF_NONE = 0, - TE_NOTIF_HOST_START = 0x1, - TE_NOTIF_HOST_END = 0x2, - TE_NOTIF_INTERNAL_START = 0x4, - TE_NOTIF_INTERNAL_END = 0x8 -}; /* MAC_EVENT_ACTION_API_E_VER_1 */ - -/* - * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. - * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only - * the first fragment is scheduled. - * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only - * the first 2 fragments are scheduled. - * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number - * of fragments are valid. - * - * Other than the constant defined above, specifying a fragmentation value 'x' - * means that the event can be fragmented but only the first 'x' will be - * scheduled. - */ -enum { - TE_FRAG_NONE = 0, - TE_FRAG_SINGLE = 1, - TE_FRAG_DUAL = 2, - TE_FRAG_ENDLESS = 0xffffffff -}; - -/* Repeat the time event endlessly (until removed) */ -#define TE_REPEAT_ENDLESS (0xffffffff) -/* If a Time Event has bounded repetitions, this is the maximal value */ -#define TE_REPEAT_MAX_MSK (0x0fffffff) -/* If a Time Event can be fragmented, this is the max number of fragments */ -#define TE_FRAG_MAX_MSK (0x0fffffff) - -/** - * struct iwl_time_event_cmd - configuring Time Events - * ( TIME_EVENT_CMD = 0x29 ) - * @id_and_color: ID and color of the relevant MAC - * @action: action to perform, one of FW_CTXT_ACTION_* - * @id: this field has two meanings, depending on the action: - * If the action is ADD, then it means the type of event to add. - * For all other actions it is the unique event ID assigned when the - * event was added by the FW. - * @apply_time: When to start the Time Event (in GP2) - * @max_delay: maximum delay to event's start (apply time), in TU - * @depends_on: the unique ID of the event we depend on (if any) - * @interval: interval between repetitions, in TU - * @interval_reciprocal: 2^32 / interval - * @duration: duration of event in TU - * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS - * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF - * @is_present: 0 or 1, are we present or absent during the Time Event - * @max_frags: maximal number of fragments the Time Event can be divided to - * @notify: notifications using TE_NOTIF_* (whom to notify when) - */ -struct iwl_time_event_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - __le32 id; - /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ - __le32 apply_time; - __le32 max_delay; - __le32 dep_policy; - __le32 depends_on; - __le32 is_present; - __le32 max_frags; - __le32 interval; - __le32 interval_reciprocal; - __le32 duration; - __le32 repeat; - __le32 notify; -} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ - -/** - * struct iwl_time_event_resp - response structure to iwl_time_event_cmd - * @status: bit 0 indicates success, all others specify errors - * @id: the Time Event type - * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE - * @id_and_color: ID and color of the relevant MAC - */ -struct iwl_time_event_resp { - __le32 status; - __le32 id; - __le32 unique_id; - __le32 id_and_color; -} __packed; /* MAC_TIME_EVENT_RSP_API_S_VER_1 */ - -/** - * struct iwl_time_event_notif - notifications of time event start/stop - * ( TIME_EVENT_NOTIFICATION = 0x2a ) - * @timestamp: action timestamp in GP2 - * @session_id: session's unique id - * @unique_id: unique id of the Time Event itself - * @id_and_color: ID and color of the relevant MAC - * @action: one of TE_NOTIF_START or TE_NOTIF_END - * @status: true if scheduled, false otherwise (not executed) - */ -struct iwl_time_event_notif { - __le32 timestamp; - __le32 session_id; - __le32 unique_id; - __le32 id_and_color; - __le32 action; - __le32 status; -} __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */ - - -/* Bindings and Time Quota */ - -/** - * struct iwl_binding_cmd - configuring bindings - * ( BINDING_CONTEXT_CMD = 0x2b ) - * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* - * @macs: array of MAC id and colors which belong to the binding - * @phy: PHY id and color which belongs to the binding - */ -struct iwl_binding_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - /* BINDING_DATA_API_S_VER_1 */ - __le32 macs[MAX_MACS_IN_BINDING]; - __le32 phy; -} __packed; /* BINDING_CMD_API_S_VER_1 */ - -/** - * struct iwl_time_quota_data - configuration of time quota per binding - * @id_and_color: ID and color of the relevant Binding - * @quota: absolute time quota in TU. The scheduler will try to divide the - * remainig quota (after Time Events) according to this quota. - * @max_duration: max uninterrupted context duration in TU - */ -struct iwl_time_quota_data { - __le32 id_and_color; - __le32 quota; - __le32 max_duration; -} __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */ - -/** - * struct iwl_time_quota_cmd - configuration of time quota between bindings - * ( TIME_QUOTA_CMD = 0x2c ) - * @quotas: allocations per binding - */ -struct iwl_time_quota_cmd { - struct iwl_time_quota_data quotas[MAX_BINDINGS]; -} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ - - -/* PHY context */ - -/* Supported bands */ -#define PHY_BAND_5 (0) -#define PHY_BAND_24 (1) - -/* Supported channel width, vary if there is VHT support */ -#define PHY_VHT_CHANNEL_MODE20 (0x0) -#define PHY_VHT_CHANNEL_MODE40 (0x1) -#define PHY_VHT_CHANNEL_MODE80 (0x2) -#define PHY_VHT_CHANNEL_MODE160 (0x3) - -/* - * Control channel position: - * For legacy set bit means upper channel, otherwise lower. - * For VHT - bit-2 marks if the control is lower/upper relative to center-freq - * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. - * center_freq - * | - * 40Mhz |_______|_______| - * 80Mhz |_______|_______|_______|_______| - * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| - * code 011 010 001 000 | 100 101 110 111 - */ -#define PHY_VHT_CTRL_POS_1_BELOW (0x0) -#define PHY_VHT_CTRL_POS_2_BELOW (0x1) -#define PHY_VHT_CTRL_POS_3_BELOW (0x2) -#define PHY_VHT_CTRL_POS_4_BELOW (0x3) -#define PHY_VHT_CTRL_POS_1_ABOVE (0x4) -#define PHY_VHT_CTRL_POS_2_ABOVE (0x5) -#define PHY_VHT_CTRL_POS_3_ABOVE (0x6) -#define PHY_VHT_CTRL_POS_4_ABOVE (0x7) - -/* - * @band: PHY_BAND_* - * @channel: channel number - * @width: PHY_[VHT|LEGACY]_CHANNEL_* - * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* - */ -struct iwl_fw_channel_info { - u8 band; - u8 channel; - u8 width; - u8 ctrl_pos; -} __packed; - -#define PHY_RX_CHAIN_DRIVER_FORCE_POS (0) -#define PHY_RX_CHAIN_DRIVER_FORCE_MSK \ - (0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS) -#define PHY_RX_CHAIN_VALID_POS (1) -#define PHY_RX_CHAIN_VALID_MSK \ - (0x7 << PHY_RX_CHAIN_VALID_POS) -#define PHY_RX_CHAIN_FORCE_SEL_POS (4) -#define PHY_RX_CHAIN_FORCE_SEL_MSK \ - (0x7 << PHY_RX_CHAIN_FORCE_SEL_POS) -#define PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ - (0x7 << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) -#define PHY_RX_CHAIN_CNT_POS (10) -#define PHY_RX_CHAIN_CNT_MSK \ - (0x3 << PHY_RX_CHAIN_CNT_POS) -#define PHY_RX_CHAIN_MIMO_CNT_POS (12) -#define PHY_RX_CHAIN_MIMO_CNT_MSK \ - (0x3 << PHY_RX_CHAIN_MIMO_CNT_POS) -#define PHY_RX_CHAIN_MIMO_FORCE_POS (14) -#define PHY_RX_CHAIN_MIMO_FORCE_MSK \ - (0x1 << PHY_RX_CHAIN_MIMO_FORCE_POS) - -/* TODO: fix the value, make it depend on firmware at runtime? */ -#define NUM_PHY_CTX 3 - -/* TODO: complete missing documentation */ -/** - * struct iwl_phy_context_cmd - config of the PHY context - * ( PHY_CONTEXT_CMD = 0x8 ) - * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* - * @apply_time: 0 means immediate apply and context switch. - * other value means apply new params after X usecs - * @tx_param_color: ??? - * @channel_info: - * @txchain_info: ??? - * @rxchain_info: ??? - * @acquisition_data: ??? - * @dsp_cfg_flags: set to 0 - */ -struct iwl_phy_context_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - /* PHY_CONTEXT_DATA_API_S_VER_1 */ - __le32 apply_time; - __le32 tx_param_color; - struct iwl_fw_channel_info ci; - __le32 txchain_info; - __le32 rxchain_info; - __le32 acquisition_data; - __le32 dsp_cfg_flags; -} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ - -#define IWL_RX_INFO_PHY_CNT 8 -#define IWL_RX_INFO_AGC_IDX 1 -#define IWL_RX_INFO_RSSI_AB_IDX 2 -#define IWL_RX_INFO_RSSI_C_IDX 3 -#define IWL_OFDM_AGC_DB_MSK 0xfe00 -#define IWL_OFDM_AGC_DB_POS 9 -#define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 -#define IWL_OFDM_RSSI_A_POS 0 -#define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 -#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 -#define IWL_OFDM_RSSI_B_POS 16 -#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 -#define IWL_OFDM_RSSI_C_POS 0 - -/** - * struct iwl_rx_phy_info - phy info - * (REPLY_RX_PHY_CMD = 0xc0) - * @non_cfg_phy_cnt: non configurable DSP phy data byte count - * @cfg_phy_cnt: configurable DSP phy data byte count - * @stat_id: configurable DSP phy data set ID - * @reserved1: - * @system_timestamp: GP2 at on air rise - * @timestamp: TSF at on air rise - * @beacon_time_stamp: beacon at on-air rise - * @phy_flags: general phy flags: band, modulation, ... - * @channel: channel number - * @non_cfg_phy_buf: for various implementations of non_cfg_phy - * @rate_n_flags: RATE_MCS_* - * @byte_count: frame's byte-count - * @frame_time: frame's time on the air, based on byte count and frame rate - * calculation - * - * Before each Rx, the device sends this data. It contains PHY information - * about the reception of the packet. - */ -struct iwl_rx_phy_info { - u8 non_cfg_phy_cnt; - u8 cfg_phy_cnt; - u8 stat_id; - u8 reserved1; - __le32 system_timestamp; - __le64 timestamp; - __le32 beacon_time_stamp; - __le16 phy_flags; - __le16 channel; - __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT]; - __le32 rate_n_flags; - __le32 byte_count; - __le16 reserved2; - __le16 frame_time; -} __packed; - -struct iwl_rx_mpdu_res_start { - __le16 byte_count; - __le16 reserved; -} __packed; - -/** - * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags - * @RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band - * @RX_RES_PHY_FLAGS_MOD_CCK: - * @RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short - * @RX_RES_PHY_FLAGS_NARROW_BAND: - * @RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received - * @RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU - * @RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame - * @RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble - * @RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame - */ -enum iwl_rx_phy_flags { - RX_RES_PHY_FLAGS_BAND_24 = BIT(0), - RX_RES_PHY_FLAGS_MOD_CCK = BIT(1), - RX_RES_PHY_FLAGS_SHORT_PREAMBLE = BIT(2), - RX_RES_PHY_FLAGS_NARROW_BAND = BIT(3), - RX_RES_PHY_FLAGS_ANTENNA = (0x7 << 4), - RX_RES_PHY_FLAGS_ANTENNA_POS = 4, - RX_RES_PHY_FLAGS_AGG = BIT(7), - RX_RES_PHY_FLAGS_OFDM_HT = BIT(8), - RX_RES_PHY_FLAGS_OFDM_GF = BIT(9), - RX_RES_PHY_FLAGS_OFDM_VHT = BIT(10), -}; - -/** - * enum iwl_mvm_rx_status - written by fw for each Rx packet - * @RX_MPDU_RES_STATUS_CRC_OK: CRC is fine - * @RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow - * @RX_MPDU_RES_STATUS_SRC_STA_FOUND: - * @RX_MPDU_RES_STATUS_KEY_VALID: - * @RX_MPDU_RES_STATUS_KEY_PARAM_OK: - * @RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed - * @RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked - * in the driver. - * @RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine - * @RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR: valid for alg = CCM_CMAC or - * alg = CCM only. Checks replay attack for 11w frames. Relevant only if - * %RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set. - * @RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted - * @RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP - * @RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM - * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP - * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC - * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted - * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm - * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted - * @RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: - * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: - * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: - * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame - * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK: - * @RX_MPDU_RES_STATUS_STA_ID_MSK: - * @RX_MPDU_RES_STATUS_RRF_KILL: - * @RX_MPDU_RES_STATUS_FILTERING_MSK: - * @RX_MPDU_RES_STATUS2_FILTERING_MSK: - */ -enum iwl_mvm_rx_status { - RX_MPDU_RES_STATUS_CRC_OK = BIT(0), - RX_MPDU_RES_STATUS_OVERRUN_OK = BIT(1), - RX_MPDU_RES_STATUS_SRC_STA_FOUND = BIT(2), - RX_MPDU_RES_STATUS_KEY_VALID = BIT(3), - RX_MPDU_RES_STATUS_KEY_PARAM_OK = BIT(4), - RX_MPDU_RES_STATUS_ICV_OK = BIT(5), - RX_MPDU_RES_STATUS_MIC_OK = BIT(6), - RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), - RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR = BIT(7), - RX_MPDU_RES_STATUS_SEC_NO_ENC = (0 << 8), - RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8), - RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8), - RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8), - RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8), - RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), - RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), - RX_MPDU_RES_STATUS_DEC_DONE = BIT(11), - RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP = BIT(12), - RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13), - RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14), - RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15), - RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), - RX_MPDU_RES_STATUS_STA_ID_MSK = (0x1f000000), - RX_MPDU_RES_STATUS_RRF_KILL = BIT(29), - RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000), - RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), -}; - -/** - * struct iwl_radio_version_notif - information on the radio version - * ( RADIO_VERSION_NOTIFICATION = 0x68 ) - * @radio_flavor: - * @radio_step: - * @radio_dash: - */ -struct iwl_radio_version_notif { - __le32 radio_flavor; - __le32 radio_step; - __le32 radio_dash; -} __packed; /* RADIO_VERSION_NOTOFICATION_S_VER_1 */ - -enum iwl_card_state_flags { - CARD_ENABLED = 0x00, - HW_CARD_DISABLED = 0x01, - SW_CARD_DISABLED = 0x02, - CT_KILL_CARD_DISABLED = 0x04, - HALT_CARD_DISABLED = 0x08, - CARD_DISABLED_MSK = 0x0f, - CARD_IS_RX_ON = 0x10, -}; - -/** - * struct iwl_radio_version_notif - information on the radio version - * ( CARD_STATE_NOTIFICATION = 0xa1 ) - * @flags: %iwl_card_state_flags - */ -struct iwl_card_state_notif { - __le32 flags; -} __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ - -/** - * struct iwl_set_calib_default_cmd - set default value for calibration. - * ( SET_CALIB_DEFAULT_CMD = 0x8e ) - * @calib_index: the calibration to set value for - * @length: of data - * @data: the value to set for the calibration result - */ -struct iwl_set_calib_default_cmd { - __le16 calib_index; - __le16 length; - u8 data[0]; -} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ - -#endif /* __fw_api_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/fw.c b/trunk/drivers/net/wireless/iwlwifi/mvm/fw.c deleted file mode 100644 index 90473c2ba1c7..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/fw.c +++ /dev/null @@ -1,644 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 - -#include "iwl-trans.h" -#include "iwl-op-mode.h" -#include "iwl-fw.h" -#include "iwl-debug.h" -#include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ -#include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ -#include "iwl-eeprom-parse.h" - -#include "mvm.h" -#include "iwl-phy-db.h" - -#define MVM_UCODE_ALIVE_TIMEOUT HZ -#define MVM_UCODE_CALIB_TIMEOUT (2*HZ) - -#define UCODE_VALID_OK cpu_to_le32(0x1) - -/* Default calibration values for WkP - set to INIT image w/o running */ -static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, - 0x00, 0x18, 0x00 }; -static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f }; -static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, - 0x00 }; -static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; -static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 }; - -struct iwl_calib_default_data { - u16 size; - void *data; -}; - -#define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} - -static const struct iwl_calib_default_data wkp_calib_default_data[12] = { - [5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), - [6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), - [7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), - [8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq), - [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), - [10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq), - [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), -}; - -struct iwl_mvm_alive_data { - bool valid; - u32 scd_base_addr; -}; - -static inline const struct fw_img * -iwl_get_ucode_image(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type) -{ - if (ucode_type >= IWL_UCODE_TYPE_MAX) - return NULL; - - return &mvm->fw->img[ucode_type]; -} - -static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) -{ - struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { - .valid = cpu_to_le32(valid_tx_ant), - }; - - IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant); - return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC, - sizeof(tx_ant_cmd), &tx_ant_cmd); -} - -static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, void *data) -{ - struct iwl_mvm *mvm = - container_of(notif_wait, struct iwl_mvm, notif_wait); - struct iwl_mvm_alive_data *alive_data = data; - struct mvm_alive_resp *palive; - - palive = (void *)pkt->data; - - mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr); - mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); - alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); - - alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; - IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", - le16_to_cpu(palive->status), palive->ver_type, - palive->ver_subtype); - - return true; -} - -static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, void *data) -{ - struct iwl_phy_db *phy_db = data; - - if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) { - WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); - return true; - } - - WARN_ON(iwl_phy_db_set_section(phy_db, pkt, GFP_ATOMIC)); - - return false; -} - -static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, - enum iwl_ucode_type ucode_type) -{ - struct iwl_notification_wait alive_wait; - struct iwl_mvm_alive_data alive_data; - const struct fw_img *fw; - int ret, i; - enum iwl_ucode_type old_type = mvm->cur_ucode; - static const u8 alive_cmd[] = { MVM_ALIVE }; - - mvm->cur_ucode = ucode_type; - fw = iwl_get_ucode_image(mvm, ucode_type); - - mvm->ucode_loaded = false; - - if (!fw) - return -EINVAL; - - iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, - alive_cmd, ARRAY_SIZE(alive_cmd), - iwl_alive_fn, &alive_data); - - ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); - if (ret) { - mvm->cur_ucode = old_type; - iwl_remove_notification(&mvm->notif_wait, &alive_wait); - return ret; - } - - /* - * Some things may run in the background now, but we - * just wait for the ALIVE notification here. - */ - ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, - MVM_UCODE_ALIVE_TIMEOUT); - if (ret) { - mvm->cur_ucode = old_type; - return ret; - } - - if (!alive_data.valid) { - IWL_ERR(mvm, "Loaded ucode is not valid!\n"); - mvm->cur_ucode = old_type; - return -EIO; - } - - iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); - - /* - * Note: all the queues are enabled as part of the interface - * initialization, but in firmware restart scenarios they - * could be stopped, so wake them up. In firmware restart, - * mac80211 will have the queues stopped as well until the - * reconfiguration completes. During normal startup, they - * will be empty. - */ - - for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { - if (i < IWL_MVM_FIRST_AGG_QUEUE && i != IWL_MVM_CMD_QUEUE) - mvm->queue_to_mac80211[i] = i; - else - mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; - atomic_set(&mvm->queue_stop_count[i], 0); - } - - mvm->transport_queue_stop = 0; - - mvm->ucode_loaded = true; - - return 0; -} -#define IWL_HW_REV_ID_RAINBOW 0x2 -#define IWL_PROJ_TYPE_LHP 0x5 - -static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) -{ - struct iwl_nvm_data *data = mvm->nvm_data; - /* Temp calls to static definitions, will be changed to CSR calls */ - u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; - u8 project_type = IWL_PROJ_TYPE_LHP; - - return data->radio_cfg_dash | (data->radio_cfg_step << 2) | - (hw_rev_id << 4) | ((project_type & 0x7f) << 6) | - (data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); -} - -static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) -{ - struct iwl_phy_cfg_cmd phy_cfg_cmd; - enum iwl_ucode_type ucode_type = mvm->cur_ucode; - - /* Set parameters */ - phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); - phy_cfg_cmd.calib_control.event_trigger = - mvm->fw->default_calib[ucode_type].event_trigger; - phy_cfg_cmd.calib_control.flow_trigger = - mvm->fw->default_calib[ucode_type].flow_trigger; - - IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", - phy_cfg_cmd.phy_cfg); - - return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, CMD_SYNC, - sizeof(phy_cfg_cmd), &phy_cfg_cmd); -} - -/* Starting with the new PHY DB implementation - New calibs are enabled */ -/* Value - 0x405e7 */ -#define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\ - IWL_CALIB_CFG_TEMPERATURE_IDX |\ - IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ - IWL_CALIB_CFG_DC_IDX |\ - IWL_CALIB_CFG_BB_FILTER_IDX |\ - IWL_CALIB_CFG_LO_LEAKAGE_IDX |\ - IWL_CALIB_CFG_TX_IQ_IDX |\ - IWL_CALIB_CFG_RX_IQ_IDX |\ - IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_INIT 0x0 - -/* Value 0x41567 */ -#define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\ - IWL_CALIB_CFG_TEMPERATURE_IDX |\ - IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ - IWL_CALIB_CFG_BB_FILTER_IDX |\ - IWL_CALIB_CFG_DC_IDX |\ - IWL_CALIB_CFG_TX_IQ_IDX |\ - IWL_CALIB_CFG_RX_IQ_IDX |\ - IWL_CALIB_CFG_SENSITIVITY_IDX |\ - IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\ - IWL_CALIB_CFG_TEMPERATURE_IDX |\ - IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ - IWL_CALIB_CFG_TX_PWR_IDX |\ - IWL_CALIB_CFG_DC_IDX |\ - IWL_CALIB_CFG_TX_IQ_IDX |\ - IWL_CALIB_CFG_SENSITIVITY_IDX) - -/* - * Sets the calibrations trigger values that will be sent to the FW for runtime - * and init calibrations. - * The ones given in the FW TLV are not correct. - */ -static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) -{ - struct iwl_tlv_calib_ctrl default_calib; - - /* - * WkP FW TLV calib bits are wrong, overwrite them. - * This defines the dynamic calibrations which are implemented in the - * uCode both for init(flow) calculation and event driven calibs. - */ - - /* Init Image */ - default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); - default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); - - if (default_calib.event_trigger != - mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) - IWL_ERR(mvm, - "Updating the event calib for INIT image: 0x%x -> 0x%x\n", - mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, - default_calib.event_trigger); - if (default_calib.flow_trigger != - mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) - IWL_ERR(mvm, - "Updating the flow calib for INIT image: 0x%x -> 0x%x\n", - mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, - default_calib.flow_trigger); - - memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], - &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); - IWL_ERR(mvm, - "Setting uCode init calibrations event 0x%x, trigger 0x%x\n", - default_calib.event_trigger, - default_calib.flow_trigger); - - /* Run time image */ - default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); - default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); - - if (default_calib.event_trigger != - mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) - IWL_ERR(mvm, - "Updating the event calib for RT image: 0x%x -> 0x%x\n", - mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, - default_calib.event_trigger); - if (default_calib.flow_trigger != - mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) - IWL_ERR(mvm, - "Updating the flow calib for RT image: 0x%x -> 0x%x\n", - mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, - default_calib.flow_trigger); - - memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], - &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); - IWL_ERR(mvm, - "Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", - default_calib.event_trigger, - default_calib.flow_trigger); -} - -static int iwl_set_default_calibrations(struct iwl_mvm *mvm) -{ - u8 cmd_raw[16]; /* holds the variable size commands */ - struct iwl_set_calib_default_cmd *cmd = - (struct iwl_set_calib_default_cmd *)cmd_raw; - int ret, i; - - /* Setting default values for calibrations we don't run */ - for (i = 0; i < ARRAY_SIZE(wkp_calib_default_data); i++) { - u16 cmd_len; - - if (wkp_calib_default_data[i].size == 0) - continue; - - memset(cmd_raw, 0, sizeof(cmd_raw)); - cmd_len = wkp_calib_default_data[i].size + sizeof(cmd); - cmd->calib_index = cpu_to_le16(i); - cmd->length = cpu_to_le16(wkp_calib_default_data[i].size); - if (WARN_ONCE(cmd_len > sizeof(cmd_raw), - "Need to enlarge cmd_raw to %d\n", cmd_len)) - break; - memcpy(cmd->data, wkp_calib_default_data[i].data, - wkp_calib_default_data[i].size); - ret = iwl_mvm_send_cmd_pdu(mvm, SET_CALIB_DEFAULT_CMD, 0, - sizeof(*cmd) + - wkp_calib_default_data[i].size, - cmd); - if (ret) - return ret; - } - - return 0; -} - -int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) -{ - struct iwl_notification_wait calib_wait; - static const u8 init_complete[] = { - INIT_COMPLETE_NOTIF, - CALIB_RES_NOTIF_PHY_DB - }; - int ret; - - lockdep_assert_held(&mvm->mutex); - - if (mvm->init_ucode_run) - return 0; - - iwl_init_notification_wait(&mvm->notif_wait, - &calib_wait, - init_complete, - ARRAY_SIZE(init_complete), - iwl_wait_phy_db_entry, - mvm->phy_db); - - /* Will also start the device */ - ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT); - if (ret) { - IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret); - goto error; - } - - if (read_nvm) { - /* Read nvm */ - ret = iwl_nvm_init(mvm); - if (ret) { - IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); - goto error; - } - } - - ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); - WARN_ON(ret); - - /* Override the calibrations from TLV and the const of fw */ - iwl_set_default_calib_trigger(mvm); - - /* WkP doesn't have all calibrations, need to set default values */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - ret = iwl_set_default_calibrations(mvm); - if (ret) - goto error; - } - - /* - * Send phy configurations command to init uCode - * to start the 16.0 uCode init image internal calibrations. - */ - ret = iwl_send_phy_cfg_cmd(mvm); - if (ret) { - IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", - ret); - goto error; - } - - /* - * Some things may run in the background now, but we - * just wait for the calibration complete notification. - */ - ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, - MVM_UCODE_CALIB_TIMEOUT); - if (!ret) - mvm->init_ucode_run = true; - goto out; - -error: - iwl_remove_notification(&mvm->notif_wait, &calib_wait); -out: - if (!iwlmvm_mod_params.init_dbg) { - iwl_trans_stop_device(mvm->trans); - } else if (!mvm->nvm_data) { - /* we want to debug INIT and we have no NVM - fake */ - mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + - sizeof(struct ieee80211_channel) + - sizeof(struct ieee80211_rate), - GFP_KERNEL); - if (!mvm->nvm_data) - return -ENOMEM; - mvm->nvm_data->valid_rx_ant = 1; - mvm->nvm_data->valid_tx_ant = 1; - mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; - mvm->nvm_data->bands[0].n_channels = 1; - mvm->nvm_data->bands[0].n_bitrates = 1; - mvm->nvm_data->bands[0].bitrates = - (void *)mvm->nvm_data->channels + 1; - mvm->nvm_data->bands[0].bitrates->hw_value = 10; - } - - return ret; -} - -#define UCODE_CALIB_TIMEOUT (2*HZ) - -int iwl_mvm_up(struct iwl_mvm *mvm) -{ - int ret, i; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_trans_start_hw(mvm->trans); - if (ret) - return ret; - - /* If we were in RFKILL during module loading, load init ucode now */ - if (!mvm->init_ucode_run) { - ret = iwl_run_init_mvm_ucode(mvm, false); - if (ret && !iwlmvm_mod_params.init_dbg) { - IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); - goto error; - } - } - - if (iwlmvm_mod_params.init_dbg) - return 0; - - ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); - if (ret) { - IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); - goto error; - } - - ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); - if (ret) - goto error; - - /* Send phy db control command and then phy db calibration*/ - ret = iwl_send_phy_db_data(mvm->phy_db); - if (ret) - goto error; - - ret = iwl_send_phy_cfg_cmd(mvm); - if (ret) - goto error; - - /* init the fw <-> mac80211 STA mapping */ - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) - RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); - - /* Add auxiliary station for scanning */ - ret = iwl_mvm_add_aux_sta(mvm); - if (ret) - goto error; - - IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); - - return 0; - error: - iwl_trans_stop_device(mvm->trans); - return ret; -} - -int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) -{ - int ret, i; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_trans_start_hw(mvm->trans); - if (ret) - return ret; - - ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN); - if (ret) { - IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret); - goto error; - } - - ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); - if (ret) - goto error; - - /* Send phy db control command and then phy db calibration*/ - ret = iwl_send_phy_db_data(mvm->phy_db); - if (ret) - goto error; - - ret = iwl_send_phy_cfg_cmd(mvm); - if (ret) - goto error; - - /* init the fw <-> mac80211 STA mapping */ - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) - RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); - - /* Add auxiliary station for scanning */ - ret = iwl_mvm_add_aux_sta(mvm); - if (ret) - goto error; - - return 0; - error: - iwl_trans_stop_device(mvm->trans); - return ret; -} - -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; - u32 flags = le32_to_cpu(card_state_notif->flags); - - IWL_DEBUG_RF_KILL(mvm, "Card state received: HW:%s SW:%s CT:%s\n", - (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On", - (flags & CT_KILL_CARD_DISABLED) ? - "Reached" : "Not reached"); - - if (flags & CARD_DISABLED_MSK) - iwl_write32(mvm->trans, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - return 0; -} - -int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_radio_version_notif *radio_version = (void *)pkt->data; - - /* TODO: what to do with that? */ - IWL_DEBUG_INFO(mvm, - "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n", - le32_to_cpu(radio_version->radio_flavor), - le32_to_cpu(radio_version->radio_step), - le32_to_cpu(radio_version->radio_dash)); - return 0; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/led.c b/trunk/drivers/net/wireless/iwlwifi/mvm/led.c deleted file mode 100644 index 011906e73a05..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/led.c +++ /dev/null @@ -1,134 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include "iwl-io.h" -#include "iwl-csr.h" -#include "mvm.h" - -/* Set led register on */ -static void iwl_mvm_led_enable(struct iwl_mvm *mvm) -{ - iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); -} - -/* Set led register off */ -static void iwl_mvm_led_disable(struct iwl_mvm *mvm) -{ - iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_OFF); -} - -static void iwl_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led); - if (brightness > 0) - iwl_mvm_led_enable(mvm); - else - iwl_mvm_led_disable(mvm); -} - -int iwl_mvm_leds_init(struct iwl_mvm *mvm) -{ - int mode = iwlwifi_mod_params.led_mode; - int ret; - - switch (mode) { - case IWL_LED_DEFAULT: - case IWL_LED_RF_STATE: - mode = IWL_LED_RF_STATE; - break; - case IWL_LED_DISABLE: - IWL_INFO(mvm, "Led disabled\n"); - return 0; - default: - return -EINVAL; - }; - - mvm->led.name = kasprintf(GFP_KERNEL, "%s-led", - wiphy_name(mvm->hw->wiphy)); - mvm->led.brightness_set = iwl_led_brightness_set; - mvm->led.max_brightness = 1; - - if (mode == IWL_LED_RF_STATE) - mvm->led.default_trigger = - ieee80211_get_radio_led_name(mvm->hw); - - ret = led_classdev_register(mvm->trans->dev, &mvm->led); - if (ret) { - kfree(mvm->led.name); - IWL_INFO(mvm, "Failed to enable led\n"); - return ret; - } - - return 0; -} - -void iwl_mvm_leds_exit(struct iwl_mvm *mvm) -{ - if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE) - return; - - led_classdev_unregister(&mvm->led); - kfree(mvm->led.name); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/trunk/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c deleted file mode 100644 index c08a17a3cab9..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ /dev/null @@ -1,951 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include -#include "iwl-io.h" -#include "iwl-prph.h" -#include "fw-api.h" -#include "mvm.h" - -const u8 iwl_mvm_ac_to_tx_fifo[] = { - IWL_MVM_TX_FIFO_BK, - IWL_MVM_TX_FIFO_BE, - IWL_MVM_TX_FIFO_VI, - IWL_MVM_TX_FIFO_VO, -}; - -struct iwl_mvm_mac_iface_iterator_data { - struct iwl_mvm *mvm; - struct ieee80211_vif *vif; - unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; - unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; - unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_FIRST_AGG_QUEUE)]; - enum iwl_tsf_id preferred_tsf; - bool found_vif; -}; - -static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_mac_iface_iterator_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 ac; - - /* Iterator may already find the interface being added -- skip it */ - if (vif == data->vif) { - data->found_vif = true; - return; - } - - /* Mark the queues used by the vif */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - __set_bit(vif->hw_queue[ac], data->used_hw_queues); - - if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) - __set_bit(vif->cab_queue, data->used_hw_queues); - - /* - * Mark MAC IDs as used by clearing the available bit, and - * (below) mark TSFs as used if their existing use is not - * compatible with the new interface type. - * No locking or atomic bit operations are needed since the - * data is on the stack of the caller function. - */ - __clear_bit(mvmvif->id, data->available_mac_ids); - - /* - * The TSF is a hardware/firmware resource, there are 4 and - * the driver should assign and free them as needed. However, - * there are cases where 2 MACs should share the same TSF ID - * for the purpose of clock sync, an optimization to avoid - * clock drift causing overlapping TBTTs/DTIMs for a GO and - * client in the system. - * - * The firmware will decide according to the MAC type which - * will be the master and slave. Clients that need to sync - * with a remote station will be the master, and an AP or GO - * will be the slave. - * - * Depending on the new interface type it can be slaved to - * or become the master of an existing interface. - */ - switch (data->vif->type) { - case NL80211_IFTYPE_STATION: - /* - * The new interface is client, so if the existing one - * we're iterating is an AP, the TSF should be used to - * avoid drift between the new client and existing AP, - * the existing AP will get drift updates from the new - * client context in this case - */ - if (vif->type == NL80211_IFTYPE_AP) { - if (data->preferred_tsf == NUM_TSF_IDS && - test_bit(mvmvif->tsf_id, data->available_tsf_ids)) - data->preferred_tsf = mvmvif->tsf_id; - return; - } - break; - case NL80211_IFTYPE_AP: - /* - * The new interface is AP/GO, so should get drift - * updates from an existing client or use the same - * TSF as an existing GO. There's no drift between - * TSFs internally but if they used different TSFs - * then a new client MAC could update one of them - * and cause drift that way. - */ - if (vif->type == NL80211_IFTYPE_STATION || - vif->type == NL80211_IFTYPE_AP) { - if (data->preferred_tsf == NUM_TSF_IDS && - test_bit(mvmvif->tsf_id, data->available_tsf_ids)) - data->preferred_tsf = mvmvif->tsf_id; - return; - } - break; - default: - /* - * For all other interface types there's no need to - * take drift into account. Either they're exclusive - * like IBSS and monitor, or we don't care much about - * their TSF (like P2P Device), but we won't be able - * to share the TSF resource. - */ - break; - } - - /* - * Unless we exited above, we can't share the TSF resource - * that the virtual interface we're iterating over is using - * with the new one, so clear the available bit and if this - * was the preferred one, reset that as well. - */ - __clear_bit(mvmvif->tsf_id, data->available_tsf_ids); - - if (data->preferred_tsf == mvmvif->tsf_id) - data->preferred_tsf = NUM_TSF_IDS; -} - -/* - * Get the mask of the queus used by the vif - */ -u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - u32 qmask, ac; - - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) - return BIT(IWL_OFFCHANNEL_QUEUE); - - qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ? - BIT(vif->cab_queue) : 0; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - qmask |= BIT(vif->hw_queue[ac]); - - return qmask; -} - -static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_mac_iface_iterator_data data = { - .mvm = mvm, - .vif = vif, - .available_mac_ids = { (1 << NUM_MAC_INDEX_DRIVER) - 1 }, - .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, - /* no preference yet */ - .preferred_tsf = NUM_TSF_IDS, - .used_hw_queues = { - BIT(IWL_MVM_OFFCHANNEL_QUEUE) | - BIT(IWL_MVM_AUX_QUEUE) | - BIT(IWL_MVM_CMD_QUEUE) - }, - .found_vif = false, - }; - u32 ac; - int ret; - - /* - * Allocate a MAC ID and a TSF for this MAC, along with the queues - * and other resources. - */ - - /* - * Before the iterator, we start with all MAC IDs and TSFs available. - * - * During iteration, all MAC IDs are cleared that are in use by other - * virtual interfaces, and all TSF IDs are cleared that can't be used - * by this new virtual interface because they're used by an interface - * that can't share it with the new one. - * At the same time, we check if there's a preferred TSF in the case - * that we should share it with another interface. - */ - - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - iwl_mvm_mac_iface_iterator, &data); - - /* - * In the case we're getting here during resume, it's similar to - * firmware restart, and with RESUME_ALL the iterator will find - * the vif being added already. - * We don't want to reassign any IDs in either case since doing - * so would probably assign different IDs (as interfaces aren't - * necessarily added in the same order), but the old IDs were - * preserved anyway, so skip ID assignment for both resume and - * recovery. - */ - if (data.found_vif) - return 0; - - /* Therefore, in recovery, we can't get here */ - WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); - - mvmvif->id = find_first_bit(data.available_mac_ids, - NUM_MAC_INDEX_DRIVER); - if (mvmvif->id == NUM_MAC_INDEX_DRIVER) { - IWL_ERR(mvm, "Failed to init MAC context - no free ID!\n"); - ret = -EIO; - goto exit_fail; - } - - if (data.preferred_tsf != NUM_TSF_IDS) - mvmvif->tsf_id = data.preferred_tsf; - else - mvmvif->tsf_id = find_first_bit(data.available_tsf_ids, - NUM_TSF_IDS); - if (mvmvif->tsf_id == NUM_TSF_IDS) { - IWL_ERR(mvm, "Failed to init MAC context - no free TSF!\n"); - ret = -EIO; - goto exit_fail; - } - - mvmvif->color = 0; - - /* No need to allocate data queues to P2P Device MAC.*/ - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; - - return 0; - } - - /* Find available queues, and allocate them to the ACs */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - u8 queue = find_first_zero_bit(data.used_hw_queues, - IWL_MVM_FIRST_AGG_QUEUE); - - if (queue >= IWL_MVM_FIRST_AGG_QUEUE) { - IWL_ERR(mvm, "Failed to allocate queue\n"); - ret = -EIO; - goto exit_fail; - } - - __set_bit(queue, data.used_hw_queues); - vif->hw_queue[ac] = queue; - } - - /* Allocate the CAB queue for softAP and GO interfaces */ - if (vif->type == NL80211_IFTYPE_AP) { - u8 queue = find_first_zero_bit(data.used_hw_queues, - IWL_MVM_FIRST_AGG_QUEUE); - - if (queue >= IWL_MVM_FIRST_AGG_QUEUE) { - IWL_ERR(mvm, "Failed to allocate cab queue\n"); - ret = -EIO; - goto exit_fail; - } - - vif->cab_queue = queue; - } else { - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; - } - - mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT; - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - - INIT_LIST_HEAD(&mvmvif->time_event_data.list); - mvmvif->time_event_data.id = TE_MAX; - - return 0; - -exit_fail: - memset(mvmvif, 0, sizeof(struct iwl_mvm_vif)); - memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue)); - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; - return ret; -} - -int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - u32 ac; - int ret; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_mac_ctxt_allocate_resources(mvm, vif); - if (ret) - return ret; - - switch (vif->type) { - case NL80211_IFTYPE_P2P_DEVICE: - iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MVM_TX_FIFO_VO); - break; - case NL80211_IFTYPE_AP: - iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, - IWL_MVM_TX_FIFO_VO); - /* fall through */ - default: - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac]); - break; - } - - return 0; -} - -void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - int ac; - - lockdep_assert_held(&mvm->mutex); - - switch (vif->type) { - case NL80211_IFTYPE_P2P_DEVICE: - iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE); - break; - case NL80211_IFTYPE_AP: - iwl_trans_txq_disable(mvm->trans, vif->cab_queue); - /* fall through */ - default: - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]); - } -} - -static void iwl_mvm_ack_rates(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - enum ieee80211_band band, - u8 *cck_rates, u8 *ofdm_rates) -{ - struct ieee80211_supported_band *sband; - unsigned long basic = vif->bss_conf.basic_rates; - int lowest_present_ofdm = 100; - int lowest_present_cck = 100; - u8 cck = 0; - u8 ofdm = 0; - int i; - - sband = mvm->hw->wiphy->bands[band]; - - for_each_set_bit(i, &basic, BITS_PER_LONG) { - int hw = sband->bitrates[i].hw_value; - if (hw >= IWL_FIRST_OFDM_RATE) { - ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE); - if (lowest_present_ofdm > hw) - lowest_present_ofdm = hw; - } else { - BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0); - - cck |= BIT(hw); - if (lowest_present_cck > hw) - lowest_present_cck = hw; - } - } - - /* - * Now we've got the basic rates as bitmaps in the ofdm and cck - * variables. This isn't sufficient though, as there might not - * be all the right rates in the bitmap. E.g. if the only basic - * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps - * and 6 Mbps because the 802.11-2007 standard says in 9.6: - * - * [...] a STA responding to a received frame shall transmit - * its Control Response frame [...] at the highest rate in the - * BSSBasicRateSet parameter that is less than or equal to the - * rate of the immediately previous frame in the frame exchange - * sequence ([...]) and that is of the same modulation class - * ([...]) as the received frame. If no rate contained in the - * BSSBasicRateSet parameter meets these conditions, then the - * control frame sent in response to a received frame shall be - * transmitted at the highest mandatory rate of the PHY that is - * less than or equal to the rate of the received frame, and - * that is of the same modulation class as the received frame. - * - * As a consequence, we need to add all mandatory rates that are - * lower than all of the basic rates to these bitmaps. - */ - - if (IWL_RATE_24M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE; - if (IWL_RATE_12M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE; - /* 6M already there or needed so always add */ - ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE; - - /* - * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. - * Note, however: - * - if no CCK rates are basic, it must be ERP since there must - * be some basic rates at all, so they're OFDM => ERP PHY - * (or we're in 5 GHz, and the cck bitmap will never be used) - * - if 11M is a basic rate, it must be ERP as well, so add 5.5M - * - if 5.5M is basic, 1M and 2M are mandatory - * - if 2M is basic, 1M is mandatory - * - if 1M is basic, that's the only valid ACK rate. - * As a consequence, it's not as complicated as it sounds, just add - * any lower rates to the ACK rate bitmap. - */ - if (IWL_RATE_11M_INDEX < lowest_present_cck) - cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE; - if (IWL_RATE_5M_INDEX < lowest_present_cck) - cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE; - if (IWL_RATE_2M_INDEX < lowest_present_cck) - cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE; - /* 1M already there or needed so always add */ - cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE; - - *cck_rates = cck; - *ofdm_rates = ofdm; -} - -static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_mac_ctx_cmd *cmd, - u32 action) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct ieee80211_chanctx_conf *chanctx; - u8 cck_ack_rates, ofdm_ack_rates; - int i; - - cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)); - cmd->action = cpu_to_le32(action); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (vif->p2p) - cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_STA); - else - cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_BSS_STA); - break; - case NL80211_IFTYPE_AP: - cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_GO); - break; - case NL80211_IFTYPE_MONITOR: - cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_LISTENER); - break; - case NL80211_IFTYPE_P2P_DEVICE: - cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_DEVICE); - break; - case NL80211_IFTYPE_ADHOC: - cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_IBSS); - break; - default: - WARN_ON_ONCE(1); - } - - cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id); - - memcpy(cmd->node_addr, vif->addr, ETH_ALEN); - if (vif->bss_conf.bssid) - memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN); - else - eth_broadcast_addr(cmd->bssid_addr); - - rcu_read_lock(); - chanctx = rcu_dereference(vif->chanctx_conf); - iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band - : IEEE80211_BAND_2GHZ, - &cck_ack_rates, &ofdm_ack_rates); - rcu_read_unlock(); - - cmd->cck_rates = cpu_to_le32((u32)cck_ack_rates); - cmd->ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates); - - cmd->cck_short_preamble = - cpu_to_le32(vif->bss_conf.use_short_preamble ? - MAC_FLG_SHORT_PREAMBLE : 0); - cmd->short_slot = - cpu_to_le32(vif->bss_conf.use_short_slot ? - MAC_FLG_SHORT_SLOT : 0); - - for (i = 0; i < AC_NUM; i++) { - cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min); - cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max); - cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs; - cmd->ac[i].edca_txop = - cpu_to_le16(mvmvif->queue_params[i].txop * 32); - cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]); - } - - if (vif->bss_conf.qos) - cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); - - if (vif->bss_conf.use_cts_prot) - cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT | - MAC_PROT_FLG_SELF_CTS_EN); - - /* - * I think that we should enable these 2 flags regardless the HT PROT - * fields in the HT IE, but I am not sure. Someone knows whom to ask?... - */ - if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { - cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); - cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT | - MAC_PROT_FLG_FAT_PROT); - } - - cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP); -} - -static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, - struct iwl_mac_ctx_cmd *cmd) -{ - int ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC, - sizeof(*cmd), cmd); - if (ret) - IWL_ERR(mvm, "Failed to send MAC context (action:%d): %d\n", - le32_to_cpu(cmd->action), ret); - return ret; -} - -/* - * Fill the specific data for mac context of type station or p2p client - */ -static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_mac_data_sta *ctxt_sta) -{ - ctxt_sta->is_assoc = cpu_to_le32(vif->bss_conf.assoc ? 1 : 0); - - ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); - ctxt_sta->bi_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); - ctxt_sta->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period); - ctxt_sta->dtim_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period)); - - ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval); - ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid); -} - -static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 action) -{ - struct iwl_mac_ctx_cmd cmd = {}; - - WARN_ON(vif->type != NL80211_IFTYPE_STATION || vif->p2p); - - /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); - - /* Fill the data specific for station mode */ - iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); - - return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); -} - -static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 action) -{ - struct iwl_mac_ctx_cmd cmd = {}; - - WARN_ON(vif->type != NL80211_IFTYPE_STATION || !vif->p2p); - - /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); - - /* Fill the data specific for station mode */ - iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta); - - cmd.p2p_sta.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow); - - return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); -} - -static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 action) -{ - struct iwl_mac_ctx_cmd cmd = {}; - - WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); - - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); - /* No other data to be filled */ - return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); -} - -struct iwl_mvm_go_iterator_data { - bool go_active; -}; - -static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) -{ - struct iwl_mvm_go_iterator_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (vif->type == NL80211_IFTYPE_AP && vif->p2p && mvmvif->ap_active) - data->go_active = true; -} - -static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 action) -{ - struct iwl_mac_ctx_cmd cmd = {}; - struct iwl_mvm_go_iterator_data data = {}; - - WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); - - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); - - cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); - cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC); - - /* - * This flag should be set to true when the P2P Device is - * discoverable and there is at least another active P2P GO. Settings - * this flag will allow the P2P Device to be discoverable on other - * channels in addition to its listen channel. - * Note that this flag should not be set in other cases as it opens the - * Rx filters on all MAC and increases the number of interrupts. - */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - iwl_mvm_go_iterator, &data); - - cmd.p2p_dev.is_disc_extended = cpu_to_le32(data.go_active ? 1 : 0); - return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); -} - -static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, - struct iwl_mac_beacon_cmd *beacon_cmd, - u8 *beacon, u32 frame_size) -{ - u32 tim_idx; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; - - /* The index is relative to frame start but we start looking at the - * variable-length part of the beacon. */ - tim_idx = mgmt->u.beacon.variable - beacon; - - /* Parse variable-length elements of beacon to find WLAN_EID_TIM */ - while ((tim_idx < (frame_size - 2)) && - (beacon[tim_idx] != WLAN_EID_TIM)) - tim_idx += beacon[tim_idx+1] + 2; - - /* If TIM field was found, set variables */ - if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) { - beacon_cmd->tim_idx = cpu_to_le32(tim_idx); - beacon_cmd->tim_size = cpu_to_le32((u32)beacon[tim_idx+1]); - } else { - IWL_WARN(mvm, "Unable to find TIM Element in beacon\n"); - } -} - -static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct sk_buff *beacon) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_host_cmd cmd = { - .id = BEACON_TEMPLATE_CMD, - .flags = CMD_ASYNC, - }; - struct iwl_mac_beacon_cmd beacon_cmd = {}; - struct ieee80211_tx_info *info; - u32 beacon_skb_len; - u32 rate; - - if (WARN_ON(!beacon)) - return -EINVAL; - - beacon_skb_len = beacon->len; - - /* TODO: for now the beacon template id is set to be the mac context id. - * Might be better to handle it as another resource ... */ - beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); - - /* Set up TX command fields */ - beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len); - beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id; - beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); - beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | - TX_CMD_FLG_BT_DIS | - TX_CMD_FLG_TSF); - - mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, - mvm->mgmt_last_antenna_idx); - - beacon_cmd.tx.rate_n_flags = - cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << - RATE_MCS_ANT_POS); - - info = IEEE80211_SKB_CB(beacon); - - if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) { - rate = IWL_FIRST_OFDM_RATE; - } else { - rate = IWL_FIRST_CCK_RATE; - beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK); - } - beacon_cmd.tx.rate_n_flags |= - cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); - - /* Set up TX beacon command fields */ - iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd, - beacon->data, - beacon_skb_len); - - /* Submit command */ - cmd.len[0] = sizeof(beacon_cmd); - cmd.data[0] = &beacon_cmd; - cmd.dataflags[0] = 0; - cmd.len[1] = beacon_skb_len; - cmd.data[1] = beacon->data; - cmd.dataflags[1] = IWL_HCMD_DFL_DUP; - - return iwl_mvm_send_cmd(mvm, &cmd); -} - -/* The beacon template for the AP/GO context has changed and needs update */ -int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct sk_buff *beacon; - int ret; - - WARN_ON(vif->type != NL80211_IFTYPE_AP); - - beacon = ieee80211_beacon_get(mvm->hw, vif); - if (!beacon) - return -ENOMEM; - - ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon); - dev_kfree_skb(beacon); - return ret; -} - -/* - * Fill the specific data for mac context of type AP of P2P GO - */ -static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_mac_data_ap *ctxt_ap) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 curr_dev_time; - - ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int); - ctxt_ap->bi_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); - ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period); - ctxt_ap->dtim_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period)); - - ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue); - curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); - ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time); - - ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time); - - /* TODO: Assume that the beacon id == mac context id */ - ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id); -} - -static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 action) -{ - struct iwl_mac_ctx_cmd cmd = {}; - - WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); - - /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); - - /* Fill the data specific for ap mode */ - iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap); - - return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); -} - -static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 action) -{ - struct iwl_mac_ctx_cmd cmd = {}; - - WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p); - - /* Fill the common data for all mac context types */ - iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); - - /* Fill the data specific for GO mode */ - iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap); - - cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow); - cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps); - - return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); -} - -static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 action) -{ - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->p2p) - return iwl_mvm_mac_ctxt_cmd_station(mvm, vif, - action); - else - return iwl_mvm_mac_ctxt_cmd_p2p_client(mvm, vif, - action); - break; - case NL80211_IFTYPE_AP: - if (!vif->p2p) - return iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, action); - else - return iwl_mvm_mac_ctxt_cmd_go(mvm, vif, action); - break; - case NL80211_IFTYPE_MONITOR: - return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action); - case NL80211_IFTYPE_P2P_DEVICE: - return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action); - default: - break; - } - - return -EOPNOTSUPP; -} - -int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n", - vif->addr, ieee80211_vif_type_p2p(vif))) - return -EIO; - - ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD); - if (ret) - return ret; - - mvmvif->uploaded = true; - return 0; -} - -int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n", - vif->addr, ieee80211_vif_type_p2p(vif))) - return -EIO; - - return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY); -} - -int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mac_ctx_cmd cmd; - int ret; - - if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n", - vif->addr, ieee80211_vif_type_p2p(vif))) - return -EIO; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)); - cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); - - ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC, - sizeof(cmd), &cmd); - if (ret) { - IWL_ERR(mvm, "Failed to remove MAC context: %d\n", ret); - return ret; - } - - mvmvif->uploaded = false; - return 0; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/trunk/drivers/net/wireless/iwlwifi/mvm/mac80211.c deleted file mode 100644 index ce6127caabdf..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ /dev/null @@ -1,1310 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include -#include -#include -#include -#include - -#include "iwl-op-mode.h" -#include "iwl-io.h" -#include "mvm.h" -#include "sta.h" -#include "time-event.h" -#include "iwl-eeprom-parse.h" -#include "fw-api-scan.h" -#include "iwl-phy-db.h" - -static const struct ieee80211_iface_limit iwl_mvm_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE), - }, -}; - -static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { - { - .num_different_channels = 1, - .max_interfaces = 3, - .limits = iwl_mvm_limits, - .n_limits = ARRAY_SIZE(iwl_mvm_limits), - }, -}; - -int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) -{ - struct ieee80211_hw *hw = mvm->hw; - int num_mac, ret; - - /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_REPORTS_TX_ACK_STATUS | - IEEE80211_HW_QUEUE_CONTROL | - IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_SCAN_WHILE_IDLE | - IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - IEEE80211_HW_AMPDU_AGGREGATION; - - hw->queues = IWL_FIRST_AMPDU_QUEUE; - hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE; - hw->rate_control_algorithm = "iwl-mvm-rs"; - - /* - * Enable 11w if advertised by firmware and software crypto - * is not enabled (as the firmware will interpret some mgmt - * packets, so enabling it with software crypto isn't safe) - */ - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && - !iwlwifi_mod_params.sw_crypto) - hw->flags |= IEEE80211_HW_MFP_CAPABLE; - - hw->sta_data_size = sizeof(struct iwl_mvm_sta); - hw->vif_data_size = sizeof(struct iwl_mvm_vif); - hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt); - - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_DEVICE); - - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; - - hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; - hw->wiphy->n_iface_combinations = - ARRAY_SIZE(iwl_mvm_iface_combinations); - - hw->wiphy->max_remain_on_channel_duration = 500; - hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; - - /* Extract MAC address */ - memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); - hw->wiphy->addresses = mvm->addresses; - hw->wiphy->n_addresses = 1; - num_mac = mvm->nvm_data->n_hw_addrs; - if (num_mac > 1) { - memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr, - ETH_ALEN); - mvm->addresses[1].addr[5]++; - hw->wiphy->n_addresses++; - } - - /* we create the 802.11 header and a max-length SSID element */ - hw->wiphy->max_scan_ie_len = - mvm->fw->ucode_capa.max_probe_length - 24 - 34; - hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; - - if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; - if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; - - hw->wiphy->hw_version = mvm->trans->hw_id; - - if (iwlwifi_mod_params.power_save) - hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; - else - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - - hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | - NL80211_FEATURE_P2P_GO_OPPPS; - - mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - -#ifdef CONFIG_PM_SLEEP - if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && - mvm->trans->ops->d3_suspend && - mvm->trans->ops->d3_resume && - device_can_wakeup(mvm->trans->dev)) { - hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | - WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_EAP_IDENTITY_REQ | - WIPHY_WOWLAN_RFKILL_RELEASE; - if (!iwlwifi_mod_params.sw_crypto) - hw->wiphy->wowlan.flags |= - WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | - WIPHY_WOWLAN_GTK_REKEY_FAILURE | - WIPHY_WOWLAN_4WAY_HANDSHAKE; - - hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; - hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; - hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; - } -#endif - - ret = iwl_mvm_leds_init(mvm); - if (ret) - return ret; - - return ieee80211_register_hw(mvm->hw); -} - -static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, - struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) { - IWL_DEBUG_DROP(mvm, "Dropping - RF KILL\n"); - goto drop; - } - - if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE && - !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) - goto drop; - - if (control->sta) { - if (iwl_mvm_tx_skb(mvm, skb, control->sta)) - goto drop; - return; - } - - if (iwl_mvm_tx_skb_non_sta(mvm, skb)) - goto drop; - return; - drop: - ieee80211_free_txskb(hw, skb); -} - -static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, - u16 *ssn, u8 buf_size) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", - sta->addr, tid, action); - - if (!(mvm->nvm_data->sku_cap_11n_enable)) - return -EACCES; - - mutex_lock(&mvm->mutex); - - switch (action) { - case IEEE80211_AMPDU_RX_START: - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) { - ret = -EINVAL; - break; - } - ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true); - break; - case IEEE80211_AMPDU_RX_STOP: - ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); - break; - case IEEE80211_AMPDU_TX_START: - ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); - break; - case IEEE80211_AMPDU_TX_STOP_CONT: - case IEEE80211_AMPDU_TX_STOP_FLUSH: - case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: - ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); - break; - default: - WARN_ON_ONCE(1); - ret = -EINVAL; - break; - } - mutex_unlock(&mvm->mutex); - - return ret; -} - -static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - mvmvif->uploaded = false; - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - - /* does this make sense at all? */ - mvmvif->color++; - - spin_lock_bh(&mvm->time_event_lock); - iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); - spin_unlock_bh(&mvm->time_event_lock); - - if (vif->type != NL80211_IFTYPE_P2P_DEVICE) - mvmvif->phy_ctxt = NULL; -} - -static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) -{ - iwl_trans_stop_device(mvm->trans); - iwl_trans_stop_hw(mvm->trans, false); - - mvm->scan_status = IWL_MVM_SCAN_NONE; - - /* just in case one was running */ - ieee80211_remain_on_channel_expired(mvm->hw); - - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - iwl_mvm_cleanup_iterator, mvm); - - memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); - memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); - - ieee80211_wake_queues(mvm->hw); - - mvm->vif_count = 0; -} - -static int iwl_mvm_mac_start(struct ieee80211_hw *hw) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - mutex_lock(&mvm->mutex); - - /* Clean up some internal and mac80211 state on restart */ - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - iwl_mvm_restart_cleanup(mvm); - - ret = iwl_mvm_up(mvm); - mutex_unlock(&mvm->mutex); - - return ret; -} - -static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - mutex_lock(&mvm->mutex); - - clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - ret = iwl_mvm_update_quotas(mvm, NULL); - if (ret) - IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", - ret); - - mutex_unlock(&mvm->mutex); -} - -static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - flush_work(&mvm->async_handlers_wk); - - mutex_lock(&mvm->mutex); - /* async_handlers_wk is now blocked */ - - /* - * The work item could be running or queued if the - * ROC time event stops just as we get here. - */ - cancel_work_sync(&mvm->roc_done_wk); - - iwl_trans_stop_device(mvm->trans); - iwl_trans_stop_hw(mvm->trans, false); - - iwl_mvm_async_handlers_purge(mvm); - /* async_handlers_list is empty and will stay empty: HW is stopped */ - - /* the fw is stopped, the aux sta is dead: clean up driver state */ - iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); - - mutex_unlock(&mvm->mutex); - - /* - * The worker might have been waiting for the mutex, let it run and - * discover that its list is now empty. - */ - cancel_work_sync(&mvm->async_handlers_wk); -} - -static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = data; - int ret; - - ret = iwl_mvm_power_disable(mvm, vif); - if (ret) - IWL_ERR(mvm, "failed to disable power management\n"); -} - -static void iwl_mvm_power_update_iterator(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = data; - - iwl_mvm_power_update_mode(mvm, vif); -} - -static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - /* - * Not much to do here. The stack will not allow interface - * types or combinations that we didn't advertise, so we - * don't really have to check the types. - */ - - mutex_lock(&mvm->mutex); - - /* Allocate resources for the MAC context, and add it the the fw */ - ret = iwl_mvm_mac_ctxt_init(mvm, vif); - if (ret) - goto out_unlock; - - /* - * The AP binding flow can be done only after the beacon - * template is configured (which happens only in the mac80211 - * start_ap() flow), and adding the broadcast station can happen - * only after the binding. - * In addition, since modifying the MAC before adding a bcast - * station is not allowed by the FW, delay the adding of MAC context to - * the point where we can also add the bcast station. - * In short: there's not much we can do at this point, other than - * allocating resources :) - */ - if (vif->type == NL80211_IFTYPE_AP) { - u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); - ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, - qmask); - if (ret) { - IWL_ERR(mvm, "Failed to allocate bcast sta\n"); - goto out_release; - } - - goto out_unlock; - } - - /* - * TODO: remove this temporary code. - * Currently MVM FW supports power management only on single MAC. - * Iterate and disable PM on all active interfaces. - * Note: the method below does not count the new interface being added - * at this moment. - */ - mvm->vif_count++; - if (mvm->vif_count > 1) { - IWL_DEBUG_MAC80211(mvm, - "Disable power on existing interfaces\n"); - ieee80211_iterate_active_interfaces( - mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_pm_disable_iterator, mvm); - } - - ret = iwl_mvm_mac_ctxt_add(mvm, vif); - if (ret) - goto out_release; - - /* - * Update power state on the new interface. Admittedly, based on - * mac80211 logics this power update will disable power management - */ - iwl_mvm_power_update_mode(mvm, vif); - - /* - * P2P_DEVICE interface does not have a channel context assigned to it, - * so a dedicated PHY context is allocated to it and the corresponding - * MAC context is bound to it at this stage. - */ - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - struct ieee80211_channel *chan; - struct cfg80211_chan_def chandef; - - mvmvif->phy_ctxt = &mvm->phy_ctxt_roc; - - /* - * The channel used here isn't relevant as it's - * going to be overwritten as part of the ROC flow. - * For now use the first channel we have. - */ - chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; - cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); - ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, - &chandef, 1, 1); - if (ret) - goto out_remove_mac; - - ret = iwl_mvm_binding_add_vif(mvm, vif); - if (ret) - goto out_remove_phy; - - ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); - if (ret) - goto out_unbind; - - /* Save a pointer to p2p device vif, so it can later be used to - * update the p2p device MAC when a GO is started/stopped */ - mvm->p2p_device_vif = vif; - } - - goto out_unlock; - - out_unbind: - iwl_mvm_binding_remove_vif(mvm, vif); - out_remove_phy: - iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); - out_remove_mac: - mvmvif->phy_ctxt = NULL; - iwl_mvm_mac_ctxt_remove(mvm, vif); - out_release: - /* - * TODO: remove this temporary code. - * Currently MVM FW supports power management only on single MAC. - * Check if only one additional interface remains after rereasing - * current one. Update power mode on the remaining interface. - */ - mvm->vif_count--; - IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", - mvm->vif_count); - if (mvm->vif_count == 1) { - ieee80211_iterate_active_interfaces( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_update_iterator, mvm); - } - iwl_mvm_mac_ctxt_release(mvm, vif); - out_unlock: - mutex_unlock(&mvm->mutex); - - return ret; -} - -static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 tfd_msk = 0, ac; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - tfd_msk |= BIT(vif->hw_queue[ac]); - - if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) - tfd_msk |= BIT(vif->cab_queue); - - if (tfd_msk) { - mutex_lock(&mvm->mutex); - iwl_mvm_flush_tx_path(mvm, tfd_msk, true); - mutex_unlock(&mvm->mutex); - } - - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - /* - * Flush the ROC worker which will flush the OFFCHANNEL queue. - * We assume here that all the packets sent to the OFFCHANNEL - * queue are sent in ROC session. - */ - flush_work(&mvm->roc_done_wk); - } else { - /* - * By now, all the AC queues are empty. The AGG queues are - * empty too. We already got all the Tx responses for all the - * packets in the queues. The drain work can have been - * triggered. Flush it. This work item takes the mutex, so kill - * it before we take it. - */ - flush_work(&mvm->sta_drained_wk); - } - - mutex_lock(&mvm->mutex); - - /* - * For AP/GO interface, the tear down of the resources allocated to the - * interface should be handled as part of the bss_info_changed flow. - */ - if (vif->type == NL80211_IFTYPE_AP) { - iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); - goto out_release; - } - - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - mvm->p2p_device_vif = NULL; - iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); - iwl_mvm_binding_remove_vif(mvm, vif); - iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); - mvmvif->phy_ctxt = NULL; - } - - /* - * TODO: remove this temporary code. - * Currently MVM FW supports power management only on single MAC. - * Check if only one additional interface remains after removing - * current one. Update power mode on the remaining interface. - */ - if (mvm->vif_count) - mvm->vif_count--; - IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", - mvm->vif_count); - if (mvm->vif_count == 1) { - ieee80211_iterate_active_interfaces( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_power_update_iterator, mvm); - } - - iwl_mvm_mac_ctxt_remove(mvm, vif); - -out_release: - iwl_mvm_mac_ctxt_release(mvm, vif); - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - return 0; -} - -static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - *total_flags = 0; -} - -static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - ret = iwl_mvm_mac_ctxt_changed(mvm, vif); - if (ret) - IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); - - if (changes & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - /* add quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, vif); - if (ret) { - IWL_ERR(mvm, "failed to update quotas\n"); - return; - } - iwl_mvm_remove_time_event(mvm, mvmvif, - &mvmvif->time_event_data); - } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { - /* remove AP station now that the MAC is unassoc */ - ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); - if (ret) - IWL_ERR(mvm, "failed to remove AP station\n"); - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - /* remove quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, NULL); - if (ret) - IWL_ERR(mvm, "failed to update quotas\n"); - } - } else if (changes & BSS_CHANGED_PS) { - /* - * TODO: remove this temporary code. - * Currently MVM FW supports power management only on single - * MAC. Avoid power mode update if more than one interface - * is active. - */ - IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", - mvm->vif_count); - if (mvm->vif_count == 1) { - ret = iwl_mvm_power_update_mode(mvm, vif); - if (ret) - IWL_ERR(mvm, "failed to update power mode\n"); - } - } -} - -static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - mutex_lock(&mvm->mutex); - - /* Send the beacon template */ - ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif); - if (ret) - goto out_unlock; - - /* Add the mac context */ - ret = iwl_mvm_mac_ctxt_add(mvm, vif); - if (ret) - goto out_unlock; - - /* Perform the binding */ - ret = iwl_mvm_binding_add_vif(mvm, vif); - if (ret) - goto out_remove; - - mvmvif->ap_active = true; - - /* Send the bcast station. At this stage the TBTT and DTIM time events - * are added and applied to the scheduler */ - ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); - if (ret) - goto out_unbind; - - ret = iwl_mvm_update_quotas(mvm, vif); - if (ret) - goto out_rm_bcast; - - /* Need to update the P2P Device MAC */ - if (vif->p2p && mvm->p2p_device_vif) - iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); - - mutex_unlock(&mvm->mutex); - return 0; - -out_rm_bcast: - iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); -out_unbind: - iwl_mvm_binding_remove_vif(mvm, vif); -out_remove: - iwl_mvm_mac_ctxt_remove(mvm, vif); -out_unlock: - mutex_unlock(&mvm->mutex); - return ret; -} - -static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - mutex_lock(&mvm->mutex); - - mvmvif->ap_active = false; - - /* Need to update the P2P Device MAC */ - if (vif->p2p && mvm->p2p_device_vif) - iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); - - iwl_mvm_update_quotas(mvm, NULL); - iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); - iwl_mvm_binding_remove_vif(mvm, vif); - iwl_mvm_mac_ctxt_remove(mvm, vif); - - mutex_unlock(&mvm->mutex); -} - -static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - /* Need to send a new beacon template to the FW */ - if (changes & BSS_CHANGED_BEACON) { - if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) - IWL_WARN(mvm, "Failed updating beacon data\n"); - } -} - -static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - mutex_lock(&mvm->mutex); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); - break; - case NL80211_IFTYPE_AP: - iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes); - break; - default: - /* shouldn't happen */ - WARN_ON_ONCE(1); - } - - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) - return -EINVAL; - - mutex_lock(&mvm->mutex); - - if (mvm->scan_status == IWL_MVM_SCAN_NONE) - ret = iwl_mvm_scan_request(mvm, vif, req); - else - ret = -EBUSY; - - mutex_unlock(&mvm->mutex); - - return ret; -} - -static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - mutex_lock(&mvm->mutex); - - iwl_mvm_cancel_scan(mvm); - - mutex_unlock(&mvm->mutex); -} - -static void -iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, u16 tid, - int num_frames, - enum ieee80211_frame_release_type reason, - bool more_data) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - - /* TODO: how do we tell the fw to send frames for a specific TID */ - - /* - * The fw will send EOSP notification when the last frame will be - * transmitted. - */ - iwl_mvm_sta_modify_sleep_tx_count(mvm, mvmsta->sta_id, reason, - num_frames); -} - -static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - - switch (cmd) { - case STA_NOTIFY_SLEEP: - if (atomic_read(&mvmsta->pending_frames) > 0) - ieee80211_sta_block_awake(hw, sta, true); - /* - * The fw updates the STA to be asleep. Tx packets on the Tx - * queues to this station will not be transmitted. The fw will - * send a Tx response with TX_STATUS_FAIL_DEST_PS. - */ - break; - case STA_NOTIFY_AWAKE: - if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION)) - break; - iwl_mvm_sta_modify_ps_wake(mvm, mvmsta->sta_id); - break; - default: - break; - } -} - -static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n", - sta->addr, old_state, new_state); - - /* this would be a mac80211 bug ... but don't crash */ - if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) - return -EINVAL; - - /* if a STA is being removed, reuse its ID */ - flush_work(&mvm->sta_drained_wk); - - mutex_lock(&mvm->mutex); - if (old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE) { - ret = iwl_mvm_add_sta(mvm, vif, sta); - } else if (old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_AUTH) { - ret = 0; - } else if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC) { - iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); - ret = 0; - } else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTHORIZED) { - ret = 0; - } else if (old_state == IEEE80211_STA_AUTHORIZED && - new_state == IEEE80211_STA_ASSOC) { - ret = 0; - } else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTH) { - ret = 0; - } else if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_NONE) { - ret = 0; - } else if (old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST) { - ret = iwl_mvm_rm_sta(mvm, vif, sta); - } else { - ret = -EIO; - } - mutex_unlock(&mvm->mutex); - - return ret; -} - -static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - mvm->rts_threshold = value; - - return 0; -} - -static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - mvmvif->queue_params[ac] = *params; - - /* - * No need to update right away, we'll get BSS_CHANGED_QOS - * The exception is P2P_DEVICE interface which needs immediate update. - */ - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - int ret; - - mutex_lock(&mvm->mutex); - ret = iwl_mvm_mac_ctxt_changed(mvm, vif); - mutex_unlock(&mvm->mutex); - return ret; - } - return 0; -} - -static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS, - 200 + vif->bss_conf.beacon_int); - u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS, - 100 + vif->bss_conf.beacon_int); - - if (WARN_ON_ONCE(vif->bss_conf.assoc)) - return; - - mutex_lock(&mvm->mutex); - /* Try really hard to protect the session and hear a beacon */ - iwl_mvm_protect_session(mvm, vif, duration, min_duration); - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - if (iwlwifi_mod_params.sw_crypto) { - IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); - return -EOPNOTSUPP; - } - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_TKIP: - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - /* fall-through */ - case WLAN_CIPHER_SUITE_CCMP: - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE)); - break; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - /* - * Support for TX only, at least for now, so accept - * the key and do nothing else. Then mac80211 will - * pass it for TX but we don't have to use it for RX. - */ - return 0; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&mvm->mutex); - - switch (cmd) { - case SET_KEY: - IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false); - if (ret) { - IWL_WARN(mvm, "set key failed\n"); - /* - * can't add key for RX, but we don't need it - * in the device for TX so still return 0 - */ - ret = 0; - } - - break; - case DISABLE_KEY: - IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); - ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&mvm->mutex); - return ret; -} - -static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); -} - - -static int iwl_mvm_roc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel *channel, - int duration) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct cfg80211_chan_def chandef; - int ret; - - if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { - IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); - return -EINVAL; - } - - IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value, - duration); - - mutex_lock(&mvm->mutex); - - cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); - ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc, - &chandef, 1, 1); - - /* Schedule the time events */ - ret = iwl_mvm_start_p2p_roc(mvm, vif, duration); - - mutex_unlock(&mvm->mutex); - IWL_DEBUG_MAC80211(mvm, "leave\n"); - - return ret; -} - -static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - IWL_DEBUG_MAC80211(mvm, "enter\n"); - - mutex_lock(&mvm->mutex); - iwl_mvm_stop_p2p_roc(mvm); - mutex_unlock(&mvm->mutex); - - IWL_DEBUG_MAC80211(mvm, "leave\n"); - return 0; -} - -static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; - int ret; - - mutex_lock(&mvm->mutex); - - IWL_DEBUG_MAC80211(mvm, "Add PHY context\n"); - ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def, - ctx->rx_chains_static, - ctx->rx_chains_dynamic); - mutex_unlock(&mvm->mutex); - return ret; -} - -static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; - - mutex_lock(&mvm->mutex); - iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt); - mutex_unlock(&mvm->mutex); -} - -static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx, - u32 changed) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; - - mutex_lock(&mvm->mutex); - iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, - ctx->rx_chains_static, - ctx->rx_chains_dynamic); - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - mutex_lock(&mvm->mutex); - - mvmvif->phy_ctxt = phyctx; - - switch (vif->type) { - case NL80211_IFTYPE_AP: - /* - * The AP binding flow is handled as part of the start_ap flow - * (in bss_info_changed). - */ - ret = 0; - goto out_unlock; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MONITOR: - break; - default: - ret = -EINVAL; - goto out_unlock; - } - - ret = iwl_mvm_binding_add_vif(mvm, vif); - if (ret) - goto out_unlock; - - /* - * Setting the quota at this stage is only required for monitor - * interfaces. For the other types, the bss_info changed flow - * will handle quota settings. - */ - if (vif->type == NL80211_IFTYPE_MONITOR) { - ret = iwl_mvm_update_quotas(mvm, vif); - if (ret) - goto out_remove_binding; - } - - goto out_unlock; - - out_remove_binding: - iwl_mvm_binding_remove_vif(mvm, vif); - out_unlock: - mutex_unlock(&mvm->mutex); - if (ret) - mvmvif->phy_ctxt = NULL; - return ret; -} - -static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - mutex_lock(&mvm->mutex); - - iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); - - if (vif->type == NL80211_IFTYPE_AP) - goto out_unlock; - - iwl_mvm_binding_remove_vif(mvm, vif); - switch (vif->type) { - case NL80211_IFTYPE_MONITOR: - iwl_mvm_update_quotas(mvm, vif); - break; - default: - break; - } - -out_unlock: - mvmvif->phy_ctxt = NULL; - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_set_tim(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, - bool set) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - - if (!mvm_sta || !mvm_sta->vif) { - IWL_ERR(mvm, "Station is not associated to a vif\n"); - return -EINVAL; - } - - return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); -} - -struct ieee80211_ops iwl_mvm_hw_ops = { - .tx = iwl_mvm_mac_tx, - .ampdu_action = iwl_mvm_mac_ampdu_action, - .start = iwl_mvm_mac_start, - .restart_complete = iwl_mvm_mac_restart_complete, - .stop = iwl_mvm_mac_stop, - .add_interface = iwl_mvm_mac_add_interface, - .remove_interface = iwl_mvm_mac_remove_interface, - .config = iwl_mvm_mac_config, - .configure_filter = iwl_mvm_configure_filter, - .bss_info_changed = iwl_mvm_bss_info_changed, - .hw_scan = iwl_mvm_mac_hw_scan, - .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan, - .sta_state = iwl_mvm_mac_sta_state, - .sta_notify = iwl_mvm_mac_sta_notify, - .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, - .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, - .conf_tx = iwl_mvm_mac_conf_tx, - .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, - .set_key = iwl_mvm_mac_set_key, - .update_tkip_key = iwl_mvm_mac_update_tkip_key, - .remain_on_channel = iwl_mvm_roc, - .cancel_remain_on_channel = iwl_mvm_cancel_roc, - - .add_chanctx = iwl_mvm_add_chanctx, - .remove_chanctx = iwl_mvm_remove_chanctx, - .change_chanctx = iwl_mvm_change_chanctx, - .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, - .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, - - .start_ap = iwl_mvm_start_ap, - .stop_ap = iwl_mvm_stop_ap, - - .set_tim = iwl_mvm_set_tim, - -#ifdef CONFIG_PM_SLEEP - /* look at d3.c */ - .suspend = iwl_mvm_suspend, - .resume = iwl_mvm_resume, - .set_wakeup = iwl_mvm_set_wakeup, - .set_rekey_data = iwl_mvm_set_rekey_data, -#if IS_ENABLED(CONFIG_IPV6) - .ipv6_addr_change = iwl_mvm_ipv6_addr_change, -#endif - .set_default_unicast_key = iwl_mvm_set_default_unicast_key, -#endif -}; diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/mvm.h b/trunk/drivers/net/wireless/iwlwifi/mvm/mvm.h deleted file mode 100644 index 4e339ccfa800..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ /dev/null @@ -1,500 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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_MVM_H__ -#define __IWL_MVM_H__ - -#include -#include -#include -#include - -#include "iwl-op-mode.h" -#include "iwl-trans.h" -#include "iwl-notif-wait.h" -#include "iwl-eeprom-parse.h" -#include "iwl-test.h" -#include "iwl-trans.h" -#include "sta.h" -#include "fw-api.h" - -#define IWL_INVALID_MAC80211_QUEUE 0xff -#define IWL_MVM_MAX_ADDRESSES 2 -#define IWL_RSSI_OFFSET 44 - -enum iwl_mvm_tx_fifo { - IWL_MVM_TX_FIFO_BK = 0, - IWL_MVM_TX_FIFO_BE, - IWL_MVM_TX_FIFO_VI, - IWL_MVM_TX_FIFO_VO, -}; - -/* Placeholder */ -#define IWL_OFFCHANNEL_QUEUE 8 -#define IWL_FIRST_AMPDU_QUEUE 11 - -extern struct ieee80211_ops iwl_mvm_hw_ops; -/** - * struct iwl_mvm_mod_params - module parameters for iwlmvm - * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. - * We will register to mac80211 to have testmode working. The NIC must not - * be up'ed after the INIT fw asserted. This is useful to be able to use - * proprietary tools over testmode to debug the INIT fw. - * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power - * Save)-2(default), LP(Low Power)-3 - */ -struct iwl_mvm_mod_params { - bool init_dbg; - int power_scheme; -}; -extern struct iwl_mvm_mod_params iwlmvm_mod_params; - -struct iwl_mvm_phy_ctxt { - u16 id; - u16 color; - - /* - * TODO: This should probably be removed. Currently here only for rate - * scaling algorithm - */ - struct ieee80211_channel *channel; -}; - -struct iwl_mvm_time_event_data { - struct ieee80211_vif *vif; - struct list_head list; - unsigned long end_jiffies; - u32 duration; - bool running; - u32 uid; - - /* - * The access to the 'id' field must be done when the - * mvm->time_event_lock is held, as it value is used to indicate - * if the te is in the time event list or not (when id == TE_MAX) - */ - u32 id; -}; - - /* Power management */ - -/** - * enum iwl_power_scheme - * @IWL_POWER_LEVEL_CAM - Continuously Active Mode - * @IWL_POWER_LEVEL_BPS - Balanced Power Save (default) - * @IWL_POWER_LEVEL_LP - Low Power - */ -enum iwl_power_scheme { - IWL_POWER_SCHEME_CAM = 1, - IWL_POWER_SCHEME_BPS, - IWL_POWER_SCHEME_LP -}; - -#define IWL_CONN_MAX_LISTEN_INTERVAL 70 - -/** - * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context - * @id: between 0 and 3 - * @color: to solve races upon MAC addition and removal - * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA - * @uploaded: indicates the MAC context has been added to the device - * @ap_active: indicates that ap context is configured, and that the interface - * should get quota etc. - * @queue_params: QoS params for this MAC - * @bcast_sta: station used for broadcast packets. Used by the following - * vifs: P2P_DEVICE, GO and AP. - * @beacon_skb: the skb used to hold the AP/GO beacon template - */ -struct iwl_mvm_vif { - u16 id; - u16 color; - u8 ap_sta_id; - - bool uploaded; - bool ap_active; - - enum iwl_tsf_id tsf_id; - - /* - * QoS data from mac80211, need to store this here - * as mac80211 has a separate callback but we need - * to have the data for the MAC context - */ - struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; - struct iwl_mvm_time_event_data time_event_data; - - struct iwl_mvm_int_sta bcast_sta; - - /* - * Assigned while mac80211 has the interface in a channel context, - * or, for P2P Device, while it exists. - */ - struct iwl_mvm_phy_ctxt *phy_ctxt; - -#ifdef CONFIG_PM_SLEEP - /* WoWLAN GTK rekey data */ - struct { - u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; - __le64 replay_ctr; - bool valid; - } rekey_data; - - int tx_key_idx; - -#if IS_ENABLED(CONFIG_IPV6) - /* IPv6 addresses for WoWLAN */ - struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS]; - int num_target_ipv6_addrs; -#endif -#endif - -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct dentry *dbgfs_dir; - void *dbgfs_data; -#endif -}; - -static inline struct iwl_mvm_vif * -iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) -{ - return (void *)vif->drv_priv; -} - -enum iwl_mvm_status { - IWL_MVM_STATUS_HW_RFKILL, - IWL_MVM_STATUS_ROC_RUNNING, - IWL_MVM_STATUS_IN_HW_RESTART, -}; - -enum iwl_scan_status { - IWL_MVM_SCAN_NONE, - IWL_MVM_SCAN_OS, -}; - -/** - * struct iwl_nvm_section - describes an NVM section in memory. - * - * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD, - * and saved for later use by the driver. Not all NVM sections are saved - * this way, only the needed ones. - */ -struct iwl_nvm_section { - u16 length; - const u8 *data; -}; - -struct iwl_mvm { - /* for logger access */ - struct device *dev; - - struct iwl_trans *trans; - const struct iwl_fw *fw; - const struct iwl_cfg *cfg; - struct iwl_phy_db *phy_db; - struct ieee80211_hw *hw; - - /* for protecting access to iwl_mvm */ - struct mutex mutex; - struct list_head async_handlers_list; - spinlock_t async_handlers_lock; - struct work_struct async_handlers_wk; - - struct work_struct roc_done_wk; - - unsigned long status; - - enum iwl_ucode_type cur_ucode; - bool ucode_loaded; - bool init_ucode_run; - u32 error_event_table; - u32 log_event_table; - - u32 ampdu_ref; - - struct iwl_notif_wait_data notif_wait; - - unsigned long transport_queue_stop; - u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; - atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; - - struct iwl_nvm_data *nvm_data; - /* eeprom blob for debugfs/testmode */ - u8 *eeprom_blob; - size_t eeprom_blob_size; - /* NVM sections for 7000 family */ - struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS]; - - /* EEPROM MAC addresses */ - struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; - - /* data related to data path */ - struct iwl_rx_phy_info last_phy_info; - struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; - struct work_struct sta_drained_wk; - unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; - - /* configured by mac80211 */ - u32 rts_threshold; - - /* Scan status, cmd (pre-allocated) and auxiliary station */ - enum iwl_scan_status scan_status; - struct iwl_scan_cmd *scan_cmd; - - /* Internal station */ - struct iwl_mvm_int_sta aux_sta; - - u8 scan_last_antenna_idx; /* to toggle TX between antennas */ - u8 mgmt_last_antenna_idx; - -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct dentry *debugfs_dir; - u32 dbgfs_sram_offset, dbgfs_sram_len; - bool prevent_power_down_d3; -#endif - - struct iwl_mvm_phy_ctxt phy_ctxt_roc; - - struct list_head time_event_list; - spinlock_t time_event_lock; - - /* - * A bitmap indicating the index of the key in use. The firmware - * can hold 16 keys at most. Reflect this fact. - */ - unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; - u8 vif_count; - - struct led_classdev led; - - struct ieee80211_vif *p2p_device_vif; -}; - -/* Extract MVM priv from op_mode and _hw */ -#define IWL_OP_MODE_GET_MVM(_iwl_op_mode) \ - ((struct iwl_mvm *)(_iwl_op_mode)->op_mode_specific) - -#define IWL_MAC80211_GET_MVM(_hw) \ - IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) - -extern const u8 iwl_mvm_ac_to_tx_fifo[]; - -struct iwl_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ - u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ - u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ -}; - -/****************** - * MVM Methods - ******************/ -/* uCode */ -int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm); - -/* Utils */ -int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, - enum ieee80211_band band); -u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); -u8 first_antenna(u8 mask); -u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); - -/* Tx / Host Commands */ -int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm, - struct iwl_host_cmd *cmd); -int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, - u32 flags, u16 len, const void *data); -int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, - struct iwl_host_cmd *cmd, - u32 *status); -int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, - u16 len, const void *data, - u32 *status); -int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_sta *sta); -int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); -#ifdef CONFIG_IWLWIFI_DEBUG -const char *iwl_mvm_get_tx_fail_reason(u32 status); -#else -static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } -#endif -int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); -void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); - -/* Statistics */ -int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); - -/* NVM */ -int iwl_nvm_init(struct iwl_mvm *mvm); - -int iwl_mvm_up(struct iwl_mvm *mvm); -int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); - -int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm); - -/* - * FW notifications / CMD responses handlers - * Convention: iwl_mvm_rx_ - */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); - -/* MVM PHY */ -int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, - u8 chains_static, u8 chains_dynamic); -int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, - u8 chains_static, u8 chains_dynamic); -void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, - struct iwl_mvm_phy_ctxt *ctxt); - -/* MAC (virtual interface) programming */ -int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); -int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); - -/* Bindings */ -int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); - -/* Quota management */ -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif); - -/* Scanning */ -int iwl_mvm_scan_request(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req); -int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); - -/* MVM debugfs */ -#ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); -int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct dentry *dbgfs_dir); -void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_powertable_cmd *cmd); -#else -static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, - struct dentry *dbgfs_dir) -{ - return 0; -} -#endif /* CONFIG_IWLWIFI_DEBUGFS */ - -/* rate scaling */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, - u8 flags, bool init); - -/* power managment */ -int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); - -int iwl_mvm_leds_init(struct iwl_mvm *mvm); -void iwl_mvm_leds_exit(struct iwl_mvm *mvm); - -/* D3 (WoWLAN, NetDetect) */ -int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); -int iwl_mvm_resume(struct ieee80211_hw *hw); -void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled); -void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_gtk_rekey_data *data); -void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct inet6_dev *idev); -void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int idx); - -#endif /* __IWL_MVM_H__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/nvm.c b/trunk/drivers/net/wireless/iwlwifi/mvm/nvm.c deleted file mode 100644 index 20016bcbdeab..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ /dev/null @@ -1,311 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 "iwl-trans.h" -#include "mvm.h" -#include "iwl-eeprom-parse.h" -#include "iwl-eeprom-read.h" -#include "iwl-nvm-parse.h" - -/* list of NVM sections we are allowed/need to read */ -static const int nvm_to_read[] = { - NVM_SECTION_TYPE_HW, - NVM_SECTION_TYPE_SW, - NVM_SECTION_TYPE_CALIBRATION, - NVM_SECTION_TYPE_PRODUCTION, -}; - -/* used to simplify the shared operations on NCM_ACCESS_CMD versions */ -union iwl_nvm_access_cmd { - struct iwl_nvm_access_cmd_ver1 ver1; - struct iwl_nvm_access_cmd_ver2 ver2; -}; -union iwl_nvm_access_resp { - struct iwl_nvm_access_resp_ver1 ver1; - struct iwl_nvm_access_resp_ver2 ver2; -}; - -static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd, - u16 offset, u16 length) -{ - cmd->offset = cpu_to_le16(offset); - cmd->length = cpu_to_le16(length); - cmd->cache_refresh = 1; -} - -static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd, - u16 offset, u16 length, u16 section) -{ - cmd->offset = cpu_to_le16(offset); - cmd->length = cpu_to_le16(length); - cmd->type = cpu_to_le16(section); -} - -static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, - u16 offset, u16 length, u8 *data) -{ - union iwl_nvm_access_cmd nvm_access_cmd; - union iwl_nvm_access_resp *nvm_resp; - struct iwl_rx_packet *pkt; - struct iwl_host_cmd cmd = { - .id = NVM_ACCESS_CMD, - .flags = CMD_SYNC | CMD_WANT_SKB, - .data = { &nvm_access_cmd, }, - }; - int ret, bytes_read, offset_read; - u8 *resp_data; - - memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd)); - - /* TODO: not sure family should be the decider, maybe FW version? */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2), - offset, length, section); - cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2); - } else { - iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1), - offset, length); - cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1); - } - - ret = iwl_mvm_send_cmd(mvm, &cmd); - if (ret) - return ret; - - pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - goto exit; - } - - /* Extract NVM response */ - nvm_resp = (void *)pkt->data; - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - ret = le16_to_cpu(nvm_resp->ver2.status); - bytes_read = le16_to_cpu(nvm_resp->ver2.length); - offset_read = le16_to_cpu(nvm_resp->ver2.offset); - resp_data = nvm_resp->ver2.data; - } else { - ret = le16_to_cpu(nvm_resp->ver1.length) <= 0; - bytes_read = le16_to_cpu(nvm_resp->ver1.length); - offset_read = le16_to_cpu(nvm_resp->ver1.offset); - resp_data = nvm_resp->ver1.data; - } - if (ret) { - IWL_ERR(mvm, - "NVM access command failed with status %d (device: %s)\n", - ret, mvm->cfg->name); - ret = -EINVAL; - goto exit; - } - - if (offset_read != offset) { - IWL_ERR(mvm, "NVM ACCESS response with invalid offset %d\n", - offset_read); - ret = -EINVAL; - goto exit; - } - - /* Write data to NVM */ - memcpy(data + offset, resp_data, bytes_read); - ret = bytes_read; - -exit: - iwl_free_resp(&cmd); - return ret; -} - -/* - * Reads an NVM section completely. - * NICs prior to 7000 family doesn't have a real NVM, but just read - * section 0 which is the EEPROM. Because the EEPROM reading is unlimited - * by uCode, we need to manually check in this case that we don't - * overflow and try to read more than the EEPROM size. - * For 7000 family NICs, we supply the maximal size we can read, and - * the uCode fills the response with as much data as we can, - * without overflowing, so no check is needed. - */ -static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, - u8 *data) -{ - u16 length, offset = 0; - int ret; - bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000; - - length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024)) - - sizeof(union iwl_nvm_access_cmd) - - sizeof(struct iwl_rx_packet); - /* - * if length is greater than EEPROM size, truncate it because uCode - * doesn't check it by itself, and exit the loop when reached. - */ - if (old_eeprom && length > mvm->cfg->base_params->eeprom_size) - length = mvm->cfg->base_params->eeprom_size; - ret = length; - - /* Read the NVM until exhausted (reading less than requested) */ - while (ret == length) { - ret = iwl_nvm_read_chunk(mvm, section, offset, length, data); - if (ret < 0) { - IWL_ERR(mvm, - "Cannot read NVM from section %d offset %d, length %d\n", - section, offset, length); - return ret; - } - offset += ret; - if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size) - break; - } - - IWL_INFO(mvm, "NVM section %d read completed\n", section); - return offset; -} - -static struct iwl_nvm_data * -iwl_parse_nvm_sections(struct iwl_mvm *mvm) -{ - struct iwl_nvm_section *sections = mvm->nvm_sections; - const __le16 *hw, *sw, *calib; - - /* Checking for required sections */ - if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || - !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) { - IWL_ERR(mvm, "Can't parse empty NVM sections\n"); - return NULL; - } - - if (WARN_ON(!mvm->cfg)) - return NULL; - - hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data; - sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; - calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; - return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib); -} - -int iwl_nvm_init(struct iwl_mvm *mvm) -{ - int ret, i, section; - u8 *nvm_buffer, *temp; - - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - /* TODO: find correct NVM max size for a section */ - nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, - GFP_KERNEL); - if (!nvm_buffer) - return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { - section = nvm_to_read[i]; - /* we override the constness for initial read */ - ret = iwl_nvm_read_section(mvm, section, nvm_buffer); - if (ret < 0) - break; - temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); - if (!temp) { - ret = -ENOMEM; - break; - } - mvm->nvm_sections[section].data = temp; - mvm->nvm_sections[section].length = ret; - } - kfree(nvm_buffer); - if (ret < 0) - return ret; - } else { - /* allocate eeprom */ - mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size; - IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n", - mvm->eeprom_blob_size); - mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL); - if (!mvm->eeprom_blob) - return -ENOMEM; - - ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob); - if (ret != mvm->eeprom_blob_size) { - IWL_ERR(mvm, "Read partial NVM %d/%zd\n", - ret, mvm->eeprom_blob_size); - kfree(mvm->eeprom_blob); - mvm->eeprom_blob = NULL; - return -EINVAL; - } - } - - ret = 0; - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) - mvm->nvm_data = iwl_parse_nvm_sections(mvm); - else - mvm->nvm_data = - iwl_parse_eeprom_data(mvm->trans->dev, - mvm->cfg, - mvm->eeprom_blob, - mvm->eeprom_blob_size); - - if (!mvm->nvm_data) { - kfree(mvm->eeprom_blob); - mvm->eeprom_blob = NULL; - ret = -ENOMEM; - } - - return ret; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/ops.c b/trunk/drivers/net/wireless/iwlwifi/mvm/ops.c deleted file mode 100644 index 983dca3f888a..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/ops.c +++ /dev/null @@ -1,679 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include - -#include "iwl-notif-wait.h" -#include "iwl-trans.h" -#include "iwl-op-mode.h" -#include "iwl-fw.h" -#include "iwl-debug.h" -#include "iwl-drv.h" -#include "iwl-modparams.h" -#include "mvm.h" -#include "iwl-phy-db.h" -#include "iwl-eeprom-parse.h" -#include "iwl-csr.h" -#include "iwl-io.h" -#include "iwl-prph.h" -#include "rs.h" -#include "fw-api-scan.h" -#include "time-event.h" - -/* - * module name, copyright, version, etc. - */ -#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" - -#define DRV_VERSION IWLWIFI_VERSION - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); -MODULE_LICENSE("GPL"); - -static const struct iwl_op_mode_ops iwl_mvm_ops; - -struct iwl_mvm_mod_params iwlmvm_mod_params = { - .power_scheme = IWL_POWER_SCHEME_BPS, - /* rest of fields are 0 by default */ -}; - -module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, S_IRUGO); -MODULE_PARM_DESC(init_dbg, - "set to true to debug an ASSERT in INIT fw (default: false"); -module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); -MODULE_PARM_DESC(power_scheme, - "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); - -/* - * module init and exit functions - */ -static int __init iwl_mvm_init(void) -{ - int ret; - - ret = iwl_mvm_rate_control_register(); - if (ret) { - pr_err("Unable to register rate control algorithm: %d\n", ret); - return ret; - } - - ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops); - - if (ret) { - pr_err("Unable to register MVM op_mode: %d\n", ret); - iwl_mvm_rate_control_unregister(); - } - - return ret; -} -module_init(iwl_mvm_init); - -static void __exit iwl_mvm_exit(void) -{ - iwl_opmode_deregister("iwlmvm"); - iwl_mvm_rate_control_unregister(); -} -module_exit(iwl_mvm_exit); - -static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; - u32 reg_val = 0; - - /* - * We can't upload the correct value to the INIT image - * as we don't have nvm_data by that time. - * - * TODO: Figure out what we should do here - */ - if (mvm->nvm_data) { - radio_cfg_type = mvm->nvm_data->radio_cfg_type; - radio_cfg_step = mvm->nvm_data->radio_cfg_step; - radio_cfg_dash = mvm->nvm_data->radio_cfg_dash; - } else { - radio_cfg_type = 0; - radio_cfg_step = 0; - radio_cfg_dash = 0; - } - - /* SKU control */ - reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; - reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; - - /* radio configuration */ - reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; - reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; - reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; - - WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & - ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); - - /* silicon bits */ - reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; - reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; - - iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | - CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | - CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | - CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | - CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | - CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, - reg_val); - - IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, - radio_cfg_step, radio_cfg_dash); - - /* - * W/A : NIC is stuck in a reset state after Early PCIe power off - * (PCIe power is lost before PERST# is asserted), causing ME FW - * to lose ownership and not being able to obtain it back. - */ - iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, - ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); -} - -struct iwl_rx_handlers { - u8 cmd_id; - bool async; - int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -}; - -#define RX_HANDLER(_cmd_id, _fn, _async) \ - { .cmd_id = _cmd_id , .fn = _fn , .async = _async } - -/* - * Handlers for fw notifications - * Convention: RX_HANDLER(CMD_NAME, iwl_mvm_rx_CMD_NAME - * This list should be in order of frequency for performance purposes. - * - * The handler can be SYNC - this means that it will be called in the Rx path - * which can't acquire mvm->mutex. If the handler needs to hold mvm->mutex (and - * only in this case!), it should be set as ASYNC. In that case, it will be - * called from a worker with mvm->mutex held. - */ -static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { - RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false), - RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), - RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), - RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), - RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), - - RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), - RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), - - RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), - RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), - - RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), -}; -#undef RX_HANDLER -#define CMD(x) [x] = #x - -static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { - CMD(MVM_ALIVE), - CMD(REPLY_ERROR), - CMD(INIT_COMPLETE_NOTIF), - CMD(PHY_CONTEXT_CMD), - CMD(MGMT_MCAST_KEY), - CMD(TX_CMD), - CMD(TXPATH_FLUSH), - CMD(MAC_CONTEXT_CMD), - CMD(TIME_EVENT_CMD), - CMD(TIME_EVENT_NOTIFICATION), - CMD(BINDING_CONTEXT_CMD), - CMD(TIME_QUOTA_CMD), - CMD(RADIO_VERSION_NOTIFICATION), - CMD(SCAN_REQUEST_CMD), - CMD(SCAN_ABORT_CMD), - CMD(SCAN_START_NOTIFICATION), - CMD(SCAN_RESULTS_NOTIFICATION), - CMD(SCAN_COMPLETE_NOTIFICATION), - CMD(NVM_ACCESS_CMD), - CMD(PHY_CONFIGURATION_CMD), - CMD(CALIB_RES_NOTIF_PHY_DB), - CMD(SET_CALIB_DEFAULT_CMD), - CMD(CALIBRATION_COMPLETE_NOTIFICATION), - CMD(ADD_STA), - CMD(REMOVE_STA), - CMD(LQ_CMD), - CMD(SCAN_OFFLOAD_CONFIG_CMD), - CMD(SCAN_OFFLOAD_REQUEST_CMD), - CMD(SCAN_OFFLOAD_ABORT_CMD), - CMD(SCAN_OFFLOAD_COMPLETE), - CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), - CMD(POWER_TABLE_CMD), - CMD(WEP_KEY), - CMD(REPLY_RX_PHY_CMD), - CMD(REPLY_RX_MPDU_CMD), - CMD(BEACON_TEMPLATE_CMD), - CMD(STATISTICS_NOTIFICATION), - CMD(TX_ANT_CONFIGURATION_CMD), - CMD(D3_CONFIG_CMD), - CMD(PROT_OFFLOAD_CONFIG_CMD), - CMD(OFFLOADS_QUERY_CMD), - CMD(REMOTE_WAKE_CONFIG_CMD), - CMD(WOWLAN_PATTERNS), - CMD(WOWLAN_CONFIGURATION), - CMD(WOWLAN_TSC_RSC_PARAM), - CMD(WOWLAN_TKIP_PARAM), - CMD(WOWLAN_KEK_KCK_MATERIAL), - CMD(WOWLAN_GET_STATUSES), - CMD(WOWLAN_TX_POWER_PER_DB), - CMD(NET_DETECT_CONFIG_CMD), - CMD(NET_DETECT_PROFILES_QUERY_CMD), - CMD(NET_DETECT_PROFILES_CMD), - CMD(NET_DETECT_HOTSPOTS_CMD), - CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), -}; -#undef CMD - -/* this forward declaration can avoid to export the function */ -static void iwl_mvm_async_handlers_wk(struct work_struct *wk); - -static struct iwl_op_mode * -iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, - const struct iwl_fw *fw, struct dentry *dbgfs_dir) -{ - struct ieee80211_hw *hw; - struct iwl_op_mode *op_mode; - struct iwl_mvm *mvm; - struct iwl_trans_config trans_cfg = {}; - static const u8 no_reclaim_cmds[] = { - TX_CMD, - }; - int err, scan_size; - - switch (cfg->device_family) { - case IWL_DEVICE_FAMILY_6030: - case IWL_DEVICE_FAMILY_6005: - case IWL_DEVICE_FAMILY_7000: - break; - default: - IWL_ERR(trans, "Trying to load mvm on an unsupported device\n"); - return NULL; - } - - /******************************** - * 1. Allocating and configuring HW data - ********************************/ - hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) + - sizeof(struct iwl_mvm), - &iwl_mvm_hw_ops); - if (!hw) - return NULL; - - op_mode = hw->priv; - op_mode->ops = &iwl_mvm_ops; - op_mode->trans = trans; - - mvm = IWL_OP_MODE_GET_MVM(op_mode); - mvm->dev = trans->dev; - mvm->trans = trans; - mvm->cfg = cfg; - mvm->fw = fw; - mvm->hw = hw; - - mutex_init(&mvm->mutex); - spin_lock_init(&mvm->async_handlers_lock); - INIT_LIST_HEAD(&mvm->time_event_list); - INIT_LIST_HEAD(&mvm->async_handlers_list); - spin_lock_init(&mvm->time_event_lock); - - INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); - INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); - INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); - - SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); - - /* - * Populate the state variables that the transport layer needs - * to know about. - */ - trans_cfg.op_mode = op_mode; - trans_cfg.no_reclaim_cmds = no_reclaim_cmds; - trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; - - /* TODO: this should really be a TLV */ - if (cfg->device_family == IWL_DEVICE_FAMILY_7000) - trans_cfg.bc_table_dword = true; - - if (!iwlwifi_mod_params.wd_disable) - trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout; - else - trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; - - trans_cfg.command_names = iwl_mvm_cmd_strings; - - trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; - trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO; - - snprintf(mvm->hw->wiphy->fw_version, - sizeof(mvm->hw->wiphy->fw_version), - "%s", fw->fw_version); - - /* Configure transport layer */ - iwl_trans_configure(mvm->trans, &trans_cfg); - - trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; - trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); - - /* set up notification wait support */ - iwl_notification_wait_init(&mvm->notif_wait); - - /* Init phy db */ - mvm->phy_db = iwl_phy_db_init(trans); - if (!mvm->phy_db) { - IWL_ERR(mvm, "Cannot init phy_db\n"); - goto out_free; - } - - IWL_INFO(mvm, "Detected %s, REV=0x%X\n", - mvm->cfg->name, mvm->trans->hw_rev); - - err = iwl_trans_start_hw(mvm->trans); - if (err) - goto out_free; - - mutex_lock(&mvm->mutex); - err = iwl_run_init_mvm_ucode(mvm, true); - mutex_unlock(&mvm->mutex); - if (err && !iwlmvm_mod_params.init_dbg) { - IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); - goto out_free; - } - - /* Stop the hw after the ALIVE and NVM has been read */ - if (!iwlmvm_mod_params.init_dbg) - iwl_trans_stop_hw(mvm->trans, false); - - scan_size = sizeof(struct iwl_scan_cmd) + - mvm->fw->ucode_capa.max_probe_length + - (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)); - mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); - if (!mvm->scan_cmd) - goto out_free; - - err = iwl_mvm_mac_setup_register(mvm); - if (err) - goto out_free; - - err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir); - if (err) - goto out_unregister; - - return op_mode; - - out_unregister: - ieee80211_unregister_hw(mvm->hw); - out_free: - iwl_phy_db_free(mvm->phy_db); - kfree(mvm->scan_cmd); - kfree(mvm->eeprom_blob); - iwl_trans_stop_hw(trans, true); - ieee80211_free_hw(mvm->hw); - return NULL; -} - -static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - int i; - - iwl_mvm_leds_exit(mvm); - - ieee80211_unregister_hw(mvm->hw); - - kfree(mvm->scan_cmd); - - iwl_trans_stop_hw(mvm->trans, true); - - iwl_phy_db_free(mvm->phy_db); - mvm->phy_db = NULL; - - kfree(mvm->eeprom_blob); - iwl_free_nvm_data(mvm->nvm_data); - for (i = 0; i < NVM_NUM_OF_SECTIONS; i++) - kfree(mvm->nvm_sections[i].data); - - ieee80211_free_hw(mvm->hw); -} - -struct iwl_async_handler_entry { - struct list_head list; - struct iwl_rx_cmd_buffer rxb; - int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -}; - -void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm) -{ - struct iwl_async_handler_entry *entry, *tmp; - - spin_lock_bh(&mvm->async_handlers_lock); - list_for_each_entry_safe(entry, tmp, &mvm->async_handlers_list, list) { - iwl_free_rxb(&entry->rxb); - list_del(&entry->list); - kfree(entry); - } - spin_unlock_bh(&mvm->async_handlers_lock); -} - -static void iwl_mvm_async_handlers_wk(struct work_struct *wk) -{ - struct iwl_mvm *mvm = - container_of(wk, struct iwl_mvm, async_handlers_wk); - struct iwl_async_handler_entry *entry, *tmp; - struct list_head local_list; - - INIT_LIST_HEAD(&local_list); - - /* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */ - mutex_lock(&mvm->mutex); - - /* - * Sync with Rx path with a lock. Remove all the entries from this list, - * add them to a local one (lock free), and then handle them. - */ - spin_lock_bh(&mvm->async_handlers_lock); - list_splice_init(&mvm->async_handlers_list, &local_list); - spin_unlock_bh(&mvm->async_handlers_lock); - - list_for_each_entry_safe(entry, tmp, &local_list, list) { - if (entry->fn(mvm, &entry->rxb, NULL)) - IWL_WARN(mvm, - "returned value from ASYNC handlers are ignored\n"); - iwl_free_rxb(&entry->rxb); - list_del(&entry->list); - kfree(entry); - } - mutex_unlock(&mvm->mutex); -} - -static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - u8 i; - - /* - * Do the notification wait before RX handlers so - * even if the RX handler consumes the RXB we have - * access to it in the notification wait entry. - */ - iwl_notification_wait_notify(&mvm->notif_wait, pkt); - - for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { - const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; - if (rx_h->cmd_id == pkt->hdr.cmd) { - struct iwl_async_handler_entry *entry; - if (!rx_h->async) - return rx_h->fn(mvm, rxb, cmd); - - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - /* we can't do much... */ - if (!entry) - return 0; - - entry->rxb._page = rxb_steal_page(rxb); - entry->rxb._offset = rxb->_offset; - entry->rxb._rx_page_order = rxb->_rx_page_order; - entry->fn = rx_h->fn; - spin_lock(&mvm->async_handlers_lock); - list_add_tail(&entry->list, &mvm->async_handlers_list); - spin_unlock(&mvm->async_handlers_lock); - schedule_work(&mvm->async_handlers_wk); - } - } - - return 0; -} - -static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - int mq = mvm->queue_to_mac80211[queue]; - - if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) - return; - - if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) { - IWL_DEBUG_TX_QUEUES(mvm, - "queue %d (mac80211 %d) already stopped\n", - queue, mq); - return; - } - - set_bit(mq, &mvm->transport_queue_stop); - ieee80211_stop_queue(mvm->hw, mq); -} - -static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - int mq = mvm->queue_to_mac80211[queue]; - - if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) - return; - - if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) { - IWL_DEBUG_TX_QUEUES(mvm, - "queue %d (mac80211 %d) already awake\n", - queue, mq); - return; - } - - clear_bit(mq, &mvm->transport_queue_stop); - - ieee80211_wake_queue(mvm->hw, mq); -} - -static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - - if (state) - set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); - else - clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); - - wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); -} - -static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - struct ieee80211_tx_info *info; - - info = IEEE80211_SKB_CB(skb); - iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); - ieee80211_free_txskb(mvm->hw, skb); -} - -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - - iwl_mvm_dump_nic_error_log(mvm); - - iwl_abort_notification_waits(&mvm->notif_wait); - - /* - * If we're restarting already, don't cycle restarts. - * If INIT fw asserted, it will likely fail again. - * If WoWLAN fw asserted, don't restart either, mac80211 - * can't recover this since we're already half suspended. - */ - if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n"); - } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && - iwlwifi_mod_params.restart_fw) { - /* - * This is a bit racy, but worst case we tell mac80211 about - * a stopped/aborted (sched) scan when that was already done - * which is not a problem. It is necessary to abort any scan - * here because mac80211 requires having the scan cleared - * before restarting. - * We'll reset the scan_status to NONE in restart cleanup in - * the next start() call from mac80211. - */ - switch (mvm->scan_status) { - case IWL_MVM_SCAN_NONE: - break; - case IWL_MVM_SCAN_OS: - ieee80211_scan_completed(mvm->hw, true); - break; - } - - ieee80211_restart_hw(mvm->hw); - } -} - -static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) -{ - WARN_ON(1); -} - -static const struct iwl_op_mode_ops iwl_mvm_ops = { - .start = iwl_op_mode_mvm_start, - .stop = iwl_op_mode_mvm_stop, - .rx = iwl_mvm_rx_dispatch, - .queue_full = iwl_mvm_stop_sw_queue, - .queue_not_full = iwl_mvm_wake_sw_queue, - .hw_rf_kill = iwl_mvm_set_hw_rfkill_state, - .free_skb = iwl_mvm_free_skb, - .nic_error = iwl_mvm_nic_error, - .cmd_queue_full = iwl_mvm_cmd_queue_full, - .nic_config = iwl_mvm_nic_config, -}; diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/trunk/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c deleted file mode 100644 index b428448f8ddf..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ /dev/null @@ -1,292 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include "fw-api.h" -#include "mvm.h" - -/* Maps the driver specific channel width definition to the the fw values */ -static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) -{ - switch (chandef->width) { - case NL80211_CHAN_WIDTH_20_NOHT: - case NL80211_CHAN_WIDTH_20: - return PHY_VHT_CHANNEL_MODE20; - case NL80211_CHAN_WIDTH_40: - return PHY_VHT_CHANNEL_MODE40; - case NL80211_CHAN_WIDTH_80: - return PHY_VHT_CHANNEL_MODE80; - case NL80211_CHAN_WIDTH_160: - return PHY_VHT_CHANNEL_MODE160; - default: - WARN(1, "Invalid channel width=%u", chandef->width); - return PHY_VHT_CHANNEL_MODE20; - } -} - -/* - * Maps the driver specific control channel position (relative to the center - * freq) definitions to the the fw values - */ -static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) -{ - switch (chandef->chan->center_freq - chandef->center_freq1) { - case -70: - return PHY_VHT_CTRL_POS_4_BELOW; - case -50: - return PHY_VHT_CTRL_POS_3_BELOW; - case -30: - return PHY_VHT_CTRL_POS_2_BELOW; - case -10: - return PHY_VHT_CTRL_POS_1_BELOW; - case 10: - return PHY_VHT_CTRL_POS_1_ABOVE; - case 30: - return PHY_VHT_CTRL_POS_2_ABOVE; - case 50: - return PHY_VHT_CTRL_POS_3_ABOVE; - case 70: - return PHY_VHT_CTRL_POS_4_ABOVE; - default: - WARN(1, "Invalid channel definition"); - case 0: - /* - * The FW is expected to check the control channel position only - * when in HT/VHT and the channel width is not 20MHz. Return - * this value as the default one. - */ - return PHY_VHT_CTRL_POS_1_BELOW; - } -} - -/* - * Construct the generic fields of the PHY context command - */ -static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, - struct iwl_phy_context_cmd *cmd, - u32 action, u32 apply_time) -{ - memset(cmd, 0, sizeof(struct iwl_phy_context_cmd)); - - cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(ctxt->id, - ctxt->color)); - cmd->action = cpu_to_le32(action); - cmd->apply_time = cpu_to_le32(apply_time); -} - -/* - * Add the phy configuration to the PHY context command - */ -static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, - struct iwl_phy_context_cmd *cmd, - struct cfg80211_chan_def *chandef, - u8 chains_static, u8 chains_dynamic) -{ - u8 valid_rx_chains, active_cnt, idle_cnt; - - /* Set the channel info data */ - cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ? - PHY_BAND_24 : PHY_BAND_5); - - cmd->ci.channel = chandef->chan->hw_value; - cmd->ci.width = iwl_mvm_get_channel_width(chandef); - cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); - - /* Set rx the chains */ - - /* TODO: - * Need to add on chain noise calibration limitations, and - * BT coex considerations. - */ - valid_rx_chains = mvm->nvm_data->valid_rx_ant; - idle_cnt = chains_static; - active_cnt = chains_dynamic; - - cmd->rxchain_info = cpu_to_le32(valid_rx_chains << - PHY_RX_CHAIN_VALID_POS); - cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); - cmd->rxchain_info |= cpu_to_le32(active_cnt << - PHY_RX_CHAIN_MIMO_CNT_POS); - - cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant); -} - -/* - * Send a command to apply the current phy configuration. The command is send - * only if something in the configuration changed: in case that this is the - * first time that the phy configuration is applied or in case that the phy - * configuration changed from the previous apply. - */ -static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, - struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, - u8 chains_static, u8 chains_dynamic, - u32 action, u32 apply_time) -{ - struct iwl_phy_context_cmd cmd; - int ret; - - /* Set the command header fields */ - iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action, apply_time); - - /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, - chains_static, chains_dynamic); - - ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, - sizeof(struct iwl_phy_context_cmd), - &cmd); - if (ret) - IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); - return ret; -} - - -struct phy_ctx_used_data { - unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)]; -}; - -static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx, - void *_data) -{ - struct phy_ctx_used_data *data = _data; - struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; - - __set_bit(phy_ctxt->id, data->used); -} - -/* - * Send a command to add a PHY context based on the current HW configuration. - */ -int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, - u8 chains_static, u8 chains_dynamic) -{ - struct phy_ctx_used_data data = { - .used = { }, - }; - - /* - * If this is a regular PHY context (not the ROC one) - * skip the ROC PHY context's ID. - */ - if (ctxt != &mvm->phy_ctxt_roc) - __set_bit(mvm->phy_ctxt_roc.id, data.used); - - lockdep_assert_held(&mvm->mutex); - ctxt->color++; - - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - ieee80211_iter_chan_contexts_atomic( - mvm->hw, iwl_mvm_phy_ctx_used_iter, &data); - - ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX); - if (WARN_ONCE(ctxt->id == NUM_PHY_CTX, - "Failed to init PHY context - no free ID!\n")) - return -EIO; - } - - ctxt->channel = chandef->chan; - return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, - chains_static, chains_dynamic, - FW_CTXT_ACTION_ADD, 0); -} - -/* - * Send a command to modify the PHY context based on the current HW - * configuration. Note that the function does not check that the configuration - * changed. - */ -int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, - u8 chains_static, u8 chains_dynamic) -{ - lockdep_assert_held(&mvm->mutex); - - ctxt->channel = chandef->chan; - return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, - chains_static, chains_dynamic, - FW_CTXT_ACTION_MODIFY, 0); -} - -/* - * Send a command to the FW to remove the given phy context. - * Once the command is sent, regardless of success or failure, the context is - * marked as invalid - */ -void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) -{ - struct iwl_phy_context_cmd cmd; - int ret; - - lockdep_assert_held(&mvm->mutex); - - iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0); - ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, - sizeof(struct iwl_phy_context_cmd), - &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n", - ctxt->id); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/power.c b/trunk/drivers/net/wireless/iwlwifi/mvm/power.c deleted file mode 100644 index 63628739cf4a..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/power.c +++ /dev/null @@ -1,207 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include -#include -#include - -#include - -#include "iwl-debug.h" -#include "mvm.h" -#include "iwl-modparams.h" -#include "fw-api-power.h" - -#define POWER_KEEP_ALIVE_PERIOD_SEC 25 - -static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_powertable_cmd *cmd) -{ - struct ieee80211_hw *hw = mvm->hw; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; - int dtimper, dtimper_msec; - int keep_alive; - bool radar_detect = false; - - cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)); - cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); - - if ((!vif->bss_conf.ps) || - (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)) - return; - - cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); - - dtimper = hw->conf.ps_dtim_period ?: 1; - - /* Check if radar detection is required on current channel */ - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - WARN_ON(!chanctx_conf); - if (chanctx_conf) { - chan = chanctx_conf->def.chan; - radar_detect = chan->flags & IEEE80211_CHAN_RADAR; - } - rcu_read_unlock(); - - /* Check skip over DTIM conditions */ - if (!radar_detect && (dtimper <= 10) && - (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) { - cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK); - cmd->num_skip_dtim = 2; - } - - /* Check that keep alive period is at least 3 * DTIM */ - dtimper_msec = dtimper * vif->bss_conf.beacon_int; - keep_alive = max_t(int, 3 * dtimper_msec, - MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); - keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); - - cmd->keep_alive_seconds = cpu_to_le16(keep_alive); - - if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { - /* TODO: Also for D3 (device sleep / WoWLAN) */ - cmd->rx_data_timeout = cpu_to_le32(10); - cmd->tx_data_timeout = cpu_to_le32(10); - } else { - cmd->rx_data_timeout = cpu_to_le32(50); - cmd->tx_data_timeout = cpu_to_le32(50); - } -} - -int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_powertable_cmd cmd = {}; - - if (!iwlwifi_mod_params.power_save) { - IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); - return 0; - } - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return 0; - - iwl_power_build_cmd(mvm, vif, &cmd); - - IWL_DEBUG_POWER(mvm, - "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", - cmd.id_and_color, iwlmvm_mod_params.power_scheme, - le16_to_cpu(cmd.flags)); - - if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { - IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", - le16_to_cpu(cmd.keep_alive_seconds)); - IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", - le32_to_cpu(cmd.rx_data_timeout)); - IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", - le32_to_cpu(cmd.tx_data_timeout)); - IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", - le32_to_cpu(cmd.rx_data_timeout_uapsd)); - IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", - le32_to_cpu(cmd.tx_data_timeout_uapsd)); - IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", - cmd.lprx_rssi_threshold); - IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim); - } - - return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, - sizeof(cmd), &cmd); -} - -int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_powertable_cmd cmd = {}; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (!iwlwifi_mod_params.power_save) { - IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); - return 0; - } - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return 0; - - cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)); - cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); - - IWL_DEBUG_POWER(mvm, - "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", - cmd.id_and_color, iwlmvm_mod_params.power_scheme, - le16_to_cpu(cmd.flags)); - - return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, - sizeof(cmd), &cmd); -} - -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_powertable_cmd *cmd) -{ - iwl_power_build_cmd(mvm, vif, cmd); -} -#endif /* CONFIG_IWLWIFI_DEBUGFS */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/quota.c b/trunk/drivers/net/wireless/iwlwifi/mvm/quota.c deleted file mode 100644 index 2d4611a563c5..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/quota.c +++ /dev/null @@ -1,178 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include "fw-api.h" -#include "mvm.h" - -struct iwl_mvm_quota_iterator_data { - int n_interfaces[MAX_BINDINGS]; - int colors[MAX_BINDINGS]; - struct ieee80211_vif *new_vif; -}; - -static void iwl_mvm_quota_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_quota_iterator_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u16 id; - - /* - * We'll account for the new interface (if any) below, - * skip it here in case we're not called from within - * the add_interface callback (otherwise it won't show - * up in iteration) - */ - if (vif == data->new_vif) - return; - - if (!mvmvif->phy_ctxt) - return; - - /* currently, PHY ID == binding ID */ - id = mvmvif->phy_ctxt->id; - - /* need at least one binding per PHY */ - BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS); - - if (WARN_ON_ONCE(id >= MAX_BINDINGS)) - return; - - if (data->colors[id] < 0) - data->colors[id] = mvmvif->phy_ctxt->color; - else - WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (vif->bss_conf.assoc) - data->n_interfaces[id]++; - break; - case NL80211_IFTYPE_AP: - if (mvmvif->ap_active) - data->n_interfaces[id]++; - break; - case NL80211_IFTYPE_MONITOR: - data->n_interfaces[id]++; - break; - case NL80211_IFTYPE_P2P_DEVICE: - break; - case NL80211_IFTYPE_ADHOC: - if (vif->bss_conf.ibss_joined) - data->n_interfaces[id]++; - break; - default: - WARN_ON_ONCE(1); - break; - } -} - -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) -{ - struct iwl_time_quota_cmd cmd; - int i, idx, ret; - struct iwl_mvm_quota_iterator_data data = { - .n_interfaces = {}, - .colors = { -1, -1, -1, -1 }, - .new_vif = newvif, - }; - - /* update all upon completion */ - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - return 0; - - BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1); - - lockdep_assert_held(&mvm->mutex); - - memset(&cmd, 0, sizeof(cmd)); - - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_quota_iterator, &data); - if (newvif) { - data.new_vif = NULL; - iwl_mvm_quota_iterator(&data, newvif->addr, newvif); - } - - for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { - if (data.n_interfaces[i] <= 0) - continue; - - cmd.quotas[idx].id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); - cmd.quotas[idx].quota = cpu_to_le32(100); - cmd.quotas[idx].max_duration = cpu_to_le32(1000); - idx++; - } - - for (i = idx; i < MAX_BINDINGS; i++) - cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); - - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send quota: %d\n", ret); - return ret; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/rs.c b/trunk/drivers/net/wireless/iwlwifi/mvm/rs.c deleted file mode 100644 index 60a4291ca221..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/rs.c +++ /dev/null @@ -1,3096 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2005 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include "rs.h" -#include "fw-api.h" -#include "sta.h" -#include "iwl-op-mode.h" -#include "mvm.h" - -#define RS_NAME "iwl-mvm-rs" - -#define NUM_TRY_BEFORE_ANT_TOGGLE 1 -#define IWL_NUMBER_TRY 1 -#define IWL_HT_NUMBER_TRY 3 - -#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ -#define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ -#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ - -/* max allowed rate miss before sync LQ cmd */ -#define IWL_MISSED_RATE_MAX 15 -/* max time to accum history 2 seconds */ -#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) - -static u8 rs_ht_to_legacy[] = { - IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, - IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, - IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, - IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX -}; - -static const u8 ant_toggle_lookup[] = { - /*ANT_NONE -> */ ANT_NONE, - /*ANT_A -> */ ANT_B, - /*ANT_B -> */ ANT_C, - /*ANT_AB -> */ ANT_BC, - /*ANT_C -> */ ANT_A, - /*ANT_AC -> */ ANT_AB, - /*ANT_BC -> */ ANT_AC, - /*ANT_ABC -> */ ANT_ABC, -}; - -#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ - [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ - IWL_RATE_SISO_##s##M_PLCP, \ - IWL_RATE_MIMO2_##s##M_PLCP,\ - IWL_RATE_MIMO3_##s##M_PLCP,\ - IWL_RATE_##r##M_IEEE, \ - IWL_RATE_##ip##M_INDEX, \ - IWL_RATE_##in##M_INDEX, \ - IWL_RATE_##rp##M_INDEX, \ - IWL_RATE_##rn##M_INDEX, \ - IWL_RATE_##pp##M_INDEX, \ - IWL_RATE_##np##M_INDEX } - -/* - * Parameter order: - * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate - * - * If there isn't a valid next or previous rate then INV is used which - * maps to IWL_RATE_INVALID - * - */ -static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { - IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ - IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ - IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ - IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ - IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ - IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ - IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ - IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ - IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ - IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ - IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ - IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ - IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ - /* FIXME:RS: ^^ should be INV (legacy) */ -}; - -static inline u8 rs_extract_rate(u32 rate_n_flags) -{ - /* also works for HT because bits 7:6 are zero there */ - return (u8)(rate_n_flags & RATE_LEGACY_RATE_MSK); -} - -static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) -{ - int idx = 0; - - /* HT rate format */ - if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = rs_extract_rate(rate_n_flags); - - if (idx >= IWL_RATE_MIMO3_6M_PLCP) - idx = idx - IWL_RATE_MIMO3_6M_PLCP; - else if (idx >= IWL_RATE_MIMO2_6M_PLCP) - idx = idx - IWL_RATE_MIMO2_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; - - /* legacy rate format, search for match in table */ - } else { - for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) - if (iwl_rates[idx].plcp == - rs_extract_rate(rate_n_flags)) - return idx; - } - - return -1; -} - -static void rs_rate_scale_perform(struct iwl_mvm *mvm, - struct sk_buff *skb, - struct ieee80211_sta *sta, - struct iwl_lq_sta *lq_sta); -static void rs_fill_link_cmd(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, u32 rate_n_flags); -static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); - - -#ifdef CONFIG_MAC80211_DEBUGFS -static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, - u32 *rate_n_flags, int index); -#else -static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, - u32 *rate_n_flags, int index) -{} -#endif - -/** - * The following tables contain the expected throughput metrics for all rates - * - * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits - * - * where invalid entries are zeros. - * - * CCK rates are only valid in legacy table and will only be used in G - * (2.4 GHz) band. - */ - -static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { - 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 -}; - -static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ - {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ - {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ - {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ -}; - -static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ - {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ - {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ - {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ -}; - -static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ - {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ - {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ - {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ -}; - -static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ - {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ - {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ - {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ -}; - -static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ - {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ - {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ - {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ -}; - -static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ - {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ - {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ - {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ -}; - -/* mbps, mcs */ -static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { - { "1", "BPSK DSSS"}, - { "2", "QPSK DSSS"}, - {"5.5", "BPSK CCK"}, - { "11", "QPSK CCK"}, - { "6", "BPSK 1/2"}, - { "9", "BPSK 1/2"}, - { "12", "QPSK 1/2"}, - { "18", "QPSK 3/4"}, - { "24", "16QAM 1/2"}, - { "36", "16QAM 3/4"}, - { "48", "64QAM 2/3"}, - { "54", "64QAM 3/4"}, - { "60", "64QAM 5/6"}, -}; - -#define MCS_INDEX_PER_STREAM (8) - -static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) -{ - window->data = 0; - window->success_counter = 0; - window->success_ratio = IWL_INVALID_VALUE; - window->counter = 0; - window->average_tpt = IWL_INVALID_VALUE; - window->stamp = 0; -} - -static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) -{ - return (ant_type & valid_antenna) == ant_type; -} - -/* - * 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 iwl_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 u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, - struct ieee80211_hdr *hdr) -{ - u32 curr_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - struct iwl_traffic_load *tl = NULL; - u8 tid; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } else { - return IWL_MAX_TID_COUNT; - } - - if (unlikely(tid >= IWL_MAX_TID_COUNT)) - return IWL_MAX_TID_COUNT; - - 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 IWL_MAX_TID_COUNT; - } - - 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; - - return tid; -} - -#ifdef CONFIG_MAC80211_DEBUGFS -/** - * Program the device to use fixed rate for frame transmit - * This is for debugging/testing only - * once the device start use fixed rate, we need to reload the module - * to being back the normal operation. - */ -static void rs_program_fix_rate(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta) -{ - lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ - lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - - IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n", - lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); - - if (lq_sta->dbg_fixed_rate) { - rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); - iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); - } -} -#endif - -/* - get the traffic load value for tid -*/ -static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) -{ - u32 curr_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - struct iwl_traffic_load *tl = NULL; - - if (tid >= IWL_MAX_TID_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 int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_data, u8 tid, - struct ieee80211_sta *sta) -{ - int ret = -EAGAIN; - u32 load; - - load = rs_tl_get_load(lq_data, tid); - - if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { - IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", - sta->addr, tid); - ret = ieee80211_start_tx_ba_session(sta, tid, 5000); - if (ret == -EAGAIN) { - /* - * driver and mac80211 is out of sync - * this might be cause by reloading firmware - * stop the tx ba session here - */ - IWL_ERR(mvm, "Fail start Tx agg on tid: %d\n", - tid); - ieee80211_stop_tx_ba_session(sta, tid); - } - } else { - IWL_DEBUG_HT(mvm, - "Aggregation not enabled for tid %d because load = %u\n", - tid, load); - } - return ret; -} - -static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, u8 tid, - struct iwl_lq_sta *lq_data, - struct ieee80211_sta *sta) -{ - if (tid < IWL_MAX_TID_COUNT) - rs_tl_turn_on_agg_for_tid(mvm, lq_data, tid, sta); - else - IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n", - tid, IWL_MAX_TID_COUNT); -} - -static inline int get_num_of_ant_from_rate(u32 rate_n_flags) -{ - return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) + - !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + - !!(rate_n_flags & RATE_MCS_ANT_C_MSK); -} - -/* - * Static function to get the expected throughput from an iwl_scale_tbl_info - * that wraps a NULL pointer check - */ -static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) -{ - if (tbl->expected_tpt) - return tbl->expected_tpt[rs_index]; - return 0; -} - -/** - * rs_collect_tx_data - Update the success/failure sliding window - * - * We keep a sliding window of the last 62 packets transmitted - * at this rate. window->data contains the bitmask of successful - * packets. - */ -static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, - int scale_index, int attempts, int successes) -{ - struct iwl_rate_scale_data *window = NULL; - static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); - s32 fail_count, tpt; - - if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) - return -EINVAL; - - /* Select window for current tx bit rate */ - window = &(tbl->win[scale_index]); - - /* Get expected throughput */ - tpt = get_expected_tpt(tbl, scale_index); - - /* - * Keep track of only the latest 62 tx frame attempts in this rate's - * history window; anything older isn't really relevant any more. - * If we have filled up the sliding window, drop the oldest attempt; - * if the oldest attempt (highest bit in bitmap) shows "success", - * subtract "1" from the success counter (this is the main reason - * we keep these bitmaps!). - */ - while (attempts > 0) { - if (window->counter >= IWL_RATE_MAX_WINDOW) { - /* remove earliest */ - window->counter = IWL_RATE_MAX_WINDOW - 1; - - if (window->data & mask) { - window->data &= ~mask; - window->success_counter--; - } - } - - /* Increment frames-attempted counter */ - window->counter++; - - /* Shift bitmap by one frame to throw away oldest history */ - window->data <<= 1; - - /* Mark the most recent #successes attempts as successful */ - if (successes > 0) { - window->success_counter++; - window->data |= 0x1; - successes--; - } - - attempts--; - } - - /* Calculate current success ratio, avoid divide-by-0! */ - if (window->counter > 0) - window->success_ratio = 128 * (100 * window->success_counter) - / window->counter; - else - window->success_ratio = IWL_INVALID_VALUE; - - fail_count = window->counter - window->success_counter; - - /* Calculate average throughput, if we have enough history. */ - if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || - (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) - window->average_tpt = (window->success_ratio * tpt + 64) / 128; - else - window->average_tpt = IWL_INVALID_VALUE; - - /* Tag this window as having been updated */ - window->stamp = jiffies; - - return 0; -} - -/* - * Fill uCode API rate_n_flags field, based on "search" or "active" table. - */ -/* FIXME:RS:remove this function and put the flags statically in the table */ -static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, - struct iwl_scale_tbl_info *tbl, - int index, u8 use_green) -{ - u32 rate_n_flags = 0; - - if (is_legacy(tbl->lq_type)) { - rate_n_flags = iwl_rates[index].plcp; - if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) - rate_n_flags |= RATE_MCS_CCK_MSK; - } else if (is_Ht(tbl->lq_type)) { - if (index > IWL_LAST_OFDM_RATE) { - IWL_ERR(mvm, "Invalid HT rate index %d\n", index); - index = IWL_LAST_OFDM_RATE; - } - rate_n_flags = RATE_MCS_HT_MSK; - - if (is_siso(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_siso; - else if (is_mimo2(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_mimo2; - else - rate_n_flags |= iwl_rates[index].plcp_mimo3; - } else { - IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); - } - - rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & - RATE_MCS_ANT_ABC_MSK); - - if (is_Ht(tbl->lq_type)) { - if (tbl->is_ht40) - rate_n_flags |= RATE_MCS_CHAN_WIDTH_40; - if (tbl->is_SGI) - rate_n_flags |= RATE_MCS_SGI_MSK; - - if (use_green) { - rate_n_flags |= RATE_HT_MCS_GF_MSK; - if (is_siso(tbl->lq_type) && tbl->is_SGI) { - rate_n_flags &= ~RATE_MCS_SGI_MSK; - IWL_ERR(mvm, "GF was set with SGI:SISO\n"); - } - } - } - return rate_n_flags; -} - -/* - * Interpret uCode API's rate_n_flags format, - * fill "search" or "active" tx mode table. - */ -static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, - enum ieee80211_band band, - struct iwl_scale_tbl_info *tbl, - int *rate_idx) -{ - u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); - u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); - u8 mcs; - - memset(tbl, 0, sizeof(struct iwl_scale_tbl_info)); - *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); - - if (*rate_idx == IWL_RATE_INVALID) { - *rate_idx = -1; - return -EINVAL; - } - tbl->is_SGI = 0; /* default legacy setup */ - tbl->is_ht40 = 0; - tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); - tbl->lq_type = LQ_NONE; - tbl->max_search = IWL_MAX_SEARCH; - - /* legacy rate format */ - if (!(rate_n_flags & RATE_MCS_HT_MSK)) { - if (num_of_ant == 1) { - if (band == IEEE80211_BAND_5GHZ) - tbl->lq_type = LQ_A; - else - tbl->lq_type = LQ_G; - } - /* HT rate format */ - } else { - if (rate_n_flags & RATE_MCS_SGI_MSK) - tbl->is_SGI = 1; - - if (rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */ - tbl->is_ht40 = 1; - - mcs = rs_extract_rate(rate_n_flags); - - /* SISO */ - if (mcs <= IWL_RATE_SISO_60M_PLCP) { - if (num_of_ant == 1) - tbl->lq_type = LQ_SISO; /*else NONE*/ - /* MIMO2 */ - } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { - if (num_of_ant == 2) - tbl->lq_type = LQ_MIMO2; - /* MIMO3 */ - } else { - if (num_of_ant == 3) { - tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; - tbl->lq_type = LQ_MIMO3; - } - } - } - return 0; -} - -/* switch to another antenna/antennas and return 1 */ -/* if no other valid antenna found, return 0 */ -static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, - struct iwl_scale_tbl_info *tbl) -{ - u8 new_ant_type; - - if (!tbl->ant_type || tbl->ant_type > ANT_ABC) - return 0; - - if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) - return 0; - - new_ant_type = ant_toggle_lookup[tbl->ant_type]; - - while ((new_ant_type != tbl->ant_type) && - !rs_is_valid_ant(valid_ant, new_ant_type)) - new_ant_type = ant_toggle_lookup[new_ant_type]; - - if (new_ant_type == tbl->ant_type) - return 0; - - tbl->ant_type = new_ant_type; - *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; - *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; - return 1; -} - -/** - * Green-field mode is valid if the station supports it and - * there are no non-GF stations present in the BSS. - */ -static bool rs_use_green(struct ieee80211_sta *sta) -{ - struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; - - bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode & - IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - - return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green; -} - -/** - * rs_get_supported_rates - get the available rates - * - * if management frame or broadcast frame only return - * basic available rates. - * - */ -static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, - struct ieee80211_hdr *hdr, - enum iwl_table_type rate_type) -{ - if (is_legacy(rate_type)) { - return lq_sta->active_legacy_rate; - } else { - if (is_siso(rate_type)) - return lq_sta->active_siso_rate; - else if (is_mimo2(rate_type)) - return lq_sta->active_mimo2_rate; - else - return lq_sta->active_mimo3_rate; - } -} - -static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, - int rate_type) -{ - u8 high = IWL_RATE_INVALID; - u8 low = IWL_RATE_INVALID; - - /* 802.11A or ht walks to the next literal adjacent rate in - * the rate table */ - if (is_a_band(rate_type) || !is_legacy(rate_type)) { - int i; - u32 mask; - - /* Find the previous rate that is in the rate mask */ - i = index - 1; - for (mask = (1 << i); i >= 0; i--, mask >>= 1) { - if (rate_mask & mask) { - low = i; - break; - } - } - - /* Find the next rate that is in the rate mask */ - i = index + 1; - for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { - if (rate_mask & mask) { - high = i; - break; - } - } - - return (high << 8) | low; - } - - low = index; - while (low != IWL_RATE_INVALID) { - low = iwl_rates[low].prev_rs; - if (low == IWL_RATE_INVALID) - break; - if (rate_mask & (1 << low)) - break; - IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low); - } - - high = index; - while (high != IWL_RATE_INVALID) { - high = iwl_rates[high].next_rs; - if (high == IWL_RATE_INVALID) - break; - if (rate_mask & (1 << high)) - break; - IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high); - } - - return (high << 8) | low; -} - -static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl, - u8 scale_index, u8 ht_possible) -{ - s32 low; - u16 rate_mask; - u16 high_low; - u8 switch_to_legacy = 0; - u8 is_green = lq_sta->is_green; - struct iwl_mvm *mvm = lq_sta->drv; - - /* check if we need to switch from HT to legacy rates. - * assumption is that mandatory rates (1Mbps or 6Mbps) - * are always supported (spec demand) */ - 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->band == IEEE80211_BAND_5GHZ) - tbl->lq_type = LQ_A; - else - tbl->lq_type = LQ_G; - - if (num_of_ant(tbl->ant_type) > 1) - tbl->ant_type = - first_antenna(mvm->nvm_data->valid_tx_ant); - - tbl->is_ht40 = 0; - tbl->is_SGI = 0; - tbl->max_search = IWL_MAX_SEARCH; - } - - rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); - - /* Mask with station rate restriction */ - if (is_legacy(tbl->lq_type)) { - /* supp_rates has no CCK bits in A mode */ - if (lq_sta->band == IEEE80211_BAND_5GHZ) - rate_mask = (u16)(rate_mask & - (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); - else - rate_mask = (u16)(rate_mask & lq_sta->supp_rates); - } - - /* If we switched from HT to legacy, check current rate */ - if (switch_to_legacy && (rate_mask & (1 << scale_index))) { - low = scale_index; - goto out; - } - - high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, - tbl->lq_type); - low = high_low & 0xff; - - if (low == IWL_RATE_INVALID) - low = scale_index; - -out: - return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green); -} - -/* - * Simple function to compare two rate scale table types - */ -static bool table_type_matches(struct iwl_scale_tbl_info *a, - struct iwl_scale_tbl_info *b) -{ - return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) && - (a->is_SGI == b->is_SGI); -} - -/* - * mac80211 sends us Tx status - */ -static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb) -{ - int legacy_success; - int retries; - int rs_index, mac_index, i; - struct iwl_lq_sta *lq_sta = priv_sta; - struct iwl_lq_cmd *table; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r; - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - enum mac80211_rate_control_flags mac_flags; - u32 tx_rate; - struct iwl_scale_tbl_info tbl_type; - struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; - - IWL_DEBUG_RATE_LIMIT(mvm, - "get frame ack response, update rate scale window\n"); - - /* Treat uninitialized rate scaling data same as non-existing. */ - if (!lq_sta) { - IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); - return; - } else if (!lq_sta->drv) { - IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); - return; - } - - if (!ieee80211_is_data(hdr->frame_control) || - info->flags & IEEE80211_TX_CTL_NO_ACK) - return; - - /* This packet was aggregated but doesn't carry status info */ - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && - !(info->flags & IEEE80211_TX_STAT_AMPDU)) - return; - - /* - * Ignore this Tx frame response if its initial rate doesn't match - * that of latest Link Quality command. There may be stragglers - * from a previous Link Quality command, but we're no longer interested - * in those; they're either from the "active" mode while we're trying - * 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). - */ - table = &lq_sta->lq; - tx_rate = le32_to_cpu(table->rs_table[0]); - rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index); - if (info->band == IEEE80211_BAND_5GHZ) - rs_index -= IWL_FIRST_OFDM_RATE; - mac_flags = info->status.rates[0].flags; - mac_index = info->status.rates[0].idx; - /* For HT packets, map MCS to PLCP */ - if (mac_flags & IEEE80211_TX_RC_MCS) { - /* Remove # of streams */ - mac_index &= RATE_HT_MCS_RATE_CODE_MSK; - if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) - mac_index++; - /* - * mac80211 HT index is always zero-indexed; we need to move - * HT OFDM rates after CCK rates in 2.4 GHz band - */ - if (info->band == IEEE80211_BAND_2GHZ) - mac_index += IWL_FIRST_OFDM_RATE; - } - /* Here we actually compare this rate to the latest LQ command */ - if ((mac_index < 0) || - (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || - (tbl_type.ant_type != info->status.antenna) || - (!!(tx_rate & RATE_MCS_HT_MSK) != - !!(mac_flags & IEEE80211_TX_RC_MCS)) || - (!!(tx_rate & RATE_HT_MCS_GF_MSK) != - !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || - (rs_index != mac_index)) { - IWL_DEBUG_RATE(mvm, - "initial rate %d does not match %d (0x%x)\n", - mac_index, rs_index, tx_rate); - /* - * Since rates mis-match, the last LQ command may have failed. - * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with - * ... driver. - */ - lq_sta->missed_rate_counter++; - if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { - lq_sta->missed_rate_counter = 0; - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); - } - /* Regardless, ignore this status info for outdated rate */ - return; - } else - /* Rate did match, so reset the missed_rate_counter */ - lq_sta->missed_rate_counter = 0; - - /* Figure out if rate scale algorithm is in active or search table */ - if (table_type_matches(&tbl_type, - &(lq_sta->lq_info[lq_sta->active_tbl]))) { - curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - } else if (table_type_matches( - &tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) { - curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - } else { - IWL_DEBUG_RATE(mvm, - "Neither active nor search matches tx rate\n"); - tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n", - tmp_tbl->lq_type, tmp_tbl->ant_type, - tmp_tbl->is_SGI); - tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); - IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n", - tmp_tbl->lq_type, tmp_tbl->ant_type, - tmp_tbl->is_SGI); - IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n", - tbl_type.lq_type, tbl_type.ant_type, - tbl_type.is_SGI); - /* - * no matching table found, let's by-pass the data collection - * and continue to perform rate scale to find the rate table - */ - rs_stay_in_table(lq_sta, true); - goto done; - } - - /* - * Updating the frame history depends on whether packets were - * aggregated. - * - * For aggregation, all packets were transmitted at the same rate, the - * first index into rate scale table. - */ - if (info->flags & IEEE80211_TX_STAT_AMPDU) { - tx_rate = le32_to_cpu(table->rs_table[0]); - rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, - &rs_index); - rs_collect_tx_data(curr_tbl, rs_index, - info->status.ampdu_len, - info->status.ampdu_ack_len); - - /* Update success/fail counts if not searching for new mode */ - if (lq_sta->stay_in_tbl) { - lq_sta->total_success += info->status.ampdu_ack_len; - lq_sta->total_failed += (info->status.ampdu_len - - info->status.ampdu_ack_len); - } - } else { - /* - * For legacy, update frame history with for each Tx retry. - */ - retries = info->status.rates[0].count - 1; - /* HW doesn't send more than 15 retries */ - retries = min(retries, 15); - - /* The last transmission may have been successful */ - legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); - /* Collect data for each rate used during failed TX attempts */ - for (i = 0; i <= retries; ++i) { - tx_rate = le32_to_cpu(table->rs_table[i]); - rs_get_tbl_info_from_mcs(tx_rate, info->band, - &tbl_type, &rs_index); - /* - * Only collect stats if retried rate is in the same RS - * table as active/search. - */ - if (table_type_matches(&tbl_type, curr_tbl)) - tmp_tbl = curr_tbl; - else if (table_type_matches(&tbl_type, other_tbl)) - tmp_tbl = other_tbl; - else - continue; - rs_collect_tx_data(tmp_tbl, rs_index, 1, - i < retries ? 0 : legacy_success); - } - - /* Update success/fail counts if not searching for new mode */ - if (lq_sta->stay_in_tbl) { - lq_sta->total_success += legacy_success; - lq_sta->total_failed += retries + (1 - legacy_success); - } - } - /* The last TX rate is cached in lq_sta; it's set in if/else above */ - lq_sta->last_rate_n_flags = tx_rate; -done: - /* See if there's a better rate or modulation mode to try. */ - if (sta && sta->supp_rates[sband->band]) - rs_rate_scale_perform(mvm, skb, sta, lq_sta); -} - -/* - * Begin a period of staying with a selected modulation mode. - * Set "stay_in_tbl" flag to prevent any mode switches. - * Set frame tx success limits according to legacy vs. high-throughput, - * and reset overall (spanning all rates) tx success history statistics. - * These control how long we stay using same modulation mode before - * searching for a new mode. - */ -static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, - struct iwl_lq_sta *lq_sta) -{ - IWL_DEBUG_RATE(mvm, "we are staying in the same table\n"); - lq_sta->stay_in_tbl = 1; /* only place this gets set */ - if (is_legacy) { - lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT; - } else { - lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; - } - lq_sta->table_count = 0; - lq_sta->total_failed = 0; - lq_sta->total_success = 0; - lq_sta->flush_timer = jiffies; - lq_sta->action_counter = 0; -} - -/* - * Find correct throughput table for given mode of modulation - */ -static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl) -{ - /* Used to choose among HT tables */ - s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; - - /* Check for invalid LQ type */ - if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { - tbl->expected_tpt = expected_tpt_legacy; - return; - } - - /* Legacy rates have only one table */ - if (is_legacy(tbl->lq_type)) { - tbl->expected_tpt = expected_tpt_legacy; - return; - } - - /* Choose among many HT tables depending on number of streams - * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation - * status */ - if (is_siso(tbl->lq_type) && !tbl->is_ht40) - ht_tbl_pointer = expected_tpt_siso20MHz; - else if (is_siso(tbl->lq_type)) - ht_tbl_pointer = expected_tpt_siso40MHz; - else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40) - ht_tbl_pointer = expected_tpt_mimo2_20MHz; - else if (is_mimo2(tbl->lq_type)) - ht_tbl_pointer = expected_tpt_mimo2_40MHz; - else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40) - ht_tbl_pointer = expected_tpt_mimo3_20MHz; - else /* if (is_mimo3(tbl->lq_type)) <-- must be true */ - ht_tbl_pointer = expected_tpt_mimo3_40MHz; - - if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ - tbl->expected_tpt = ht_tbl_pointer[0]; - else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */ - tbl->expected_tpt = ht_tbl_pointer[1]; - else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */ - tbl->expected_tpt = ht_tbl_pointer[2]; - else /* AGG+SGI */ - tbl->expected_tpt = ht_tbl_pointer[3]; -} - -/* - * Find starting rate for new "search" high-throughput mode of modulation. - * Goal is to find lowest expected rate (under perfect conditions) that is - * above the current measured throughput of "active" mode, to give new mode - * a fair chance to prove itself without too many challenges. - * - * This gets called when transitioning to more aggressive modulation - * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive - * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need - * 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 iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl, /* "search" */ - u16 rate_mask, s8 index) -{ - /* "active" values */ - struct iwl_scale_tbl_info *active_tbl = - &(lq_sta->lq_info[lq_sta->active_tbl]); - s32 active_sr = active_tbl->win[index].success_ratio; - s32 active_tpt = active_tbl->expected_tpt[index]; - - /* expected "search" throughput */ - s32 *tpt_tbl = tbl->expected_tpt; - - s32 new_rate, high, low, start_hi; - u16 high_low; - s8 rate = index; - - new_rate = high = low = start_hi = IWL_RATE_INVALID; - - while (1) { - high_low = rs_get_adjacent_rate(mvm, rate, rate_mask, - tbl->lq_type); - - low = high_low & 0xff; - high = (high_low >> 8) & 0xff; - - /* - * Lower the "search" bit rate, to give new "search" mode - * approximately the same throughput as "active" if: - * - * 1) "Active" mode has been working modestly well (but not - * great), and expected "search" throughput (under perfect - * conditions) at candidate rate is above the actual - * measured "active" throughput (but less than expected - * "active" throughput under perfect conditions). - * OR - * 2) "Active" mode has been working perfectly or very well - * and expected "search" throughput (under perfect - * conditions) at candidate rate is above expected - * "active" throughput (under perfect conditions). - */ - if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && - ((active_sr > IWL_RATE_DECREASE_TH) && - (active_sr <= IWL_RATE_HIGH_TH) && - (tpt_tbl[rate] <= active_tpt))) || - ((active_sr >= IWL_RATE_SCALE_SWITCH) && - (tpt_tbl[rate] > active_tpt))) { - /* (2nd or later pass) - * If we've already tried to raise the rate, and are - * now trying to lower it, use the higher rate. */ - if (start_hi != IWL_RATE_INVALID) { - new_rate = start_hi; - break; - } - - new_rate = rate; - - /* Loop again with lower rate */ - if (low != IWL_RATE_INVALID) - rate = low; - - /* Lower rate not available, use the original */ - else - break; - - /* Else try to raise the "search" rate to match "active" */ - } else { - /* (2nd or later pass) - * If we've already tried to lower the rate, and are - * now trying to raise it, use the lower rate. */ - if (new_rate != IWL_RATE_INVALID) - break; - - /* Loop again with higher rate */ - else if (high != IWL_RATE_INVALID) { - start_hi = high; - rate = high; - - /* Higher rate not available, use the original */ - } else { - new_rate = rate; - break; - } - } - } - - return new_rate; -} - -static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm, - struct ieee80211_sta_ht_cap *ht_cap) -{ - /* - * Remainder of this function checks ht_cap, but if it's - * NULL then we can do HT40 (special case for RXON) - */ - if (!ht_cap) - return true; - - if (!ht_cap->ht_supported) - return false; - - if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) - return false; - - return true; -} - -/* - * Set up search table for MIMO2 - */ -static int rs_switch_to_mimo2(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - struct iwl_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - s32 rate; - s8 is_green = lq_sta->is_green; - - if (!sta->ht_cap.ht_supported) - return -1; - - if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) - == WLAN_HT_CAP_SM_PS_STATIC) - return -1; - - /* Need both Tx chains/antennas to support MIMO */ - if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2) - return -1; - - IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); - - tbl->lq_type = LQ_MIMO2; - tbl->action = 0; - tbl->max_search = IWL_MAX_SEARCH; - rate_mask = lq_sta->active_mimo2_rate; - - if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) - tbl->is_ht40 = 1; - else - tbl->is_ht40 = 0; - - rs_set_expected_tpt_table(lq_sta, tbl); - - rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n", - rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", - rate, rate_mask); - return -1; - } - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); - - IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate, is_green); - return 0; -} - -/* - * Set up search table for MIMO3 - */ -static int rs_switch_to_mimo3(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - struct iwl_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - s32 rate; - s8 is_green = lq_sta->is_green; - - if (!sta->ht_cap.ht_supported) - return -1; - - if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) - == WLAN_HT_CAP_SM_PS_STATIC) - return -1; - - /* Need both Tx chains/antennas to support MIMO */ - if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3) - return -1; - - IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); - - tbl->lq_type = LQ_MIMO3; - tbl->action = 0; - tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; - rate_mask = lq_sta->active_mimo3_rate; - - if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) - tbl->is_ht40 = 1; - else - tbl->is_ht40 = 0; - - rs_set_expected_tpt_table(lq_sta, tbl); - - rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n", - rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", - rate, rate_mask); - return -1; - } - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); - - IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate, is_green); - return 0; -} - -/* - * Set up search table for SISO - */ -static int rs_switch_to_siso(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - struct iwl_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - u8 is_green = lq_sta->is_green; - s32 rate; - - if (!sta->ht_cap.ht_supported) - return -1; - - IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); - - tbl->lq_type = LQ_SISO; - tbl->action = 0; - tbl->max_search = IWL_MAX_SEARCH; - rate_mask = lq_sta->active_siso_rate; - - if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) - tbl->is_ht40 = 1; - else - tbl->is_ht40 = 0; - - if (is_green) - tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ - - rs_set_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_RATE(mvm, - "can not switch with index %d rate mask %x\n", - rate, rate_mask); - return -1; - } - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); - IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate, is_green); - return 0; -} - -/* - * Try to switch to new modulation mode from legacy - */ -static int rs_move_legacy_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, - int index) -{ - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl_rate_scale_data *window = &(tbl->win[index]); - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; - u8 tx_chains_num = num_of_ant(valid_tx_ant); - int ret; - u8 update_search_tbl_counter = 0; - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_LEGACY_SWITCH_ANTENNA1: - case IWL_LEGACY_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n"); - - if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && - tx_chains_num <= 1) || - (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && - tx_chains_num <= 2)) - break; - - /* Don't change antenna if success has been great */ - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - /* Set up search table to try other antenna */ - memcpy(search_tbl, tbl, sz); - - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - search_tbl)) { - update_search_tbl_counter = 1; - rs_set_expected_tpt_table(lq_sta, search_tbl); - goto out; - } - break; - case IWL_LEGACY_SWITCH_SISO: - IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n"); - - /* Set up search table to try SISO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - ret = rs_switch_to_siso(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) { - lq_sta->action_counter = 0; - goto out; - } - - break; - case IWL_LEGACY_SWITCH_MIMO2_AB: - case IWL_LEGACY_SWITCH_MIMO2_AC: - case IWL_LEGACY_SWITCH_MIMO2_BC: - IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); - - /* Set up search table to try MIMO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - - if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) - search_tbl->ant_type = ANT_AB; - else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) - search_tbl->ant_type = ANT_AC; - else - search_tbl->ant_type = ANT_BC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo2(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) { - lq_sta->action_counter = 0; - goto out; - } - break; - - case IWL_LEGACY_SWITCH_MIMO3_ABC: - IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n"); - - /* Set up search table to try MIMO3 */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - - search_tbl->ant_type = ANT_ABC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo3(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) { - lq_sta->action_counter = 0; - goto out; - } - break; - } - tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; - - if (tbl->action == start_action) - break; - } - search_tbl->lq_type = LQ_NONE; - return 0; - -out: - lq_sta->search_better_tbl = 1; - tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - return 0; -} - -/* - * Try to switch to new modulation mode from SISO - */ -static int rs_move_siso_to_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, int index) -{ - u8 is_green = lq_sta->is_green; - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl_rate_scale_data *window = &(tbl->win[index]); - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; - u8 tx_chains_num = num_of_ant(valid_tx_ant); - u8 update_search_tbl_counter = 0; - int ret; - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_SISO_SWITCH_ANTENNA1: - case IWL_SISO_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n"); - if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 && - tx_chains_num <= 1) || - (tbl->action == IWL_SISO_SWITCH_ANTENNA2 && - tx_chains_num <= 2)) - break; - - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - memcpy(search_tbl, tbl, sz); - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - search_tbl)) { - update_search_tbl_counter = 1; - goto out; - } - break; - case IWL_SISO_SWITCH_MIMO2_AB: - case IWL_SISO_SWITCH_MIMO2_AC: - case IWL_SISO_SWITCH_MIMO2_BC: - IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - - if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) - search_tbl->ant_type = ANT_AB; - else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) - search_tbl->ant_type = ANT_AC; - else - search_tbl->ant_type = ANT_BC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo2(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - break; - case IWL_SISO_SWITCH_GI: - if (!tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_20)) - break; - if (tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_40)) - break; - - IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); - - memcpy(search_tbl, tbl, sz); - if (is_green) { - if (!tbl->is_SGI) - break; - else - IWL_ERR(mvm, - "SGI was set in GF+SISO\n"); - } - search_tbl->is_SGI = !tbl->is_SGI; - rs_set_expected_tpt_table(lq_sta, search_tbl); - if (tbl->is_SGI) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - search_tbl->current_rate = - rate_n_flags_from_tbl(mvm, search_tbl, - index, is_green); - update_search_tbl_counter = 1; - goto out; - case IWL_SISO_SWITCH_MIMO3_ABC: - IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n"); - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_ABC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo3(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - break; - } - tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) - tbl->action = IWL_SISO_SWITCH_ANTENNA1; - - if (tbl->action == start_action) - break; - } - search_tbl->lq_type = LQ_NONE; - return 0; - - out: - lq_sta->search_better_tbl = 1; - tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) - tbl->action = IWL_SISO_SWITCH_ANTENNA1; - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - - return 0; -} - -/* - * Try to switch to new modulation mode from MIMO2 - */ -static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, int index) -{ - s8 is_green = lq_sta->is_green; - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl_rate_scale_data *window = &(tbl->win[index]); - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; - u8 tx_chains_num = num_of_ant(valid_tx_ant); - u8 update_search_tbl_counter = 0; - int ret; - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_MIMO2_SWITCH_ANTENNA1: - case IWL_MIMO2_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle Antennas\n"); - - if (tx_chains_num <= 2) - break; - - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - memcpy(search_tbl, tbl, sz); - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - search_tbl)) { - update_search_tbl_counter = 1; - goto out; - } - break; - case IWL_MIMO2_SWITCH_SISO_A: - case IWL_MIMO2_SWITCH_SISO_B: - case IWL_MIMO2_SWITCH_SISO_C: - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); - - /* Set up new search table for SISO */ - memcpy(search_tbl, tbl, sz); - - if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) - search_tbl->ant_type = ANT_A; - else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) - search_tbl->ant_type = ANT_B; - else - search_tbl->ant_type = ANT_C; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_siso(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - - case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_20)) - break; - if (tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_40)) - break; - - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); - - /* Set up new search table for MIMO2 */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = !tbl->is_SGI; - rs_set_expected_tpt_table(lq_sta, search_tbl); - /* - * If active table already uses the fastest possible - * modulation (dual stream with short guard interval), - * and it's working well, there's no need to look - * for a better type of modulation! - */ - if (tbl->is_SGI) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - search_tbl->current_rate = - rate_n_flags_from_tbl(mvm, search_tbl, - index, is_green); - update_search_tbl_counter = 1; - goto out; - - case IWL_MIMO2_SWITCH_MIMO3_ABC: - IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n"); - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_ABC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo3(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - } - tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) - tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; - - if (tbl->action == start_action) - break; - } - search_tbl->lq_type = LQ_NONE; - return 0; - out: - lq_sta->search_better_tbl = 1; - tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) - tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - - return 0; -} - -/* - * Try to switch to new modulation mode from MIMO3 - */ -static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct ieee80211_sta *sta, int index) -{ - s8 is_green = lq_sta->is_green; - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl_rate_scale_data *window = &(tbl->win[index]); - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action; - u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; - u8 tx_chains_num = num_of_ant(valid_tx_ant); - int ret; - u8 update_search_tbl_counter = 0; - - start_action = tbl->action; - while (1) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_MIMO3_SWITCH_ANTENNA1: - case IWL_MIMO3_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n"); - - if (tx_chains_num <= 3) - break; - - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - memcpy(search_tbl, tbl, sz); - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, - search_tbl)) - goto out; - break; - case IWL_MIMO3_SWITCH_SISO_A: - case IWL_MIMO3_SWITCH_SISO_B: - case IWL_MIMO3_SWITCH_SISO_C: - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n"); - - /* Set up new search table for SISO */ - memcpy(search_tbl, tbl, sz); - - if (tbl->action == IWL_MIMO3_SWITCH_SISO_A) - search_tbl->ant_type = ANT_A; - else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B) - search_tbl->ant_type = ANT_B; - else - search_tbl->ant_type = ANT_C; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_siso(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - - case IWL_MIMO3_SWITCH_MIMO2_AB: - case IWL_MIMO3_SWITCH_MIMO2_AC: - case IWL_MIMO3_SWITCH_MIMO2_BC: - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n"); - - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB) - search_tbl->ant_type = ANT_AB; - else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC) - search_tbl->ant_type = ANT_AC; - else - search_tbl->ant_type = ANT_BC; - - if (!rs_is_valid_ant(valid_tx_ant, - search_tbl->ant_type)) - break; - - ret = rs_switch_to_mimo2(mvm, lq_sta, sta, - search_tbl, index); - if (!ret) - goto out; - - break; - - case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_20)) - break; - if (tbl->is_ht40 && !(ht_cap->cap & - IEEE80211_HT_CAP_SGI_40)) - break; - - IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n"); - - /* Set up new search table for MIMO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = !tbl->is_SGI; - rs_set_expected_tpt_table(lq_sta, search_tbl); - /* - * If active table already uses the fastest possible - * modulation (dual stream with short guard interval), - * and it's working well, there's no need to look - * for a better type of modulation! - */ - if (tbl->is_SGI) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - search_tbl->current_rate = - rate_n_flags_from_tbl(mvm, search_tbl, - index, is_green); - update_search_tbl_counter = 1; - goto out; - } - tbl->action++; - if (tbl->action > IWL_MIMO3_SWITCH_GI) - tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; - - if (tbl->action == start_action) - break; - } - search_tbl->lq_type = LQ_NONE; - return 0; - out: - lq_sta->search_better_tbl = 1; - tbl->action++; - if (tbl->action > IWL_MIMO3_SWITCH_GI) - tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; - if (update_search_tbl_counter) - search_tbl->action = tbl->action; - - return 0; -} - -/* - * Check whether we should continue using same modulation mode, or - * begin search for a new mode, based on: - * 1) # tx successes or failures while using this mode - * 2) # times calling this function - * 3) elapsed time in this mode (not used, for now) - */ -static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) -{ - struct iwl_scale_tbl_info *tbl; - int i; - int active_tbl; - int flush_interval_passed = 0; - struct iwl_mvm *mvm; - - mvm = lq_sta->drv; - active_tbl = lq_sta->active_tbl; - - tbl = &(lq_sta->lq_info[active_tbl]); - - /* If we've been disallowing search, see if we should now allow it */ - if (lq_sta->stay_in_tbl) { - /* Elapsed time using current modulation mode */ - if (lq_sta->flush_timer) - flush_interval_passed = - time_after(jiffies, - (unsigned long)(lq_sta->flush_timer + - IWL_RATE_SCALE_FLUSH_INTVL)); - - /* - * Check if we should allow search for new modulation mode. - * If many frames have failed or succeeded, or we've used - * this same modulation for a long time, allow search, and - * reset history stats that keep track of whether we should - * allow a new search. Also (below) reset all bitmaps and - * stats in active history. - */ - if (force_search || - (lq_sta->total_failed > lq_sta->max_failure_limit) || - (lq_sta->total_success > lq_sta->max_success_limit) || - ((!lq_sta->search_better_tbl) && - (lq_sta->flush_timer) && (flush_interval_passed))) { - IWL_DEBUG_RATE(mvm, - "LQ: stay is expired %d %d %d\n", - lq_sta->total_failed, - lq_sta->total_success, - flush_interval_passed); - - /* Allow search for new mode */ - lq_sta->stay_in_tbl = 0; /* only place reset */ - lq_sta->total_failed = 0; - lq_sta->total_success = 0; - lq_sta->flush_timer = 0; - /* - * Else if we've used this modulation mode enough repetitions - * (regardless of elapsed time or success/failure), reset - * history bitmaps and rate-specific stats for all rates in - * active table. - */ - } else { - lq_sta->table_count++; - if (lq_sta->table_count >= - lq_sta->table_count_limit) { - lq_sta->table_count = 0; - - IWL_DEBUG_RATE(mvm, - "LQ: stay in table clear win\n"); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window( - &(tbl->win[i])); - } - } - - /* If transitioning to allow "search", reset all history - * bitmaps and stats in active table (this will become the new - * "search" table). */ - if (!lq_sta->stay_in_tbl) { - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(tbl->win[i])); - } - } -} - -/* - * setup rate table in uCode - */ -static void rs_update_rate_tbl(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, - struct iwl_scale_tbl_info *tbl, - int index, u8 is_green) -{ - u32 rate; - - /* Update uCode's rate table. */ - rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green); - rs_fill_link_cmd(mvm, lq_sta, rate); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); -} - -/* - * Do rate scaling and search for new modulation mode. - */ -static void rs_rate_scale_perform(struct iwl_mvm *mvm, - struct sk_buff *skb, - struct ieee80211_sta *sta, - struct iwl_lq_sta *lq_sta) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int low = IWL_RATE_INVALID; - int high = IWL_RATE_INVALID; - int index; - int i; - struct iwl_rate_scale_data *window = NULL; - int current_tpt = IWL_INVALID_VALUE; - int low_tpt = IWL_INVALID_VALUE; - int high_tpt = IWL_INVALID_VALUE; - u32 fail_count; - s8 scale_action = 0; - u16 rate_mask; - u8 update_lq = 0; - struct iwl_scale_tbl_info *tbl, *tbl1; - u16 rate_scale_index_msk = 0; - u8 is_green = 0; - u8 active_tbl = 0; - u8 done_search = 0; - u16 high_low; - s32 sr; - u8 tid = IWL_MAX_TID_COUNT; - struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; - struct iwl_mvm_tid_data *tid_data; - - IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n"); - - /* Send management frames and NO_ACK data using lowest rate. */ - /* TODO: this could probably be improved.. */ - if (!ieee80211_is_data(hdr->frame_control) || - info->flags & IEEE80211_TX_CTL_NO_ACK) - return; - - lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; - - tid = rs_tl_add_packet(lq_sta, hdr); - if ((tid != IWL_MAX_TID_COUNT) && - (lq_sta->tx_agg_tid_en & (1 << tid))) { - tid_data = &sta_priv->tid_data[tid]; - if (tid_data->state == IWL_AGG_OFF) - lq_sta->is_agg = 0; - else - lq_sta->is_agg = 1; - } else { - lq_sta->is_agg = 0; - } - - /* - * Select rate-scale / modulation-mode table to work with in - * the rest of this function: "search" if searching for better - * modulation mode, or "active" if doing rate scaling within a mode. - */ - if (!lq_sta->search_better_tbl) - active_tbl = lq_sta->active_tbl; - else - active_tbl = 1 - lq_sta->active_tbl; - - tbl = &(lq_sta->lq_info[active_tbl]); - if (is_legacy(tbl->lq_type)) - lq_sta->is_green = 0; - else - lq_sta->is_green = rs_use_green(sta); - is_green = lq_sta->is_green; - - /* current tx rate */ - index = lq_sta->last_txrate_idx; - - IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index, - tbl->lq_type); - - /* rates available for this association, and for modulation mode */ - rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); - - IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask); - - /* mask with station rate restriction */ - if (is_legacy(tbl->lq_type)) { - 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)); - else - rate_scale_index_msk = (u16) (rate_mask & - lq_sta->supp_rates); - - } else { - rate_scale_index_msk = rate_mask; - } - - if (!rate_scale_index_msk) - rate_scale_index_msk = rate_mask; - - if (!((1 << index) & rate_scale_index_msk)) { - IWL_ERR(mvm, "Current Rate is not valid\n"); - if (lq_sta->search_better_tbl) { - /* revert to active table if search table is not valid*/ - tbl->lq_type = LQ_NONE; - lq_sta->search_better_tbl = 0; - tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - /* get "active" rate info */ - index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green); - } - return; - } - - /* Get expected throughput table and history window for current rate */ - if (!tbl->expected_tpt) { - IWL_ERR(mvm, "tbl->expected_tpt is NULL\n"); - return; - } - - /* force user max rate if set by user */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < index)) { - index = lq_sta->max_rate_idx; - update_lq = 1; - window = &(tbl->win[index]); - goto lq_update; - } - - window = &(tbl->win[index]); - - /* - * If there is not enough history to calculate actual average - * throughput, keep analyzing results of more tx frames, without - * changing rate or mode (bypass most of the rest of this function). - * Set up new rate table in uCode only if old rate is not supported - * in current association (use new rate found above). - */ - fail_count = window->counter - window->success_counter; - if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { - IWL_DEBUG_RATE(mvm, - "LQ: still below TH. succ=%d total=%d for index %d\n", - window->success_counter, window->counter, index); - - /* Can't calculate this yet; not enough history */ - window->average_tpt = IWL_INVALID_VALUE; - - /* Should we stay with this modulation mode, - * or search for a new one? */ - rs_stay_in_table(lq_sta, false); - - goto out; - } - /* Else we have enough samples; calculate estimate of - * actual average throughput */ - if (window->average_tpt != ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128)) { - IWL_ERR(mvm, - "expected_tpt should have been calculated by now\n"); - window->average_tpt = ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128); - } - - /* If we are searching for better modulation mode, check success. */ - if (lq_sta->search_better_tbl) { - /* If good success, continue using the "search" mode; - * no need to send new link quality command, since we're - * continuing to use the setup that we've been trying. */ - if (window->average_tpt > lq_sta->last_tpt) { - IWL_DEBUG_RATE(mvm, - "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n", - window->success_ratio, - window->average_tpt, - lq_sta->last_tpt); - - if (!is_legacy(tbl->lq_type)) - lq_sta->enable_counter = 1; - - /* Swap tables; "search" becomes "active" */ - lq_sta->active_tbl = active_tbl; - current_tpt = window->average_tpt; - /* Else poor success; go back to mode in "active" table */ - } else { - IWL_DEBUG_RATE(mvm, - "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n", - window->success_ratio, - window->average_tpt, - lq_sta->last_tpt); - - /* Nullify "search" table */ - tbl->lq_type = LQ_NONE; - - /* Revert to "active" table */ - active_tbl = lq_sta->active_tbl; - tbl = &(lq_sta->lq_info[active_tbl]); - - /* Revert to "active" rate and throughput info */ - index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - current_tpt = lq_sta->last_tpt; - - /* Need to set up a new rate table in uCode */ - update_lq = 1; - } - - /* Either way, we've made a decision; modulation mode - * search is done, allow rate adjustment next time. */ - lq_sta->search_better_tbl = 0; - done_search = 1; /* Don't switch modes below! */ - goto lq_update; - } - - /* (Else) not in search of better modulation mode, try for better - * starting rate, while staying in this mode. */ - high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk, - tbl->lq_type); - low = high_low & 0xff; - high = (high_low >> 8) & 0xff; - - /* If user set max rate, dont allow higher than user constrain */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < high)) - high = IWL_RATE_INVALID; - - sr = window->success_ratio; - - /* Collect measured throughputs for current and adjacent rates */ - current_tpt = window->average_tpt; - if (low != IWL_RATE_INVALID) - low_tpt = tbl->win[low].average_tpt; - if (high != IWL_RATE_INVALID) - high_tpt = tbl->win[high].average_tpt; - - scale_action = 0; - - /* Too many failures, decrease rate */ - if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { - IWL_DEBUG_RATE(mvm, - "decrease rate because of low success_ratio\n"); - scale_action = -1; - /* No throughput measured yet for adjacent rates; try increase. */ - } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) { - if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) - scale_action = 1; - else if (low != IWL_RATE_INVALID) - scale_action = 0; - } - - /* Both adjacent throughputs are measured, but neither one has better - * throughput; we're using the best rate, don't change it! */ - else if ((low_tpt != IWL_INVALID_VALUE) && - (high_tpt != IWL_INVALID_VALUE) && - (low_tpt < current_tpt) && - (high_tpt < current_tpt)) - scale_action = 0; - - /* At least one adjacent rate's throughput is measured, - * and may have better performance. */ - else { - /* Higher adjacent rate's throughput is measured */ - if (high_tpt != IWL_INVALID_VALUE) { - /* Higher rate has better throughput */ - if (high_tpt > current_tpt && - sr >= IWL_RATE_INCREASE_TH) { - scale_action = 1; - } else { - scale_action = 0; - } - - /* Lower adjacent rate's throughput is measured */ - } else if (low_tpt != IWL_INVALID_VALUE) { - /* Lower rate has better throughput */ - if (low_tpt > current_tpt) { - IWL_DEBUG_RATE(mvm, - "decrease rate because of low tpt\n"); - scale_action = -1; - } else if (sr >= IWL_RATE_INCREASE_TH) { - scale_action = 1; - } - } - } - - /* Sanity check; asked for decrease, but success rate or throughput - * has been good at old rate. Don't change it. */ - if ((scale_action == -1) && (low != IWL_RATE_INVALID) && - ((sr > IWL_RATE_HIGH_TH) || - (current_tpt > (100 * tbl->expected_tpt[low])))) - scale_action = 0; - - switch (scale_action) { - case -1: - /* Decrease starting rate, update uCode's rate table */ - if (low != IWL_RATE_INVALID) { - update_lq = 1; - index = low; - } - - break; - case 1: - /* Increase starting rate, update uCode's rate table */ - if (high != IWL_RATE_INVALID) { - update_lq = 1; - index = high; - } - - break; - case 0: - /* No change */ - default: - break; - } - - IWL_DEBUG_RATE(mvm, - "choose rate scale index %d action %d low %d high %d type %d\n", - index, scale_action, low, high, tbl->lq_type); - -lq_update: - /* Replace uCode's rate table for the destination station. */ - if (update_lq) - rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green); - - rs_stay_in_table(lq_sta, false); - - /* - * Search for new modulation mode if we're: - * 1) Not changing rates right now - * 2) Not just finishing up a search - * 3) Allowing a new search - */ - if (!update_lq && !done_search && - !lq_sta->stay_in_tbl && window->counter) { - /* Save current throughput to compare with "search" throughput*/ - lq_sta->last_tpt = current_tpt; - - /* Select a new "search" modulation mode to try. - * If one is found, set up the new "search" table. */ - if (is_legacy(tbl->lq_type)) - rs_move_legacy_other(mvm, lq_sta, sta, index); - else if (is_siso(tbl->lq_type)) - rs_move_siso_to_other(mvm, lq_sta, sta, index); - else if (is_mimo2(tbl->lq_type)) - rs_move_mimo2_to_other(mvm, lq_sta, sta, index); - else - rs_move_mimo3_to_other(mvm, lq_sta, sta, index); - - /* If new "search" mode was selected, set up in uCode table */ - if (lq_sta->search_better_tbl) { - /* Access the "search" table, clear its history. */ - tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(tbl->win[i])); - - /* Use new "search" start rate */ - index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - - IWL_DEBUG_RATE(mvm, - "Switch current mcs: %X index: %d\n", - tbl->current_rate, index); - rs_fill_link_cmd(mvm, lq_sta, tbl->current_rate); - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); - } else { - done_search = 1; - } - } - - if (done_search && !lq_sta->stay_in_tbl) { - /* If the "active" (non-search) mode was legacy, - * and we've tried switching antennas, - * but we haven't been able to try HT modes (not available), - * stay with best antenna legacy modulation for a while - * before next round of mode comparisons. */ - tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported && - lq_sta->action_counter > tbl1->max_search) { - IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); - rs_set_stay_in_table(mvm, 1, lq_sta); - } - - /* If we're in an HT mode, and all 3 mode switch actions - * have been tried and compared, stay in this best modulation - * mode for a while before next round of mode comparisons. */ - if (lq_sta->enable_counter && - (lq_sta->action_counter >= tbl1->max_search)) { - if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && - (lq_sta->tx_agg_tid_en & (1 << tid)) && - (tid != IWL_MAX_TID_COUNT)) { - tid_data = &sta_priv->tid_data[tid]; - if (tid_data->state == IWL_AGG_OFF) { - IWL_DEBUG_RATE(mvm, - "try to aggregate tid %d\n", - tid); - rs_tl_turn_on_agg(mvm, tid, - lq_sta, sta); - } - } - rs_set_stay_in_table(mvm, 0, lq_sta); - } - } - -out: - tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green); - lq_sta->last_txrate_idx = index; -} - -/** - * rs_initialize_lq - Initialize a station's hardware rate table - * - * The uCode's station table contains a table of fallback rates - * for automatic fallback during transmission. - * - * NOTE: This sets up a default set of values. These will be replaced later - * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of - * rc80211_simple. - * - * NOTE: Run REPLY_ADD_STA command to set up station table entry, before - * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, - * which requires station table entry to exist). - */ -static void rs_initialize_lq(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, - struct iwl_lq_sta *lq_sta, - enum ieee80211_band band) -{ - struct iwl_scale_tbl_info *tbl; - int rate_idx; - int i; - u32 rate; - u8 use_green = rs_use_green(sta); - u8 active_tbl = 0; - u8 valid_tx_ant; - - if (!sta || !lq_sta) - return; - - i = lq_sta->last_txrate_idx; - - valid_tx_ant = mvm->nvm_data->valid_tx_ant; - - if (!lq_sta->search_better_tbl) - active_tbl = lq_sta->active_tbl; - else - active_tbl = 1 - lq_sta->active_tbl; - - tbl = &(lq_sta->lq_info[active_tbl]); - - if ((i < 0) || (i >= IWL_RATE_COUNT)) - i = 0; - - rate = iwl_rates[i].plcp; - tbl->ant_type = first_antenna(valid_tx_ant); - rate |= tbl->ant_type << RATE_MCS_ANT_POS; - - if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) - rate |= RATE_MCS_CCK_MSK; - - rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx); - if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) - rs_toggle_antenna(valid_tx_ant, &rate, tbl); - - rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx, use_green); - tbl->current_rate = rate; - rs_set_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(NULL, lq_sta, rate); - /* TODO restore station should remember the lq cmd */ - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true); -} - -static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; - struct iwl_op_mode *op_mode __maybe_unused = - (struct iwl_op_mode *)mvm_r; - struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_lq_sta *lq_sta = mvm_sta; - int rate_idx; - - IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n"); - - /* Get max rate if user set max rate */ - if (lq_sta) { - lq_sta->max_rate_idx = txrc->max_rate_idx; - if ((sband->band == IEEE80211_BAND_5GHZ) && - (lq_sta->max_rate_idx != -1)) - lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; - if ((lq_sta->max_rate_idx < 0) || - (lq_sta->max_rate_idx >= IWL_RATE_COUNT)) - lq_sta->max_rate_idx = -1; - } - - /* Treat uninitialized rate scaling data same as non-existing. */ - if (lq_sta && !lq_sta->drv) { - IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); - mvm_sta = NULL; - } - - /* Send management frames and NO_ACK data using lowest rate. */ - if (rate_control_send_low(sta, mvm_sta, txrc)) - return; - - rate_idx = lq_sta->last_txrate_idx; - - if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { - rate_idx -= IWL_FIRST_OFDM_RATE; - /* 6M and 9M shared same MCS index */ - rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; - if (rs_extract_rate(lq_sta->last_rate_n_flags) >= - IWL_RATE_MIMO3_6M_PLCP) - rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); - else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= - IWL_RATE_MIMO2_6M_PLCP) - rate_idx = rate_idx + MCS_INDEX_PER_STREAM; - info->control.rates[0].flags = IEEE80211_TX_RC_MCS; - if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) - info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; - if (lq_sta->last_rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */ - info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (lq_sta->last_rate_n_flags & RATE_HT_MCS_GF_MSK) - info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; - } else { - /* Check for invalid rates */ - if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) || - ((sband->band == IEEE80211_BAND_5GHZ) && - (rate_idx < IWL_FIRST_OFDM_RATE))) - rate_idx = rate_lowest_index(sband, sta); - /* On valid 5 GHz rate, adjust index */ - else if (sband->band == IEEE80211_BAND_5GHZ) - rate_idx -= IWL_FIRST_OFDM_RATE; - info->control.rates[0].flags = 0; - } - info->control.rates[0].idx = rate_idx; -} - -static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, - gfp_t gfp) -{ - struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; - struct iwl_op_mode *op_mode __maybe_unused = - (struct iwl_op_mode *)mvm_rate; - struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); - - IWL_DEBUG_RATE(mvm, "create station rate scale window\n"); - - return &sta_priv->lq_sta; -} - -/* - * Called after adding a new station to initialize rate scaling - */ -void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum ieee80211_band band) -{ - int i, j; - struct ieee80211_hw *hw = mvm->hw; - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - struct iwl_mvm_sta *sta_priv; - struct iwl_lq_sta *lq_sta; - struct ieee80211_supported_band *sband; - unsigned long supp; /* must be unsigned long for for_each_set_bit */ - - sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; - lq_sta = &sta_priv->lq_sta; - sband = hw->wiphy->bands[band]; - - lq_sta->lq.sta_id = sta_priv->sta_id; - - 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]); - - lq_sta->flush_timer = 0; - lq_sta->supp_rates = sta->supp_rates[sband->band]; - 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]); - - IWL_DEBUG_RATE(mvm, - "LQ: *** rate scale station global init for station %d ***\n", - sta_priv->sta_id); - /* TODO: what is a good starting rate for STA? About middle? Maybe not - * the lowest or the highest rate.. Could consider using RSSI from - * previous packets? Need to have IEEE 802.1X auth succeed immediately - * after assoc.. */ - - lq_sta->max_rate_idx = -1; - lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; - lq_sta->is_green = rs_use_green(sta); - lq_sta->band = sband->band; - /* - * active legacy rates as per supported rates bitmap - */ - supp = sta->supp_rates[sband->band]; - lq_sta->active_legacy_rate = 0; - for_each_set_bit(i, &supp, BITS_PER_LONG) - lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); - - /* - * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), - * supp_rates[] does not; shift to convert format, force 9 MBits off. - */ - lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; - lq_sta->active_siso_rate &= ~((u16)0x2); - lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; - - /* Same here */ - lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; - lq_sta->active_mimo2_rate &= ~((u16)0x2); - lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - - lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; - lq_sta->active_mimo3_rate &= ~((u16)0x2); - lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; - - IWL_DEBUG_RATE(mvm, - "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", - lq_sta->active_siso_rate, - lq_sta->active_mimo2_rate, - lq_sta->active_mimo3_rate); - - /* These values will be overridden later */ - lq_sta->lq.single_stream_ant_msk = - first_antenna(mvm->nvm_data->valid_tx_ant); - lq_sta->lq.dual_stream_ant_msk = - mvm->nvm_data->valid_tx_ant & - ~first_antenna(mvm->nvm_data->valid_tx_ant); - if (!lq_sta->lq.dual_stream_ant_msk) { - lq_sta->lq.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) { - lq_sta->lq.dual_stream_ant_msk = - mvm->nvm_data->valid_tx_ant; - } - - /* as default allow aggregation for all tids */ - lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; - lq_sta->drv = mvm; - - /* Set last_txrate_idx to lowest rate */ - lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); - if (sband->band == IEEE80211_BAND_5GHZ) - lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; - lq_sta->is_agg = 0; -#ifdef CONFIG_MAC80211_DEBUGFS - lq_sta->dbg_fixed_rate = 0; -#endif - - rs_initialize_lq(mvm, sta, lq_sta, band); -} - -static void rs_fill_link_cmd(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, u32 new_rate) -{ - struct iwl_scale_tbl_info tbl_type; - int index = 0; - int rate_idx; - int repeat_rate = 0; - u8 ant_toggle_cnt = 0; - u8 use_ht_possible = 1; - u8 valid_tx_ant = 0; - struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; - - /* Override starting rate (index 0) if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - - /* Interpret new_rate (rate_n_flags) */ - rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, - &tbl_type, &rate_idx); - - /* How many times should we repeat the initial rate? */ - if (is_legacy(tbl_type.lq_type)) { - ant_toggle_cnt = 1; - repeat_rate = IWL_NUMBER_TRY; - } else { - repeat_rate = min(IWL_HT_NUMBER_TRY, - LINK_QUAL_AGG_DISABLE_START_DEF - 1); - } - - lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0; - - /* Fill 1st table entry (index 0) */ - lq_cmd->rs_table[index] = cpu_to_le32(new_rate); - - if (num_of_ant(tbl_type.ant_type) == 1) - lq_cmd->single_stream_ant_msk = tbl_type.ant_type; - else if (num_of_ant(tbl_type.ant_type) == 2) - lq_cmd->dual_stream_ant_msk = tbl_type.ant_type; - /* otherwise we don't modify the existing value */ - - index++; - repeat_rate--; - if (mvm) - valid_tx_ant = mvm->nvm_data->valid_tx_ant; - - /* Fill rest of rate table */ - while (index < LINK_QUAL_MAX_RETRY_NUM) { - /* Repeat initial/next rate. - * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. - * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ - while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { - if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) - ant_toggle_cnt++; - else if (mvm && - rs_toggle_antenna(valid_tx_ant, - &new_rate, &tbl_type)) - ant_toggle_cnt = 1; - } - - /* Override next rate if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - - /* Fill next table entry */ - lq_cmd->rs_table[index] = - cpu_to_le32(new_rate); - repeat_rate--; - index++; - } - - rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, - &rate_idx); - - - /* Indicate to uCode which entries might be MIMO. - * If initial rate was MIMO, this will finally end up - * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ - if (is_mimo(tbl_type.lq_type)) - lq_cmd->mimo_delim = index; - - /* Get next rate */ - new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, - use_ht_possible); - - /* How many times should we repeat the next rate? */ - if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) - ant_toggle_cnt++; - else if (mvm && - rs_toggle_antenna(valid_tx_ant, - &new_rate, &tbl_type)) - ant_toggle_cnt = 1; - - repeat_rate = IWL_NUMBER_TRY; - } else { - repeat_rate = IWL_HT_NUMBER_TRY; - } - - /* Don't allow HT rates after next pass. - * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ - use_ht_possible = 0; - - /* Override next rate if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - - /* Fill next table entry */ - lq_cmd->rs_table[index] = cpu_to_le32(new_rate); - - index++; - repeat_rate--; - } - - lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; - - lq_cmd->agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); -} - -static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - return hw->priv; -} -/* rate scale requires free function to be implemented */ -static void rs_free(void *mvm_rate) -{ - return; -} - -static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, - void *mvm_sta) -{ - struct iwl_op_mode *op_mode __maybe_unused = mvm_r; - struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); - - IWL_DEBUG_RATE(mvm, "enter\n"); - IWL_DEBUG_RATE(mvm, "leave\n"); -} - -#ifdef CONFIG_MAC80211_DEBUGFS -static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, - u32 *rate_n_flags, int index) -{ - struct iwl_mvm *mvm; - u8 valid_tx_ant; - u8 ant_sel_tx; - - mvm = lq_sta->drv; - valid_tx_ant = mvm->nvm_data->valid_tx_ant; - if (lq_sta->dbg_fixed_rate) { - ant_sel_tx = - ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) - >> RATE_MCS_ANT_POS); - if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) { - *rate_n_flags = lq_sta->dbg_fixed_rate; - IWL_DEBUG_RATE(mvm, "Fixed rate ON\n"); - } else { - lq_sta->dbg_fixed_rate = 0; - IWL_ERR(mvm, - "Invalid antenna selection 0x%X, Valid is 0x%X\n", - ant_sel_tx, valid_tx_ant); - IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); - } - } else { - IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); - } -} - -static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct iwl_lq_sta *lq_sta = file->private_data; - struct iwl_mvm *mvm; - char buf[64]; - size_t buf_size; - u32 parsed_rate; - - - mvm = lq_sta->drv; - 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", &parsed_rate) == 1) - lq_sta->dbg_fixed_rate = parsed_rate; - else - lq_sta->dbg_fixed_rate = 0; - - rs_program_fix_rate(mvm, lq_sta); - - return count; -} - -static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - char *buff; - int desc = 0; - int i = 0; - int index = 0; - ssize_t ret; - - struct iwl_lq_sta *lq_sta = file->private_data; - struct iwl_mvm *mvm; - struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); - - mvm = lq_sta->drv; - buff = kmalloc(1024, GFP_KERNEL); - if (!buff) - return -ENOMEM; - - desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); - desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", - lq_sta->total_failed, lq_sta->total_success, - lq_sta->active_legacy_rate); - desc += sprintf(buff+desc, "fixed rate 0x%X\n", - lq_sta->dbg_fixed_rate); - desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", - (mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "", - (mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "", - (mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : ""); - desc += sprintf(buff+desc, "lq type %s\n", - (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); - if (is_Ht(tbl->lq_type)) { - desc += sprintf(buff+desc, " %s", - (is_siso(tbl->lq_type)) ? "SISO" : - ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); - desc += sprintf(buff+desc, " %s", - (tbl->is_ht40) ? "40MHz" : "20MHz"); - desc += sprintf(buff+desc, " %s %s %s\n", - (tbl->is_SGI) ? "SGI" : "", - (lq_sta->is_green) ? "GF enabled" : "", - (lq_sta->is_agg) ? "AGG on" : ""); - } - desc += sprintf(buff+desc, "last tx rate=0x%X\n", - lq_sta->last_rate_n_flags); - desc += sprintf(buff+desc, - "general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", - lq_sta->lq.flags, - lq_sta->lq.mimo_delim, - lq_sta->lq.single_stream_ant_msk, - lq_sta->lq.dual_stream_ant_msk); - - desc += sprintf(buff+desc, - "agg: time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n", - le16_to_cpu(lq_sta->lq.agg_time_limit), - lq_sta->lq.agg_disable_start_th, - lq_sta->lq.agg_frame_cnt_limit); - - desc += sprintf(buff+desc, - "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", - lq_sta->lq.initial_rate_index[0], - lq_sta->lq.initial_rate_index[1], - lq_sta->lq.initial_rate_index[2], - lq_sta->lq.initial_rate_index[3]); - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { - index = iwl_hwrate_to_plcp_idx( - le32_to_cpu(lq_sta->lq.rs_table[i])); - if (is_legacy(tbl->lq_type)) { - desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i]), - iwl_rate_mcs[index].mbps); - } else { - desc += sprintf(buff+desc, - " rate[%d] 0x%X %smbps (%s)\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i]), - iwl_rate_mcs[index].mbps, - iwl_rate_mcs[index].mcs); - } - } - - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - kfree(buff); - return ret; -} - -static const struct file_operations rs_sta_dbgfs_scale_table_ops = { - .write = rs_sta_dbgfs_scale_table_write, - .read = rs_sta_dbgfs_scale_table_read, - .open = simple_open, - .llseek = default_llseek, -}; -static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - char *buff; - int desc = 0; - int i, j; - ssize_t ret; - - struct iwl_lq_sta *lq_sta = file->private_data; - - buff = kmalloc(1024, GFP_KERNEL); - if (!buff) - return -ENOMEM; - - for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, - "%s type=%d SGI=%d HT40=%d DUP=0 GF=%d\n" - "rate=0x%X\n", - lq_sta->active_tbl == i ? "*" : "x", - lq_sta->lq_info[i].lq_type, - lq_sta->lq_info[i].is_SGI, - lq_sta->lq_info[i].is_ht40, - lq_sta->is_green, - lq_sta->lq_info[i].current_rate); - for (j = 0; j < IWL_RATE_COUNT; j++) { - desc += sprintf(buff+desc, - "counter=%d success=%d %%=%d\n", - lq_sta->lq_info[i].win[j].counter, - lq_sta->lq_info[i].win[j].success_counter, - lq_sta->lq_info[i].win[j].success_ratio); - } - } - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - kfree(buff); - return ret; -} - -static const struct file_operations rs_sta_dbgfs_stats_table_ops = { - .read = rs_sta_dbgfs_stats_table_read, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - struct iwl_lq_sta *lq_sta = file->private_data; - struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; - char buff[120]; - int desc = 0; - - if (is_Ht(tbl->lq_type)) - desc += sprintf(buff+desc, - "Bit Rate= %d Mb/s\n", - tbl->expected_tpt[lq_sta->last_txrate_idx]); - else - desc += sprintf(buff+desc, - "Bit Rate= %d Mb/s\n", - iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); - - return simple_read_from_buffer(user_buf, count, ppos, buff, desc); -} - -static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { - .read = rs_sta_dbgfs_rate_scale_data_read, - .open = simple_open, - .llseek = default_llseek, -}; - -static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) -{ - struct iwl_lq_sta *lq_sta = mvm_sta; - lq_sta->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, - lq_sta, &rs_sta_dbgfs_scale_table_ops); - lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", S_IRUSR, dir, - lq_sta, &rs_sta_dbgfs_stats_table_ops); - lq_sta->rs_sta_dbgfs_rate_scale_data_file = - debugfs_create_file("rate_scale_data", S_IRUSR, dir, - lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); - lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, - &lq_sta->tx_agg_tid_en); -} - -static void rs_remove_debugfs(void *mvm, void *mvm_sta) -{ - struct iwl_lq_sta *lq_sta = mvm_sta; - debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); -} -#endif - -/* - * Initialization of rate scaling information is done by driver after - * the station is added. Since mac80211 calls this function before a - * station is added we ignore it. - */ -static void rs_rate_init_stub(void *mvm_r, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *mvm_sta) -{ -} -static struct rate_control_ops rs_mvm_ops = { - .module = NULL, - .name = RS_NAME, - .tx_status = rs_tx_status, - .get_rate = rs_get_rate, - .rate_init = rs_rate_init_stub, - .alloc = rs_alloc, - .free = rs_free, - .alloc_sta = rs_alloc_sta, - .free_sta = rs_free_sta, -#ifdef CONFIG_MAC80211_DEBUGFS - .add_sta_debugfs = rs_add_debugfs, - .remove_sta_debugfs = rs_remove_debugfs, -#endif -}; - -int iwl_mvm_rate_control_register(void) -{ - return ieee80211_rate_control_register(&rs_mvm_ops); -} - -void iwl_mvm_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&rs_mvm_ops); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/rs.h b/trunk/drivers/net/wireless/iwlwifi/mvm/rs.h deleted file mode 100644 index 219c6857cc0f..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/rs.h +++ /dev/null @@ -1,393 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __rs_h__ -#define __rs_h__ - -#include - -#include "iwl-config.h" - -#include "fw-api.h" -#include "iwl-trans.h" - -struct iwl_rs_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ - u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ - u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ - u8 prev_rs; /* previous rate used in rs algo */ - 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 */ -}; - -#define IWL_RATE_60M_PLCP 3 - -enum { - IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, - IWL_RATE_INVALID = IWL_RATE_COUNT, -}; - -#define LINK_QUAL_MAX_RETRY_NUM 16 - -enum { - IWL_RATE_6M_INDEX_TABLE = 0, - IWL_RATE_9M_INDEX_TABLE, - IWL_RATE_12M_INDEX_TABLE, - IWL_RATE_18M_INDEX_TABLE, - IWL_RATE_24M_INDEX_TABLE, - IWL_RATE_36M_INDEX_TABLE, - IWL_RATE_48M_INDEX_TABLE, - IWL_RATE_54M_INDEX_TABLE, - IWL_RATE_1M_INDEX_TABLE, - IWL_RATE_2M_INDEX_TABLE, - IWL_RATE_5M_INDEX_TABLE, - IWL_RATE_11M_INDEX_TABLE, - IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1, -}; - -/* #define vs. enum to keep from defaulting to 'large integer' */ -#define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX) -#define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX) -#define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX) -#define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX) -#define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX) -#define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX) -#define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX) -#define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX) -#define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX) -#define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX) -#define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX) -#define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX) -#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) - - -/* uCode API values for OFDM high-throughput (HT) bit rates */ -enum { - IWL_RATE_SISO_6M_PLCP = 0, - IWL_RATE_SISO_12M_PLCP = 1, - IWL_RATE_SISO_18M_PLCP = 2, - IWL_RATE_SISO_24M_PLCP = 3, - IWL_RATE_SISO_36M_PLCP = 4, - IWL_RATE_SISO_48M_PLCP = 5, - IWL_RATE_SISO_54M_PLCP = 6, - IWL_RATE_SISO_60M_PLCP = 7, - IWL_RATE_MIMO2_6M_PLCP = 0x8, - IWL_RATE_MIMO2_12M_PLCP = 0x9, - IWL_RATE_MIMO2_18M_PLCP = 0xa, - IWL_RATE_MIMO2_24M_PLCP = 0xb, - IWL_RATE_MIMO2_36M_PLCP = 0xc, - IWL_RATE_MIMO2_48M_PLCP = 0xd, - IWL_RATE_MIMO2_54M_PLCP = 0xe, - IWL_RATE_MIMO2_60M_PLCP = 0xf, - IWL_RATE_MIMO3_6M_PLCP = 0x10, - IWL_RATE_MIMO3_12M_PLCP = 0x11, - IWL_RATE_MIMO3_18M_PLCP = 0x12, - IWL_RATE_MIMO3_24M_PLCP = 0x13, - IWL_RATE_MIMO3_36M_PLCP = 0x14, - IWL_RATE_MIMO3_48M_PLCP = 0x15, - IWL_RATE_MIMO3_54M_PLCP = 0x16, - IWL_RATE_MIMO3_60M_PLCP = 0x17, - IWL_RATE_SISO_INVM_PLCP, - IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, - IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, -}; - -/* MAC header values for bit rates */ -enum { - IWL_RATE_6M_IEEE = 12, - IWL_RATE_9M_IEEE = 18, - IWL_RATE_12M_IEEE = 24, - IWL_RATE_18M_IEEE = 36, - IWL_RATE_24M_IEEE = 48, - IWL_RATE_36M_IEEE = 72, - IWL_RATE_48M_IEEE = 96, - IWL_RATE_54M_IEEE = 108, - IWL_RATE_60M_IEEE = 120, - IWL_RATE_1M_IEEE = 2, - IWL_RATE_2M_IEEE = 4, - IWL_RATE_5M_IEEE = 11, - IWL_RATE_11M_IEEE = 22, -}; - -#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) - -#define IWL_INVALID_VALUE -1 - -#define IWL_MIN_RSSI_VAL -100 -#define IWL_MAX_RSSI_VAL 0 - -/* These values specify how many Tx frame attempts before - * searching for a new modulation mode */ -#define IWL_LEGACY_FAILURE_LIMIT 160 -#define IWL_LEGACY_SUCCESS_LIMIT 480 -#define IWL_LEGACY_TABLE_COUNT 160 - -#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 -#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 -#define IWL_NONE_LEGACY_TABLE_COUNT 1500 - -/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */ -#define IWL_RS_GOOD_RATIO 12800 /* 100% */ -#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ -#define IWL_RATE_HIGH_TH 10880 /* 85% */ -#define IWL_RATE_INCREASE_TH 6400 /* 50% */ -#define IWL_RATE_DECREASE_TH 1920 /* 15% */ - -/* possible actions when in legacy mode */ -#define IWL_LEGACY_SWITCH_ANTENNA1 0 -#define IWL_LEGACY_SWITCH_ANTENNA2 1 -#define IWL_LEGACY_SWITCH_SISO 2 -#define IWL_LEGACY_SWITCH_MIMO2_AB 3 -#define IWL_LEGACY_SWITCH_MIMO2_AC 4 -#define IWL_LEGACY_SWITCH_MIMO2_BC 5 -#define IWL_LEGACY_SWITCH_MIMO3_ABC 6 - -/* possible actions when in siso mode */ -#define IWL_SISO_SWITCH_ANTENNA1 0 -#define IWL_SISO_SWITCH_ANTENNA2 1 -#define IWL_SISO_SWITCH_MIMO2_AB 2 -#define IWL_SISO_SWITCH_MIMO2_AC 3 -#define IWL_SISO_SWITCH_MIMO2_BC 4 -#define IWL_SISO_SWITCH_GI 5 -#define IWL_SISO_SWITCH_MIMO3_ABC 6 - - -/* possible actions when in mimo mode */ -#define IWL_MIMO2_SWITCH_ANTENNA1 0 -#define IWL_MIMO2_SWITCH_ANTENNA2 1 -#define IWL_MIMO2_SWITCH_SISO_A 2 -#define IWL_MIMO2_SWITCH_SISO_B 3 -#define IWL_MIMO2_SWITCH_SISO_C 4 -#define IWL_MIMO2_SWITCH_GI 5 -#define IWL_MIMO2_SWITCH_MIMO3_ABC 6 - - -/* possible actions when in mimo3 mode */ -#define IWL_MIMO3_SWITCH_ANTENNA1 0 -#define IWL_MIMO3_SWITCH_ANTENNA2 1 -#define IWL_MIMO3_SWITCH_SISO_A 2 -#define IWL_MIMO3_SWITCH_SISO_B 3 -#define IWL_MIMO3_SWITCH_SISO_C 4 -#define IWL_MIMO3_SWITCH_MIMO2_AB 5 -#define IWL_MIMO3_SWITCH_MIMO2_AC 6 -#define IWL_MIMO3_SWITCH_MIMO2_BC 7 -#define IWL_MIMO3_SWITCH_GI 8 - - -#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI -#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC - -/*FIXME:RS:add possible actions for MIMO3*/ - -#define IWL_ACTION_LIMIT 3 /* # possible actions */ - -#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ -#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) -#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) - -#define LINK_QUAL_AGG_DISABLE_START_DEF (3) -#define LINK_QUAL_AGG_DISABLE_START_MAX (255) -#define LINK_QUAL_AGG_DISABLE_START_MIN (0) - -#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) -#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) -#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) - -#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_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) -#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) - -enum iwl_table_type { - LQ_NONE, - LQ_G, /* legacy types */ - LQ_A, - LQ_SISO, /* high-throughput types */ - LQ_MIMO2, - LQ_MIMO3, - LQ_MAX, -}; - -#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) -#define is_siso(tbl) ((tbl) == LQ_SISO) -#define is_mimo2(tbl) ((tbl) == LQ_MIMO2) -#define is_mimo3(tbl) ((tbl) == LQ_MIMO3) -#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) -#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) -#define is_a_band(tbl) ((tbl) == LQ_A) -#define is_g_and(tbl) ((tbl) == LQ_G) - -#define IWL_MAX_MCS_DISPLAY_SIZE 12 - -struct iwl_rate_mcs_info { - char mbps[IWL_MAX_MCS_DISPLAY_SIZE]; - char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; -}; - -/** - * struct iwl_rate_scale_data -- tx success history for one rate - */ -struct iwl_rate_scale_data { - u64 data; /* bitmap of successful frames */ - s32 success_counter; /* number of frames successful */ - s32 success_ratio; /* per-cent * 128 */ - s32 counter; /* number of frames attempted */ - s32 average_tpt; /* success ratio * expected throughput */ - unsigned long stamp; -}; - -/** - * struct iwl_scale_tbl_info -- tx params and success history for all rates - * - * There are two of these in struct iwl_lq_sta, - * one for "active", and one for "search". - */ -struct iwl_scale_tbl_info { - enum iwl_table_type lq_type; - u8 ant_type; - u8 is_SGI; /* 1 = short guard interval */ - u8 is_ht40; /* 1 = 40 MHz channel width */ - u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ - u8 max_search; /* maximun number of tables we can search */ - s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ - u32 current_rate; /* rate_n_flags, uCode API format */ - struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ -}; - -struct iwl_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 */ -}; - -/** - * struct iwl_lq_sta -- driver's rate scaling private structure - * - * Pointer to this gets passed back and forth between driver and mac80211. - */ -struct iwl_lq_sta { - u8 active_tbl; /* index of active table, range 0-1 */ - u8 enable_counter; /* indicates HT mode */ - u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ - u8 search_better_tbl; /* 1: currently trying alternate mode */ - s32 last_tpt; - - /* The following determine when to search for a new mode */ - u32 table_count_limit; - u32 max_failure_limit; /* # failed frames before new search */ - u32 max_success_limit; /* # successful frames before new search */ - u32 table_count; - u32 total_failed; /* total failed frames, any/all rates */ - u32 total_success; /* total successful frames, any/all rates */ - u64 flush_timer; /* time staying in mode before new search */ - - u8 action_counter; /* # mode-switch actions tried */ - u8 is_green; - enum ieee80211_band band; - - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ - u32 supp_rates; - u16 active_legacy_rate; - u16 active_siso_rate; - u16 active_mimo2_rate; - u16 active_mimo3_rate; - s8 max_rate_idx; /* Max rate set by user */ - u8 missed_rate_counter; - - struct iwl_lq_cmd lq; - struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ - struct iwl_traffic_load load[IWL_MAX_TID_COUNT]; - u8 tx_agg_tid_en; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; - struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_rate_scale_data_file; - struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; - u32 dbg_fixed_rate; -#endif - struct iwl_mvm *drv; - - /* used to be in sta_info */ - int last_txrate_idx; - /* last tx rate_n_flags */ - u32 last_rate_n_flags; - /* packets destined for this STA are aggregated */ - u8 is_agg; - /* BT traffic this sta was last updated in */ - u8 last_bt_traffic; -}; - -static inline u8 num_of_ant(u8 mask) -{ - return !!((mask) & ANT_A) + - !!((mask) & ANT_B) + - !!((mask) & ANT_C); -} - -/* Initialize station's rate scaling information after adding station */ -extern void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, - enum ieee80211_band band); - -/** - * iwl_rate_control_register - Register the rate control algorithm callbacks - * - * Since the rate control algorithm is hardware specific, there is no need - * or reason to place it as a stand alone module. The driver can call - * iwl_rate_control_register in order to register the rate control callbacks - * with the mac80211 subsystem. This should be performed prior to calling - * ieee80211_register_hw - * - */ -extern int iwl_mvm_rate_control_register(void); - -/** - * iwl_rate_control_unregister - Unregister the rate control callbacks - * - * This should be called after calling ieee80211_unregister_hw, but before - * the driver is unloaded. - */ -extern void iwl_mvm_rate_control_unregister(void); - -#endif /* __rs__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/rx.c b/trunk/drivers/net/wireless/iwlwifi/mvm/rx.c deleted file mode 100644 index 52da375e5740..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/rx.c +++ /dev/null @@ -1,355 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 "iwl-trans.h" - -#include "mvm.h" -#include "fw-api.h" - -/* - * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler - * - * Copies the phy information in mvm->last_phy_info, it will be used when the - * actual data will come from the fw in the next packet. - */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - - memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info)); - mvm->ampdu_ref++; - return 0; -} - -/* - * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211 - * - * Adds the rxb to a new skb and give it to mac80211 - */ -static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, - struct ieee80211_hdr *hdr, u16 len, - u32 ampdu_status, - struct iwl_rx_cmd_buffer *rxb, - struct ieee80211_rx_status *stats) -{ - struct sk_buff *skb; - unsigned int hdrlen, fraglen; - - /* Dont use dev_alloc_skb(), we'll have enough headroom once - * ieee80211_hdr pulled. - */ - skb = alloc_skb(128, GFP_ATOMIC); - if (!skb) { - IWL_ERR(mvm, "alloc_skb failed\n"); - return; - } - /* If frame is small enough to fit in skb->head, pull it completely. - * If not, only pull ieee80211_hdr so that splice() or TCP coalesce - * are more efficient. - */ - hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); - - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); - fraglen = len - hdrlen; - - if (fraglen) { - int offset = (void *)hdr + hdrlen - - rxb_addr(rxb) + rxb_offset(rxb); - - skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, - fraglen, rxb->truesize); - } - - memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - - ieee80211_rx(mvm->hw, skb); -} - -/* - * iwl_mvm_calc_rssi - calculate the rssi in dBm - * @phy_info: the phy information for the coming packet - */ -static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, - struct iwl_rx_phy_info *phy_info) -{ - u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; - u32 val; - - /* Find max rssi among 3 possible receivers. - * These values are measured by the Digital Signal Processor (DSP). - * They should stay fairly constant even as the signal strength varies, - * if the radio's Automatic Gain Control (AGC) is working right. - * AGC value (see below) will provide the "interesting" info. - */ - val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); - rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; - rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; - val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); - rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; - - val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); - agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; - - max_rssi = max_t(u32, rssi_a, rssi_b); - max_rssi = max_t(u32, max_rssi, rssi_c); - - IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", - rssi_a, rssi_b, rssi_c, max_rssi, agc_db); - - /* dBm = max_rssi dB - agc dB - constant. - * Higher AGC (higher radio gain) means lower signal. */ - return max_rssi - agc_db - IWL_RSSI_OFFSET; -} - -/* - * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format - * @mvm: the mvm object - * @hdr: 80211 header - * @stats: status in mac80211's format - * @rx_pkt_status: status coming from fw - * - * returns non 0 value if the packet should be dropped - */ -static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *stats, - u32 rx_pkt_status) -{ - if (!ieee80211_has_protected(hdr->frame_control) || - (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == - RX_MPDU_RES_STATUS_SEC_NO_ENC) - return 0; - - /* packet was encrypted with unknown alg */ - if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == - RX_MPDU_RES_STATUS_SEC_ENC_ERR) - return 0; - - switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) { - case RX_MPDU_RES_STATUS_SEC_CCM_ENC: - /* alg is CCM: check MIC only */ - if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK)) - return -1; - - stats->flag |= RX_FLAG_DECRYPTED; - IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n"); - return 0; - - case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: - /* Don't drop the frame and decrypt it in SW */ - if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) - return 0; - /* fall through if TTAK OK */ - - case RX_MPDU_RES_STATUS_SEC_WEP_ENC: - if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK)) - return -1; - - stats->flag |= RX_FLAG_DECRYPTED; - return 0; - - default: - IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); - } - - return 0; -} - -/* - * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler - * - * Handles the actual data of the Rx packet from the fw - */ -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct ieee80211_hdr *hdr; - struct ieee80211_rx_status rx_status = {}; - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_rx_phy_info *phy_info; - struct iwl_rx_mpdu_res_start *rx_res; - u32 len; - u32 ampdu_status; - u32 rate_n_flags; - u32 rx_pkt_status; - - phy_info = &mvm->last_phy_info; - rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; - hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res)); - len = le16_to_cpu(rx_res->byte_count); - rx_pkt_status = le32_to_cpup((__le32 *) - (pkt->data + sizeof(*rx_res) + len)); - - memset(&rx_status, 0, sizeof(rx_status)); - - /* - * drop the packet if it has failed being decrypted by HW - */ - if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) { - IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", - rx_pkt_status); - return 0; - } - - if ((unlikely(phy_info->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", - phy_info->cfg_phy_cnt); - return 0; - } - - if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || - !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { - IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); - return 0; - } - - /* This will be used in several places later */ - rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); - - /* rx_status carries information about the packet to mac80211 */ - rx_status.mactime = le64_to_cpu(phy_info->timestamp); - rx_status.band = - (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), - rx_status.band); - /* - * TSF as indicated by the fw is at INA time, but mac80211 expects the - * TSF at the beginning of the MPDU. - */ - /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ - - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info); - - IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, - (unsigned long long)rx_status.mactime); - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bit field. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favor of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - rx_status.antenna = (le16_to_cpu(phy_info->phy_flags) & - RX_RES_PHY_FLAGS_ANTENNA) - >> RX_RES_PHY_FLAGS_ANTENNA_POS; - - /* set the preamble flag if appropriate */ - if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) - rx_status.flag |= RX_FLAG_SHORTPRE; - - if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { - /* - * We know which subframes of an A-MPDU belong - * together since we get a single PHY response - * from the firmware for all of them - */ - rx_status.flag |= RX_FLAG_AMPDU_DETAILS; - rx_status.ampdu_reference = mvm->ampdu_ref; - } - - /* Set up the HT phy flags */ - switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { - case RATE_MCS_CHAN_WIDTH_20: - break; - case RATE_MCS_CHAN_WIDTH_40: - rx_status.flag |= RX_FLAG_40MHZ; - break; - case RATE_MCS_CHAN_WIDTH_80: - rx_status.flag |= RX_FLAG_80MHZ; - break; - case RATE_MCS_CHAN_WIDTH_160: - rx_status.flag |= RX_FLAG_160MHZ; - break; - } - if (rate_n_flags & RATE_MCS_SGI_MSK) - rx_status.flag |= RX_FLAG_SHORT_GI; - if (rate_n_flags & RATE_HT_MCS_GF_MSK) - rx_status.flag |= RX_FLAG_HT_GF; - if (rate_n_flags & RATE_MCS_HT_MSK) { - rx_status.flag |= RX_FLAG_HT; - rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; - } else if (rate_n_flags & RATE_MCS_VHT_MSK) { - rx_status.vht_nss = - ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> - RATE_VHT_MCS_NSS_POS) + 1; - rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; - rx_status.flag |= RX_FLAG_VHT; - } else { - rx_status.rate_idx = - iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, - rx_status.band); - } - - iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, - rxb, &rx_status); - return 0; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/scan.c b/trunk/drivers/net/wireless/iwlwifi/mvm/scan.c deleted file mode 100644 index 406c53ad0a49..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/scan.c +++ /dev/null @@ -1,437 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include - -#include "mvm.h" -#include "iwl-eeprom-parse.h" -#include "fw-api-scan.h" - -#define IWL_PLCP_QUIET_THRESH 1 -#define IWL_ACTIVE_QUIET_TIME 10 - -static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) -{ - u16 rx_chain; - u8 rx_ant = mvm->nvm_data->valid_rx_ant; - - rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; - rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; - rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; - rx_chain |= 0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS; - return cpu_to_le16(rx_chain); -} - -static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif) -{ - if (vif->bss_conf.assoc) - return cpu_to_le32(200 * 1024); - else - return 0; -} - -static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif) -{ - if (vif->bss_conf.assoc) - return cpu_to_le32(vif->bss_conf.beacon_int); - else - return 0; -} - -static inline __le32 -iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req) -{ - if (req->channels[0]->band == IEEE80211_BAND_2GHZ) - return cpu_to_le32(PHY_BAND_24); - else - return cpu_to_le32(PHY_BAND_5); -} - -static inline __le32 -iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, - bool no_cck) -{ - u32 tx_ant; - - mvm->scan_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, - mvm->scan_last_antenna_idx); - tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; - - if (band == IEEE80211_BAND_2GHZ && !no_cck) - return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK | - tx_ant); - else - return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant); -} - -/* - * We insert the SSIDs in an inverted order, because the FW will - * invert it back. The most prioritized SSID, which is first in the - * request list, is not copied here, but inserted directly to the probe - * request. - */ -static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, - struct cfg80211_scan_request *req) -{ - int fw_idx, req_idx; - - fw_idx = 0; - for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) { - cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; - cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; - memcpy(cmd->direct_scan[fw_idx].ssid, - req->ssids[req_idx].ssid, - req->ssids[req_idx].ssid_len); - } -} - -/* - * If req->n_ssids > 0, it means we should do an active scan. - * In case of active scan w/o directed scan, we receive a zero-length SSID - * just to notify that this scan is active and not passive. - * In order to notify the FW of the number of SSIDs we wish to scan (including - * the zero-length one), we need to set the corresponding bits in chan->type, - * one for each SSID, and set the active bit (first). - */ -static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) -{ - if (band == IEEE80211_BAND_2GHZ) - return 30 + 3 * (n_ssids + 1); - return 20 + 2 * (n_ssids + 1); -} - -static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) -{ - return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10; -} - -static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, - struct cfg80211_scan_request *req) -{ - u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band); - u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band, - req->n_ssids); - struct iwl_scan_channel *chan = (struct iwl_scan_channel *) - (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); - int i; - __le32 chan_type_value; - - if (req->n_ssids > 0) - chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1); - else - chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE; - - for (i = 0; i < cmd->channel_count; i++) { - chan->channel = cpu_to_le16(req->channels[i]->hw_value); - if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) - chan->type = SCAN_CHANNEL_TYPE_PASSIVE; - else - chan->type = chan_type_value; - chan->active_dwell = cpu_to_le16(active_dwell); - chan->passive_dwell = cpu_to_le16(passive_dwell); - chan->iteration_count = cpu_to_le16(1); - chan++; - } -} - -/* - * Fill in probe request with the following parameters: - * TA is our vif HW address, which mac80211 ensures we have. - * Packet is broadcasted, so this is both SA and DA. - * The probe request IE is made out of two: first comes the most prioritized - * SSID if a directed scan is requested. Second comes whatever extra - * information was given to us as the scan request IE. - */ -static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, - int n_ssids, const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len, - int left) -{ - int len = 0; - u8 *pos = NULL; - - /* Make sure there is enough space for the probe request, - * two mandatory IEs and the data */ - left -= 24; - if (left < 0) - return 0; - - frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - eth_broadcast_addr(frame->da); - memcpy(frame->sa, ta, ETH_ALEN); - eth_broadcast_addr(frame->bssid); - frame->seq_ctrl = 0; - - len += 24; - - /* for passive scans, no need to fill anything */ - if (n_ssids == 0) - return (u16)len; - - /* points to the payload of the request */ - pos = &frame->u.probe_req.variable[0]; - - /* fill in our SSID IE */ - left -= ssid_len + 2; - if (left < 0) - return 0; - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */ - memcpy(pos, ssid, ssid_len); - pos += ssid_len; - } - - len += ssid_len + 2; - - if (WARN_ON(left < ie_len)) - return len; - - if (ie && ie_len) { - memcpy(pos, ie, ie_len); - len += ie_len; - } - - return (u16)len; -} - -int iwl_mvm_scan_request(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct iwl_host_cmd hcmd = { - .id = SCAN_REQUEST_CMD, - .len = { 0, }, - .data = { mvm->scan_cmd, }, - .flags = CMD_SYNC, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - }; - struct iwl_scan_cmd *cmd = mvm->scan_cmd; - int ret; - u32 status; - int ssid_len = 0; - u8 *ssid = NULL; - - lockdep_assert_held(&mvm->mutex); - BUG_ON(mvm->scan_cmd == NULL); - - IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n"); - mvm->scan_status = IWL_MVM_SCAN_OS; - memset(cmd, 0, sizeof(struct iwl_scan_cmd) + - mvm->fw->ucode_capa.max_probe_length + - (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); - - cmd->channel_count = (u8)req->n_channels; - cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); - cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); - cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); - cmd->max_out_time = iwl_mvm_scan_max_out_time(vif); - cmd->suspend_time = iwl_mvm_scan_suspend_time(vif); - cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); - cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | - MAC_FILTER_IN_BEACON); - cmd->type = SCAN_TYPE_FORCED; - cmd->repeats = cpu_to_le32(1); - - /* - * If the user asked for passive scan, don't change to active scan if - * you see any activity on the channel - remain passive. - */ - if (req->n_ssids > 0) { - cmd->passive2active = cpu_to_le16(1); - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } else { - cmd->passive2active = 0; - } - - iwl_mvm_scan_fill_ssids(cmd, req); - - cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); - cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; - cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); - cmd->tx_cmd.rate_n_flags = - iwl_mvm_scan_rate_n_flags(mvm, req->channels[0]->band, - req->no_cck); - - cmd->tx_cmd.len = - cpu_to_le16(iwl_mvm_fill_probe_req( - (struct ieee80211_mgmt *)cmd->data, - vif->addr, - req->n_ssids, ssid, ssid_len, - req->ie, req->ie_len, - mvm->fw->ucode_capa.max_probe_length)); - - iwl_mvm_scan_fill_channels(cmd, req); - - cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + - le16_to_cpu(cmd->tx_cmd.len) + - (cmd->channel_count * sizeof(struct iwl_scan_channel))); - hcmd.len[0] = le16_to_cpu(cmd->len); - - status = SCAN_RESPONSE_OK; - ret = iwl_mvm_send_cmd_status(mvm, &hcmd, &status); - if (!ret && status == SCAN_RESPONSE_OK) { - IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n"); - } else { - /* - * If the scan failed, it usually means that the FW was unable - * to allocate the time events. Warn on it, but maybe we - * should try to send the command again with different params. - */ - IWL_ERR(mvm, "Scan failed! status 0x%x ret %d\n", - status, ret); - mvm->scan_status = IWL_MVM_SCAN_NONE; - ret = -EIO; - } - return ret; -} - -int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_cmd_response *resp = (void *)pkt->data; - - IWL_DEBUG_SCAN(mvm, "Scan response received. status 0x%x\n", - le32_to_cpu(resp->status)); - return 0; -} - -int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_scan_complete_notif *notif = (void *)pkt->data; - - IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n", - notif->status, notif->scanned_channels); - - mvm->scan_status = IWL_MVM_SCAN_NONE; - ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK); - - return 0; -} - -static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, void *data) -{ - struct iwl_mvm *mvm = - container_of(notif_wait, struct iwl_mvm, notif_wait); - struct iwl_scan_complete_notif *notif; - u32 *resp; - - switch (pkt->hdr.cmd) { - case SCAN_ABORT_CMD: - resp = (void *)pkt->data; - if (*resp == CAN_ABORT_STATUS) { - IWL_DEBUG_SCAN(mvm, - "Scan can be aborted, wait until completion\n"); - return false; - } - - IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n", - *resp); - return true; - - case SCAN_COMPLETE_NOTIFICATION: - notif = (void *)pkt->data; - IWL_DEBUG_SCAN(mvm, "Scan aborted: status 0x%x\n", - notif->status); - return true; - - default: - WARN_ON(1); - return false; - }; -} - -void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) -{ - struct iwl_notification_wait wait_scan_abort; - static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, - SCAN_COMPLETE_NOTIFICATION }; - int ret; - - iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, - scan_abort_notif, - ARRAY_SIZE(scan_abort_notif), - iwl_mvm_scan_abort_notif, NULL); - - ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL); - if (ret) { - IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret); - goto out_remove_notif; - } - - ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ); - if (ret) - IWL_ERR(mvm, "%s - failed on timeout\n", __func__); - - return; - -out_remove_notif: - iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/sta.c b/trunk/drivers/net/wireless/iwlwifi/mvm/sta.c deleted file mode 100644 index 69603c3b2b39..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/sta.c +++ /dev/null @@ -1,1211 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 - -#include "mvm.h" -#include "sta.h" - -static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) -{ - int sta_id; - - WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); - - lockdep_assert_held(&mvm->mutex); - - /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ - for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) - if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex))) - return sta_id; - return IWL_MVM_STATION_COUNT; -} - -/* add a NEW station to fw */ -int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) -{ - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd add_sta_cmd; - int ret; - u32 status; - u32 agg_size = 0, mpdu_dens = 0; - - memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); - - add_sta_cmd.sta_id = mvm_sta->sta_id; - add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); - add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); - memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); - - /* STA_FLG_FAT_EN_MSK ? */ - /* STA_FLG_MIMO_EN_MSK ? */ - - if (sta->ht_cap.ht_supported) { - add_sta_cmd.station_flags_msk |= - cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK | - STA_FLG_AGG_MPDU_DENS_MSK); - - mpdu_dens = sta->ht_cap.ampdu_density; - } - - if (sta->vht_cap.vht_supported) { - agg_size = sta->vht_cap.cap & - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; - agg_size >>= - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; - } else if (sta->ht_cap.ht_supported) { - agg_size = sta->ht_cap.ampdu_factor; - } - - add_sta_cmd.station_flags |= - cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT); - add_sta_cmd.station_flags |= - cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); - - status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd), - &add_sta_cmd, &status); - if (ret) - return ret; - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n"); - break; - default: - ret = -EIO; - IWL_ERR(mvm, "ADD_STA failed\n"); - break; - } - - return ret; -} - -int iwl_mvm_add_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - int i, ret, sta_id; - - lockdep_assert_held(&mvm->mutex); - - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - sta_id = iwl_mvm_find_free_sta_id(mvm); - else - sta_id = mvm_sta->sta_id; - - if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) - return -ENOSPC; - - spin_lock_init(&mvm_sta->lock); - - mvm_sta->sta_id = sta_id; - mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color); - mvm_sta->vif = vif; - mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - - /* HW restart, don't assume the memory has been zeroed */ - atomic_set(&mvm_sta->pending_frames, 0); - mvm_sta->tid_disable_agg = 0; - mvm_sta->tfd_queue_msk = 0; - for (i = 0; i < IEEE80211_NUM_ACS; i++) - if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) - mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); - - if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) - mvm_sta->tfd_queue_msk |= BIT(vif->cab_queue); - - /* for HW restart - need to reset the seq_number etc... */ - memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); - - ret = iwl_mvm_sta_add_to_fw(mvm, sta); - if (ret) - return ret; - - /* The first station added is the AP, the others are TDLS STAs */ - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) - mvmvif->ap_sta_id = sta_id; - - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); - - return 0; -} - -int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, - bool drain) -{ - struct iwl_mvm_add_sta_cmd cmd = {}; - int ret; - u32 status; - - lockdep_assert_held(&mvm->mutex); - - cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color); - cmd.sta_id = mvmsta->sta_id; - cmd.add_modify = STA_MODE_MODIFY; - cmd.station_flags = drain ? cpu_to_le32(STA_FLG_DRAIN_FLOW) : 0; - cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW); - - status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), - &cmd, &status); - if (ret) - return ret; - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n", - mvmsta->sta_id); - break; - default: - ret = -EIO; - IWL_ERR(mvm, "Couldn't drain frames for staid %d\n", - mvmsta->sta_id); - break; - } - - return ret; -} - -/* - * Remove a station from the FW table. Before sending the command to remove - * the station validate that the station is indeed known to the driver (sanity - * only). - */ -static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_rm_sta_cmd rm_sta_cmd = { - .sta_id = sta_id, - }; - int ret; - - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - - /* Note: internal stations are marked as error values */ - if (!sta) { - IWL_ERR(mvm, "Invalid station id\n"); - return -EINVAL; - } - - ret = iwl_mvm_send_cmd_pdu(mvm, REMOVE_STA, CMD_SYNC, - sizeof(rm_sta_cmd), &rm_sta_cmd); - if (ret) { - IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id); - return ret; - } - - return 0; -} - -void iwl_mvm_sta_drained_wk(struct work_struct *wk) -{ - struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk); - u8 sta_id; - - /* - * The mutex is needed because of the SYNC cmd, but not only: if the - * work would run concurrently with iwl_mvm_rm_sta, it would run before - * iwl_mvm_rm_sta sets the station as busy, and exit. Then - * iwl_mvm_rm_sta would set the station as busy, and nobody will clean - * that later. - */ - mutex_lock(&mvm->mutex); - - for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) { - int ret; - struct ieee80211_sta *sta = - rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - - /* This station is in use */ - if (!IS_ERR(sta)) - continue; - - if (PTR_ERR(sta) == -EINVAL) { - IWL_ERR(mvm, "Drained sta %d, but it is internal?\n", - sta_id); - continue; - } - - if (!sta) { - IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n", - sta_id); - continue; - } - - WARN_ON(PTR_ERR(sta) != -EBUSY); - /* This station was removed and we waited until it got drained, - * we can now proceed and remove it. - */ - ret = iwl_mvm_rm_sta_common(mvm, sta_id); - if (ret) { - IWL_ERR(mvm, - "Couldn't remove sta %d after it was drained\n", - sta_id); - continue; - } - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); - clear_bit(sta_id, mvm->sta_drained); - } - - mutex_unlock(&mvm->mutex); -} - -int iwl_mvm_rm_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - int ret; - - lockdep_assert_held(&mvm->mutex); - - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id == mvm_sta->sta_id) { - /* - * Put a non-NULL since the fw station isn't removed. - * It will be removed after the MAC will be set as - * unassoc. - */ - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], - ERR_PTR(-EINVAL)); - - /* flush its queues here since we are freeing mvm_sta */ - ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true); - - /* if we are associated - we can't remove the AP STA now */ - if (vif->bss_conf.assoc) - return ret; - - /* unassoc - go ahead - remove the AP STA now */ - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - } - - /* - * There are frames pending on the AC queues for this station. - * We need to wait until all the frames are drained... - */ - if (atomic_read(&mvm_sta->pending_frames)) { - ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], - ERR_PTR(-EBUSY)); - } else { - ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); - rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); - } - - return ret; -} - -int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u8 sta_id) -{ - int ret = iwl_mvm_rm_sta_common(mvm, sta_id); - - lockdep_assert_held(&mvm->mutex); - - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL); - return ret; -} - -int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, - u32 qmask) -{ - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - sta->sta_id = iwl_mvm_find_free_sta_id(mvm); - if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) - return -ENOSPC; - } - - sta->tfd_queue_msk = qmask; - - /* put a non-NULL value so iterating over the stations won't stop */ - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], ERR_PTR(-EINVAL)); - return 0; -} - -void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) -{ - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL); - memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); - sta->sta_id = IWL_MVM_STATION_COUNT; -} - -static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta, - const u8 *addr, - u16 mac_id, u16 color) -{ - struct iwl_mvm_add_sta_cmd cmd; - int ret; - u32 status; - - lockdep_assert_held(&mvm->mutex); - - memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd)); - cmd.sta_id = sta->sta_id; - cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, - color)); - - cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); - - if (addr) - memcpy(cmd.addr, addr, ETH_ALEN); - - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), - &cmd, &status); - if (ret) - return ret; - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_INFO(mvm, "Internal station added.\n"); - return 0; - default: - ret = -EIO; - IWL_ERR(mvm, "Add internal station failed, status=0x%x\n", - status); - break; - } - return ret; -} - -int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) -{ - int ret; - - lockdep_assert_held(&mvm->mutex); - - /* Add the aux station, but without any queues */ - ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0); - if (ret) - return ret; - - ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL, - MAC_INDEX_AUX, 0); - - if (ret) - iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); - return ret; -} - -/* - * Send the add station command for the vif's broadcast station. - * Assumes that the station was already allocated. - * - * @mvm: the mvm component - * @vif: the interface to which the broadcast station is added - * @bsta: the broadcast station to add. - */ -int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - lockdep_assert_held(&mvm->mutex); - - if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT)) - return -ENOSPC; - - return iwl_mvm_add_int_sta_common(mvm, bsta, baddr, - mvmvif->id, mvmvif->color); -} - -/* Send the FW a request to remove the station from it's internal data - * structures, but DO NOT remove the entry from the local data structures. */ -int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *bsta) -{ - int ret; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); - if (ret) - IWL_WARN(mvm, "Failed sending remove station\n"); - return ret; -} - -/* Allocate a new station entry for the broadcast station to the given vif, - * and send it to the FW. - * Note that each P2P mac should have its own broadcast station. - * - * @mvm: the mvm component - * @vif: the interface to which the broadcast station is added - * @bsta: the broadcast station to add. */ -int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - u32 qmask; - int ret; - - lockdep_assert_held(&mvm->mutex); - - qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); - ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask); - if (ret) - return ret; - - ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, - mvmvif->id, mvmvif->color); - - if (ret) - iwl_mvm_dealloc_int_sta(mvm, bsta); - return ret; -} - -/* - * Send the FW a request to remove the station from it's internal data - * structures, and in addition remove it from the local data structure. - */ -int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta) -{ - int ret; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); - if (ret) - return ret; - - iwl_mvm_dealloc_int_sta(mvm, bsta); - return ret; -} - -int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, u16 ssn, bool start) -{ - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd cmd = {}; - int ret; - u32 status; - - lockdep_assert_held(&mvm->mutex); - - cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); - cmd.sta_id = mvm_sta->sta_id; - cmd.add_modify = STA_MODE_MODIFY; - cmd.add_immediate_ba_tid = (u8) tid; - cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); - cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID : - STA_MODIFY_REMOVE_BA_TID; - - status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), - &cmd, &status); - if (ret) - return ret; - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n", - start ? "start" : "stopp"); - break; - case ADD_STA_IMMEDIATE_BA_FAILURE: - IWL_WARN(mvm, "RX BA Session refused by fw\n"); - ret = -ENOSPC; - break; - default: - ret = -EIO; - IWL_ERR(mvm, "RX BA Session failed %sing, status 0x%x\n", - start ? "start" : "stopp", status); - break; - } - - return ret; -} - -static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, u8 queue, bool start) -{ - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd cmd = {}; - int ret; - u32 status; - - lockdep_assert_held(&mvm->mutex); - - if (start) { - mvm_sta->tfd_queue_msk |= BIT(queue); - mvm_sta->tid_disable_agg &= ~BIT(tid); - } else { - mvm_sta->tfd_queue_msk &= ~BIT(queue); - mvm_sta->tid_disable_agg |= BIT(tid); - } - - cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); - cmd.sta_id = mvm_sta->sta_id; - cmd.add_modify = STA_MODE_MODIFY; - cmd.modify_mask = STA_MODIFY_QUEUES | STA_MODIFY_TID_DISABLE_TX; - cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); - cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); - - status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), - &cmd, &status); - if (ret) - return ret; - - switch (status) { - case ADD_STA_SUCCESS: - break; - default: - ret = -EIO; - IWL_ERR(mvm, "TX BA Session failed %sing, status 0x%x\n", - start ? "start" : "stopp", status); - break; - } - - return ret; -} - -static const u8 tid_to_ac[] = { - IEEE80211_AC_BE, - IEEE80211_AC_BK, - IEEE80211_AC_BK, - IEEE80211_AC_BE, - IEEE80211_AC_VI, - IEEE80211_AC_VI, - IEEE80211_AC_VO, - IEEE80211_AC_VO, -}; - -int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) -{ - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - struct iwl_mvm_tid_data *tid_data; - int txq_id; - - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) - return -EINVAL; - - if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) { - IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n", - mvmsta->tid_data[tid].state); - return -ENXIO; - } - - lockdep_assert_held(&mvm->mutex); - - for (txq_id = IWL_MVM_FIRST_AGG_QUEUE; - txq_id <= IWL_MVM_LAST_AGG_QUEUE; txq_id++) - if (mvm->queue_to_mac80211[txq_id] == - IWL_INVALID_MAC80211_QUEUE) - break; - - if (txq_id > IWL_MVM_LAST_AGG_QUEUE) { - IWL_ERR(mvm, "Failed to allocate agg queue\n"); - return -EIO; - } - - /* the new tx queue is still connected to the same mac80211 queue */ - mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]]; - - spin_lock_bh(&mvmsta->lock); - tid_data = &mvmsta->tid_data[tid]; - tid_data->ssn = SEQ_TO_SN(tid_data->seq_number); - tid_data->txq_id = txq_id; - *ssn = tid_data->ssn; - - IWL_DEBUG_TX_QUEUES(mvm, - "Start AGG: sta %d tid %d queue %d - ssn = %d, next_recl = %d\n", - mvmsta->sta_id, tid, txq_id, tid_data->ssn, - tid_data->next_reclaimed); - - if (tid_data->ssn == tid_data->next_reclaimed) { - tid_data->state = IWL_AGG_STARTING; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - } else { - tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA; - } - - spin_unlock_bh(&mvmsta->lock); - - return 0; -} - -int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid, u8 buf_size) -{ - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - int queue, fifo, ret; - u16 ssn; - - buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); - - spin_lock_bh(&mvmsta->lock); - ssn = tid_data->ssn; - queue = tid_data->txq_id; - tid_data->state = IWL_AGG_ON; - tid_data->ssn = 0xffff; - spin_unlock_bh(&mvmsta->lock); - - fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]]; - - ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); - if (ret) - return -EIO; - - iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid, - buf_size, ssn); - - /* - * Even though in theory the peer could have different - * aggregation reorder buffer sizes for different sessions, - * our ucode doesn't allow for that and has a global limit - * for each station. Therefore, use the minimum of all the - * aggregation sessions and our default value. - */ - mvmsta->max_agg_bufsize = - min(mvmsta->max_agg_bufsize, buf_size); - mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize; - - if (mvm->cfg->ht_params->use_rts_for_aggregation) { - /* - * switch to RTS/CTS if it is the prefer protection - * method for HT traffic - */ - mvmsta->lq_sta.lq.flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; - /* - * TODO: remove the TLC_RTS flag when we tear down the last - * AGG session (agg_tids_count in DVM) - */ - } - - IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", - sta->addr, tid); - - return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false); -} - -int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid) -{ - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - u16 txq_id; - int err; - - spin_lock_bh(&mvmsta->lock); - - txq_id = tid_data->txq_id; - - IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n", - mvmsta->sta_id, tid, txq_id, tid_data->state); - - switch (tid_data->state) { - case IWL_AGG_ON: - tid_data->ssn = SEQ_TO_SN(tid_data->seq_number); - - IWL_DEBUG_TX_QUEUES(mvm, - "ssn = %d, next_recl = %d\n", - tid_data->ssn, tid_data->next_reclaimed); - - /* There are still packets for this RA / TID in the HW */ - if (tid_data->ssn != tid_data->next_reclaimed) { - tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA; - err = 0; - break; - } - - tid_data->ssn = 0xffff; - iwl_trans_txq_disable(mvm->trans, txq_id); - /* fall through */ - case IWL_AGG_STARTING: - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* - * The agg session has been stopped before it was set up. This - * can happen when the AddBA timer times out for example. - */ - - /* No barriers since we are under mutex */ - lockdep_assert_held(&mvm->mutex); - mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE; - - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - tid_data->state = IWL_AGG_OFF; - err = 0; - break; - default: - IWL_ERR(mvm, - "Stopping AGG while state not ON or starting for %d on %d (%d)\n", - mvmsta->sta_id, tid, tid_data->state); - IWL_ERR(mvm, - "\ttid_data->txq_id = %d\n", tid_data->txq_id); - err = -EINVAL; - } - - spin_unlock_bh(&mvmsta->lock); - - return err; -} - -static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) -{ - int i; - - lockdep_assert_held(&mvm->mutex); - - i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM); - - if (i == STA_KEY_MAX_NUM) - return STA_KEY_IDX_INVALID; - - __set_bit(i, mvm->fw_key_table); - - return i; -} - -static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; - - if (sta) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - - return mvm_sta->sta_id; - } - - /* - * The device expects GTKs for station interfaces to be - * installed as GTKs for the AP station. If we have no - * station ID, then use AP's station ID. - */ - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) - return mvmvif->ap_sta_id; - - return IWL_INVALID_STATION; -} - -static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvm_sta, - struct ieee80211_key_conf *keyconf, - u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, - u32 cmd_flags) -{ - __le16 key_flags; - struct iwl_mvm_add_sta_cmd cmd = {}; - int ret, status; - u16 keyidx; - int i; - - keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & - STA_KEY_FLG_KEYID_MSK; - key_flags = cpu_to_le16(keyidx); - key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP); - - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_TKIP: - key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); - cmd.key.tkip_rx_tsc_byte2 = tkip_iv32; - for (i = 0; i < 5; i++) - cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); - memcpy(cmd.key.key, keyconf->key, keyconf->keylen); - break; - case WLAN_CIPHER_SUITE_CCMP: - key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); - memcpy(cmd.key.key, keyconf->key, keyconf->keylen); - break; - default: - WARN_ON(1); - return -EINVAL; - } - - if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - key_flags |= cpu_to_le16(STA_KEY_MULTICAST); - - cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); - cmd.key.key_offset = keyconf->hw_key_idx; - cmd.key.key_flags = key_flags; - cmd.add_modify = STA_MODE_MODIFY; - cmd.modify_mask = STA_MODIFY_KEY; - cmd.sta_id = sta_id; - - status = ADD_STA_SUCCESS; - if (cmd_flags == CMD_SYNC) - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), - &cmd, &status); - else - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, - sizeof(cmd), &cmd); - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_WEP(mvm, "MODIFY_STA: set dynamic key passed\n"); - break; - default: - ret = -EIO; - IWL_ERR(mvm, "MODIFY_STA: set dynamic key failed\n"); - break; - } - - return ret; -} - -static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, - struct ieee80211_key_conf *keyconf, - u8 sta_id, bool remove_key) -{ - struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {}; - - /* verify the key details match the required command's expectations */ - if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) || - (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) || - (keyconf->keyidx != 4 && keyconf->keyidx != 5))) - return -EINVAL; - - igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx); - igtk_cmd.sta_id = cpu_to_le32(sta_id); - - if (remove_key) { - igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); - } else { - struct ieee80211_key_seq seq; - const u8 *pn; - - memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen); - ieee80211_aes_cmac_calculate_k1_k2(keyconf, - igtk_cmd.K1, igtk_cmd.K2); - ieee80211_get_key_rx_seq(keyconf, 0, &seq); - pn = seq.aes_cmac.pn; - igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) | - ((u64) pn[4] << 8) | - ((u64) pn[3] << 16) | - ((u64) pn[2] << 24) | - ((u64) pn[1] << 32) | - ((u64) pn[0] << 40)); - } - - IWL_DEBUG_INFO(mvm, "%s igtk for sta %u\n", - remove_key ? "removing" : "installing", - igtk_cmd.sta_id); - - return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, CMD_SYNC, - sizeof(igtk_cmd), &igtk_cmd); -} - - -static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; - - if (sta) - return sta->addr; - - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { - u8 sta_id = mvmvif->ap_sta_id; - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - return sta->addr; - } - - - return NULL; -} - -int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf, - bool have_key_offset) -{ - struct iwl_mvm_sta *mvm_sta; - int ret; - u8 *addr, sta_id; - struct ieee80211_key_seq seq; - u16 p1k[5]; - - lockdep_assert_held(&mvm->mutex); - - /* Get the station id from the mvm local station table */ - sta_id = iwl_mvm_get_key_sta_id(vif, sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_ERR(mvm, "Failed to find station id\n"); - return -EINVAL; - } - - if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); - goto end; - } - - /* - * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station table. - */ - if (!sta) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, "Invalid station id\n"); - return -EINVAL; - } - } - - mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; - if (WARN_ON_ONCE(mvm_sta->vif != vif)) - return -EINVAL; - - if (!have_key_offset) { - /* - * The D3 firmware hardcodes the PTK offset to 0, so we have to - * configure it there. As a result, this workaround exists to - * let the caller set the key offset (hw_key_idx), see d3.c. - */ - keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm); - if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) - return -ENOSPC; - } - - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_TKIP: - addr = iwl_mvm_get_mac_addr(mvm, vif, sta); - /* get phase 1 key from mac80211 */ - ieee80211_get_key_rx_seq(keyconf, 0, &seq); - ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, - seq.tkip.iv32, p1k, CMD_SYNC); - break; - case WLAN_CIPHER_SUITE_CCMP: - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, - 0, NULL, CMD_SYNC); - break; - default: - IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher); - ret = -EINVAL; - } - - if (ret) - __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); - -end: - IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", - keyconf->cipher, keyconf->keylen, keyconf->keyidx, - sta->addr, ret); - return ret; -} - -int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf) -{ - struct iwl_mvm_sta *mvm_sta; - struct iwl_mvm_add_sta_cmd cmd = {}; - __le16 key_flags; - int ret, status; - u8 sta_id; - - lockdep_assert_held(&mvm->mutex); - - /* Get the station id from the mvm local station table */ - sta_id = iwl_mvm_get_key_sta_id(vif, sta); - - IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", - keyconf->keyidx, sta_id); - - if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) - return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); - - ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); - if (!ret) { - IWL_ERR(mvm, "offset %d not used in fw key table.\n", - keyconf->hw_key_idx); - return -ENOENT; - } - - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); - return 0; - } - - /* - * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station table, - * for example when a GTK is removed (where the sta_id will then be - * the AP ID, and no station was passed by mac80211.) - */ - if (!sta) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (!sta) { - IWL_ERR(mvm, "Invalid station id\n"); - return -EINVAL; - } - } - - mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; - if (WARN_ON_ONCE(mvm_sta->vif != vif)) - return -EINVAL; - - key_flags = cpu_to_le16(keyconf->keyidx & STA_KEY_FLG_KEYID_MSK); - key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); - key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); - - if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - key_flags |= cpu_to_le16(STA_KEY_MULTICAST); - - cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); - cmd.key.key_flags = key_flags; - cmd.key.key_offset = keyconf->hw_key_idx; - cmd.sta_id = sta_id; - - cmd.modify_mask = STA_MODIFY_KEY; - cmd.add_modify = STA_MODE_MODIFY; - - status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), - &cmd, &status); - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); - break; - default: - ret = -EIO; - IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); - break; - } - - return ret; -} - -void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, u32 iv32, - u16 *phase1key) -{ - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); - - if (sta_id == IWL_INVALID_STATION) - return; - - iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, - iv32, phase1key, CMD_ASYNC); -} - -void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) -{ - struct iwl_mvm_add_sta_cmd cmd = { - .add_modify = STA_MODE_MODIFY, - .sta_id = sta_id, - .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, - .sleep_state_flags = cpu_to_le16(STA_SLEEP_STATE_AWAKE), - }; - int ret; - - /* - * Same modify mask for sleep_tx_count and sleep_state_flags but this - * should be fine since if we set the STA as "awake", then - * sleep_tx_count is not relevant. - */ - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); -} - -void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, int sta_id, - enum ieee80211_frame_release_type reason, - u16 cnt) -{ - u16 sleep_state_flags = - (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? - STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; - struct iwl_mvm_add_sta_cmd cmd = { - .add_modify = STA_MODE_MODIFY, - .sta_id = sta_id, - .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, - .sleep_tx_count = cpu_to_le16(cnt), - /* - * Same modify mask for sleep_tx_count and sleep_state_flags so - * we must set the sleep_state_flags too. - */ - .sleep_state_flags = cpu_to_le16(sleep_state_flags), - }; - int ret; - - /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/sta.h b/trunk/drivers/net/wireless/iwlwifi/mvm/sta.h deleted file mode 100644 index 1bf301097984..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/sta.h +++ /dev/null @@ -1,368 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __sta_h__ -#define __sta_h__ - -#include -#include -#include - -#include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */ -#include "fw-api.h" /* IWL_MVM_STATION_COUNT */ -#include "rs.h" - -struct iwl_mvm; - -/** - * DOC: station table - introduction - * - * The station table is a list of data structure that reprensent the stations. - * In STA/P2P client mode, the driver will hold one station for the AP/ GO. - * In GO/AP mode, the driver will have as many stations as associated clients. - * All these stations are reflected in the fw's station table. The driver - * keeps the fw's station table up to date with the ADD_STA command. Stations - * can be removed by the REMOVE_STA command. - * - * All the data related to a station is held in the structure %iwl_mvm_sta - * which is embed in the mac80211's %ieee80211_sta (in the drv_priv) area. - * This data includes the index of the station in the fw, per tid information - * (sequence numbers, Block-ack state machine, etc...). The stations are - * created and deleted by the %sta_state callback from %ieee80211_ops. - * - * The driver holds a map: %fw_id_to_mac_id that allows to fetch a - * %ieee80211_sta (and the %iwl_mvm_sta embedded into it) based on a fw - * station index. That way, the driver is able to get the tid related data in - * O(1) in time sensitive paths (Tx / Tx response / BA notification). These - * paths are triggered by the fw, and the driver needs to get a pointer to the - * %ieee80211 structure. This map helps to get that pointer quickly. - */ - -/** - * DOC: station table - locking - * - * As stated before, the station is created / deleted by mac80211's %sta_state - * callback from %ieee80211_ops which can sleep. The next paragraph explains - * the locking of a single stations, the next ones relates to the station - * table. - * - * The station holds the sequence number per tid. So this data needs to be - * accessed in the Tx path (which is softIRQ). It also holds the Block-Ack - * information (the state machine / and the logic that checks if the queues - * were drained), so it also needs to be accessible from the Tx response flow. - * In short, the station needs to be access from sleepable context as well as - * from tasklets, so the station itself needs a spinlock. - * - * The writers of %fw_id_to_mac_id map are serialized by the global mutex of - * the mvm op_mode. This is possible since %sta_state can sleep. - * The pointers in this map are RCU protected, hence we won't replace the - * station while we have Tx / Tx response / BA notification running. - * - * If a station is deleted while it still has packets in its A-MPDU queues, - * then the reclaim flow will notice that there is no station in the map for - * sta_id and it will dump the responses. - */ - -/** - * DOC: station table - internal stations - * - * The FW needs a few internal stations that are not reflected in - * mac80211, such as broadcast station in AP / GO mode, or AUX sta for - * scanning and P2P device (during the GO negotiation). - * For these kind of stations we have %iwl_mvm_int_sta struct which holds the - * data relevant for them from both %iwl_mvm_sta and %ieee80211_sta. - * Usually the data for these stations is static, so no locking is required, - * and no TID data as this is also not needed. - * One thing to note, is that these stations have an ID in the fw, but not - * in mac80211. In order to "reserve" them a sta_id in %fw_id_to_mac_id - * we fill ERR_PTR(EINVAL) in this mapping and all other dereferencing of - * pointers from this mapping need to check that the value is not error - * or NULL. - * - * Currently there is only one auxiliary station for scanning, initialized - * on init. - */ - -/** - * DOC: station table - AP Station in STA mode - * - * %iwl_mvm_vif includes the index of the AP station in the fw's STA table: - * %ap_sta_id. To get the point to the coresponsding %ieee80211_sta, - * &fw_id_to_mac_id can be used. Due to the way the fw works, we must not remove - * the AP station from the fw before setting the MAC context as unassociated. - * Hence, %fw_id_to_mac_id[%ap_sta_id] will be NULLed when the AP station is - * removed by mac80211, but the station won't be removed in the fw until the - * VIF is set as unassociated. Then, %ap_sta_id will be invalidated. - */ - -/** - * DOC: station table - Drain vs. Flush - * - * Flush means that all the frames in the SCD queue are dumped regardless the - * station to which they were sent. We do that when we disassociate and before - * we remove the STA of the AP. The flush can be done synchronously against the - * fw. - * Drain means that the fw will drop all the frames sent to a specific station. - * This is useful when a client (if we are IBSS / GO or AP) disassociates. In - * that case, we need to drain all the frames for that client from the AC queues - * that are shared with the other clients. Only then, we can remove the STA in - * the fw. In order to do so, we track the non-AMPDU packets for each station. - * If mac80211 removes a STA and if it still has non-AMPDU packets pending in - * the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all - * the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped - * (we know about it with its Tx response), we remove the station in fw and set - * it as %NULL in %fw_id_to_mac_id: this is the purpose of - * %iwl_mvm_sta_drained_wk. - */ - -/** - * DOC: station table - fw restart - * - * When the fw asserts, or we have any other issue that requires to reset the - * driver, we require mac80211 to reconfigure the driver. Since the private - * data of the stations is embed in mac80211's %ieee80211_sta, that data will - * not be zeroed and needs to be reinitialized manually. - * %IWL_MVM_STATUS_IN_HW_RESTART is set during restart and that will hint us - * that we must not allocate a new sta_id but reuse the previous one. This - * means that the stations being re-added after the reset will have the same - * place in the fw as before the reset. We do need to zero the %fw_id_to_mac_id - * map, since the stations aren't in the fw any more. Internal stations that - * are not added by mac80211 will be re-added in the init flow that is called - * after the restart: mac80211 call's %iwl_mvm_mac_start which calls to - * %iwl_mvm_up. - */ - -/** - * DOC: AP mode - PS - * - * When a station is asleep, the fw will set it as "asleep". All the - * non-aggregation frames to that station will be dropped by the fw - * (%TX_STATUS_FAIL_DEST_PS failure code). - * AMPDUs are in a separate queue that is stopped by the fw. We just need to - * let mac80211 know how many frames we have in these queues so that it can - * properly handle trigger frames. - * When the a trigger frame is received, mac80211 tells the driver to send - * frames from the AMPDU queues or AC queue depending on which queue are - * delivery-enabled and what TID has frames to transmit (Note that mac80211 has - * all the knowledege since all the non-agg frames are buffered / filtered, and - * the driver tells mac80211 about agg frames). The driver needs to tell the fw - * to let frames out even if the station is asleep. This is done by - * %iwl_mvm_sta_modify_sleep_tx_count. - * When we receive a frame from that station with PM bit unset, the - * driver needs to let the fw know that this station isn't alseep any more. - * This is done by %iwl_mvm_sta_modify_ps_wake. - * - * TODO - EOSP handling - */ - -/** - * enum iwl_mvm_agg_state - * - * The state machine of the BA agreement establishment / tear down. - * These states relate to a specific RA / TID. - * - * @IWL_AGG_OFF: aggregation is not used - * @IWL_AGG_STARTING: aggregation are starting (between start and oper) - * @IWL_AGG_ON: aggregation session is up - * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the - * HW queue to be empty from packets for this RA /TID. - * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the - * HW queue to be empty from packets for this RA /TID. - */ -enum iwl_mvm_agg_state { - IWL_AGG_OFF = 0, - IWL_AGG_STARTING, - IWL_AGG_ON, - IWL_EMPTYING_HW_QUEUE_ADDBA, - IWL_EMPTYING_HW_QUEUE_DELBA, -}; - -/** - * struct iwl_mvm_tid_data - holds the states for each RA / TID - * @seq_number: the next WiFi sequence number to use - * @next_reclaimed: the WiFi sequence number of the next packet to be acked. - * This is basically (last acked packet++). - * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the - * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). - * @state: state of the BA agreement establishment / tear down. - * @txq_id: Tx queue used by the BA session - * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or - * the first packet to be sent in legacy HW queue in Tx AGG stop flow. - * Basically when next_reclaimed reaches ssn, we can tell mac80211 that - * we are ready to finish the Tx AGG stop / start flow. - * @wait_for_ba: Expect block-ack before next Tx reply - */ -struct iwl_mvm_tid_data { - u16 seq_number; - u16 next_reclaimed; - /* The rest is Tx AGG related */ - u32 rate_n_flags; - enum iwl_mvm_agg_state state; - u16 txq_id; - u16 ssn; - bool wait_for_ba; -}; - -/** - * struct iwl_mvm_sta - representation of a station in the driver - * @sta_id: the index of the station in the fw (will be replaced by id_n_color) - * @tfd_queue_msk: the tfd queues used by the station - * @mac_id_n_color: the MAC context this station is linked to - * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for - * tid. - * @max_agg_bufsize: the maximal size of the AGG buffer for this station - * @lock: lock to protect the whole struct. Since %tid_data is access from Tx - * and from Tx response flow, it needs a spinlock. - * @pending_frames: number of frames for this STA on the shared Tx queues. - * @tid_data: per tid data. Look at %iwl_mvm_tid_data. - * - * When mac80211 creates a station it reserves some space (hw->sta_data_size) - * in the structure for use by driver. This structure is placed in that - * space. - * - */ -struct iwl_mvm_sta { - u32 sta_id; - u32 tfd_queue_msk; - u32 mac_id_n_color; - u16 tid_disable_agg; - u8 max_agg_bufsize; - spinlock_t lock; - atomic_t pending_frames; - struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; - struct iwl_lq_sta lq_sta; - struct ieee80211_vif *vif; - -#ifdef CONFIG_PM_SLEEP - u16 last_seq_ctl; -#endif -}; - -/** - * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or - * broadcast) - * @sta_id: the index of the station in the fw (will be replaced by id_n_color) - * @tfd_queue_msk: the tfd queues used by the station - */ -struct iwl_mvm_int_sta { - u32 sta_id; - u32 tfd_queue_msk; -}; - -int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta); -int iwl_mvm_add_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int iwl_mvm_rm_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u8 sta_id); -int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - bool have_key_offset); -int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf); - -void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, u32 iv32, - u16 *phase1key); - -/* AMPDU */ -int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, u16 ssn, bool start); -int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid, u16 *ssn); -int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid, u8 buf_size); -int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid); - -int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); -int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, - u32 qmask); -void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta); -int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta); -int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *bsta); -int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_int_sta *bsta); -int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta); -void iwl_mvm_sta_drained_wk(struct work_struct *wk); -void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id); -void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, int sta_id, - enum ieee80211_frame_release_type reason, - u16 cnt); -int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, - bool drain); - -#endif /* __sta_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/time-event.c b/trunk/drivers/net/wireless/iwlwifi/mvm/time-event.c deleted file mode 100644 index b9f076f4f17c..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ /dev/null @@ -1,569 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include - -#include "iwl-notif-wait.h" -#include "iwl-trans.h" -#include "fw-api.h" -#include "time-event.h" -#include "mvm.h" -#include "iwl-io.h" -#include "iwl-prph.h" - -/* A TimeUnit is 1024 microsecond */ -#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) -#define MSEC_TO_TU(_msec) (_msec*1000/1024) - -void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, - struct iwl_mvm_time_event_data *te_data) -{ - lockdep_assert_held(&mvm->time_event_lock); - - if (te_data->id == TE_MAX) - return; - - list_del(&te_data->list); - te_data->running = false; - te_data->uid = 0; - te_data->id = TE_MAX; - te_data->vif = NULL; -} - -void iwl_mvm_roc_done_wk(struct work_struct *wk) -{ - struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); - - synchronize_net(); - - /* - * Flush the offchannel queue -- this is called when the time - * event finishes or is cancelled, so that frames queued for it - * won't get stuck on the queue and be transmitted in the next - * time event. - * We have to send the command asynchronously since this cannot - * be under the mutex for locking reasons, but that's not an - * issue as it will have to complete before the next command is - * executed, and a new time event means a new command. - */ - iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false); -} - -static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) -{ - /* - * First, clear the ROC_RUNNING status bit. This will cause the TX - * path to drop offchannel transmissions. That would also be done - * by mac80211, but it is racy, in particular in the case that the - * time event actually completed in the firmware (which is handled - * in iwl_mvm_te_handle_notif). - */ - clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); - - /* - * Of course, our status bit is just as racy as mac80211, so in - * addition, fire off the work struct which will drop all frames - * from the hardware queues that made it through the race. First - * it will of course synchronize the TX path to make sure that - * any *new* TX will be rejected. - */ - schedule_work(&mvm->roc_done_wk); -} - -/* - * Handles a FW notification for an event that is known to the driver. - * - * @mvm: the mvm component - * @te_data: the time event data - * @notif: the notification data corresponding the time event data. - */ -static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, - struct iwl_mvm_time_event_data *te_data, - struct iwl_time_event_notif *notif) -{ - lockdep_assert_held(&mvm->time_event_lock); - - IWL_DEBUG_TE(mvm, "Handle time event notif - UID = 0x%x action %d\n", - le32_to_cpu(notif->unique_id), - le32_to_cpu(notif->action)); - - /* - * The FW sends the start/end time event notifications even for events - * that it fails to schedule. This is indicated in the status field of - * the notification. This happens in cases that the scheduler cannot - * find a schedule that can handle the event (for example requesting a - * P2P Device discoveribility, while there are other higher priority - * events in the system). - */ - WARN_ONCE(!le32_to_cpu(notif->status), - "Failed to schedule time event\n"); - - if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) { - IWL_DEBUG_TE(mvm, - "TE ended - current time %lu, estimated end %lu\n", - jiffies, te_data->end_jiffies); - - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { - ieee80211_remain_on_channel_expired(mvm->hw); - iwl_mvm_roc_finished(mvm); - } - - /* - * By now, we should have finished association - * and know the dtim period. - */ - if (te_data->vif->type == NL80211_IFTYPE_STATION && - (!te_data->vif->bss_conf.assoc || - !te_data->vif->bss_conf.dtim_period)) - IWL_ERR(mvm, - "No assocation and the time event is over already...\n"); - - iwl_mvm_te_clear_data(mvm, te_data); - } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { - te_data->running = true; - te_data->end_jiffies = jiffies + - TU_TO_JIFFIES(te_data->duration); - - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { - set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); - ieee80211_ready_on_channel(mvm->hw); - } - } else { - IWL_WARN(mvm, "Got TE with unknown action\n"); - } -} - -/* - * The Rx handler for time event notifications - */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_time_event_notif *notif = (void *)pkt->data; - struct iwl_mvm_time_event_data *te_data, *tmp; - - IWL_DEBUG_TE(mvm, "Time event notification - UID = 0x%x action %d\n", - le32_to_cpu(notif->unique_id), - le32_to_cpu(notif->action)); - - spin_lock_bh(&mvm->time_event_lock); - list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) { - if (le32_to_cpu(notif->unique_id) == te_data->uid) - iwl_mvm_te_handle_notif(mvm, te_data, notif); - } - spin_unlock_bh(&mvm->time_event_lock); - - return 0; -} - -static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, void *data) -{ - struct iwl_mvm *mvm = - container_of(notif_wait, struct iwl_mvm, notif_wait); - struct iwl_mvm_time_event_data *te_data = data; - struct ieee80211_vif *vif = te_data->vif; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_time_event_notif *notif; - struct iwl_time_event_resp *resp; - - u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); - - /* until we do something else */ - WARN_ON(te_data->id != TE_BSS_STA_AGGRESSIVE_ASSOC); - - switch (pkt->hdr.cmd) { - case TIME_EVENT_CMD: - resp = (void *)pkt->data; - /* TODO: I can't check that since the fw is buggy - it doesn't - * put the right values when we remove a TE. We can be here - * when we remove a TE because the remove TE command is sent in - * ASYNC... - * WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); - */ - te_data->uid = le32_to_cpu(resp->unique_id); - IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); - return false; - - case TIME_EVENT_NOTIFICATION: - notif = (void *)pkt->data; - WARN_ON(le32_to_cpu(notif->status) != 1); - WARN_ON(mac_id_n_color != le32_to_cpu(notif->id_and_color)); - /* check if this is our Time Event that is starting */ - if (le32_to_cpu(notif->unique_id) != te_data->uid) - return false; - IWL_DEBUG_TE(mvm, "Event %d is starting - time is %d\n", - te_data->uid, le32_to_cpu(notif->timestamp)); - - WARN_ONCE(!le32_to_cpu(notif->status), - "Failed to schedule protected session TE\n"); - - te_data->running = true; - te_data->end_jiffies = jiffies + - TU_TO_JIFFIES(te_data->duration); - return true; - - default: - WARN_ON(1); - return false; - }; -} - -void iwl_mvm_protect_session(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 min_duration) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - static const u8 time_event_notif[] = { TIME_EVENT_CMD, - TIME_EVENT_NOTIFICATION }; - struct iwl_notification_wait wait_time_event; - struct iwl_time_event_cmd time_cmd = {}; - int ret; - - lockdep_assert_held(&mvm->mutex); - - if (te_data->running && - time_after(te_data->end_jiffies, - jiffies + TU_TO_JIFFIES(min_duration))) { - IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", - jiffies_to_msecs(te_data->end_jiffies - jiffies)); - return; - } - - if (te_data->running) { - IWL_DEBUG_TE(mvm, "extend 0x%x: only %u ms left\n", - te_data->uid, - jiffies_to_msecs(te_data->end_jiffies - jiffies)); - /* - * we don't have enough time - * cancel the current TE and issue a new one - * Of course it would be better to remove the old one only - * when the new one is added, but we don't care if we are off - * channel for a bit. All we need to do, is not to return - * before we actually begin to be on the channel. - */ - iwl_mvm_stop_session_protection(mvm, vif); - } - - iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, - time_event_notif, - ARRAY_SIZE(time_event_notif), - iwl_mvm_time_event_notif, - &mvmvif->time_event_data); - - time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); - time_cmd.id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC); - - time_cmd.apply_time = - cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); - time_cmd.dep_policy = TE_INDEPENDENT; - time_cmd.is_present = cpu_to_le32(1); - time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); - time_cmd.max_delay = cpu_to_le32(500); - /* TODO: why do we need to interval = bi if it is not periodic? */ - time_cmd.interval = cpu_to_le32(1); - time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); - time_cmd.duration = cpu_to_le32(duration); - time_cmd.repeat = cpu_to_le32(1); - time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); - - te_data->vif = vif; - te_data->duration = duration; - - spin_lock_bh(&mvm->time_event_lock); - te_data->id = le32_to_cpu(time_cmd.id); - list_add_tail(&te_data->list, &mvm->time_event_list); - spin_unlock_bh(&mvm->time_event_lock); - - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, - sizeof(time_cmd), &time_cmd); - if (ret) { - IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); - goto out_remove_notif; - } - - ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); - if (ret) { - IWL_ERR(mvm, "%s - failed on timeout\n", __func__); - spin_lock_bh(&mvm->time_event_lock); - iwl_mvm_te_clear_data(mvm, te_data); - spin_unlock_bh(&mvm->time_event_lock); - } - - return; - -out_remove_notif: - iwl_remove_notification(&mvm->notif_wait, &wait_time_event); -} - -/* - * Explicit request to remove a time event. The removal of a time event needs to - * be synchronized with the flow of a time event's end notification, which also - * removes the time event from the op mode data structures. - */ -void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, - struct iwl_mvm_time_event_data *te_data) -{ - struct iwl_time_event_cmd time_cmd = {}; - u32 id, uid; - int ret; - - /* - * It is possible that by the time we got to this point the time - * event was already removed. - */ - spin_lock_bh(&mvm->time_event_lock); - - /* Save time event uid before clearing its data */ - uid = te_data->uid; - id = te_data->id; - - /* - * The clear_data function handles time events that were already removed - */ - iwl_mvm_te_clear_data(mvm, te_data); - spin_unlock_bh(&mvm->time_event_lock); - - /* - * It is possible that by the time we try to remove it, the time event - * has already ended and removed. In such a case there is no need to - * send a removal command. - */ - if (id == TE_MAX) { - IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid); - return; - } - - /* When we remove a TE, the UID is to be set in the id field */ - time_cmd.id = cpu_to_le32(uid); - time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); - time_cmd.id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - - IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_ASYNC, - sizeof(time_cmd), &time_cmd); - if (WARN_ON(ret)) - return; -} - -void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - - lockdep_assert_held(&mvm->mutex); - iwl_mvm_remove_time_event(mvm, mvmvif, te_data); -} - -static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, void *data) -{ - struct iwl_mvm *mvm = - container_of(notif_wait, struct iwl_mvm, notif_wait); - struct iwl_mvm_time_event_data *te_data = data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - struct iwl_time_event_resp *resp; - - u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); - - /* until we do something else */ - WARN_ON(te_data->id != TE_P2P_DEVICE_DISCOVERABLE); - - switch (pkt->hdr.cmd) { - case TIME_EVENT_CMD: - resp = (void *)pkt->data; - WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); - te_data->uid = le32_to_cpu(resp->unique_id); - IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); - return true; - - default: - WARN_ON(1); - return false; - }; -} - -int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - int duration) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - static const u8 roc_te_notif[] = { TIME_EVENT_CMD }; - struct iwl_notification_wait wait_time_event; - struct iwl_time_event_cmd time_cmd = {}; - int ret; - - lockdep_assert_held(&mvm->mutex); - if (te_data->running) { - IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n"); - return -EBUSY; - } - - /* - * Flush the done work, just in case it's still pending, so that - * the work it does can complete and we can accept new frames. - */ - flush_work(&mvm->roc_done_wk); - - iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, - roc_te_notif, - ARRAY_SIZE(roc_te_notif), - iwl_mvm_roc_te_notif, - &mvmvif->time_event_data); - - time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); - time_cmd.id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - time_cmd.id = cpu_to_le32(TE_P2P_DEVICE_DISCOVERABLE); - - time_cmd.apply_time = cpu_to_le32(0); - time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); - time_cmd.is_present = cpu_to_le32(1); - - time_cmd.interval = cpu_to_le32(1); - - /* - * TE_P2P_DEVICE_DISCOVERABLE can have lower priority than other events - * that are being scheduled by the driver/fw, and thus it might not be - * scheduled. To improve the chances of it being scheduled, allow it to - * be fragmented. - * In addition, for the same reasons, allow to delay the scheduling of - * the time event. - */ - time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); - time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); - time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); - time_cmd.repeat = cpu_to_le32(1); - time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); - - /* Push the te data to the tracked te list */ - te_data->vif = vif; - te_data->duration = MSEC_TO_TU(duration); - - spin_lock_bh(&mvm->time_event_lock); - te_data->id = le32_to_cpu(time_cmd.id); - list_add_tail(&te_data->list, &mvm->time_event_list); - spin_unlock_bh(&mvm->time_event_lock); - - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, - sizeof(time_cmd), &time_cmd); - if (ret) { - IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); - goto out_remove_notif; - } - - ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); - if (ret) { - IWL_ERR(mvm, "%s - failed on timeout\n", __func__); - iwl_mvm_te_clear_data(mvm, te_data); - } - - return ret; - -out_remove_notif: - iwl_remove_notification(&mvm->notif_wait, &wait_time_event); - return ret; -} - -void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) -{ - struct iwl_mvm_vif *mvmvif; - struct iwl_mvm_time_event_data *te_data; - - lockdep_assert_held(&mvm->mutex); - - /* - * Iterate over the list of time events and find the time event that is - * associated with a P2P_DEVICE interface. - * This assumes that a P2P_DEVICE interface can have only a single time - * event at any given time and this time event coresponds to a ROC - * request - */ - mvmvif = NULL; - spin_lock_bh(&mvm->time_event_lock); - list_for_each_entry(te_data, &mvm->time_event_list, list) { - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { - mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - break; - } - } - spin_unlock_bh(&mvm->time_event_lock); - - if (!mvmvif) { - IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n"); - return; - } - - iwl_mvm_remove_time_event(mvm, mvmvif, te_data); - - iwl_mvm_roc_finished(mvm); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/time-event.h b/trunk/drivers/net/wireless/iwlwifi/mvm/time-event.h deleted file mode 100644 index 64fb57a5ab43..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ /dev/null @@ -1,214 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 __time_event_h__ -#define __time_event_h__ - -#include "fw-api.h" - -#include "mvm.h" - -/** - * DOC: Time Events - what is it? - * - * Time Events are a fw feature that allows the driver to control the presence - * of the device on the channel. Since the fw supports multiple channels - * concurrently, the fw may choose to jump to another channel at any time. - * In order to make sure that the fw is on a specific channel at a certain time - * and for a certain duration, the driver needs to issue a time event. - * - * The simplest example is for BSS association. The driver issues a time event, - * waits for it to start, and only then tells mac80211 that we can start the - * association. This way, we make sure that the association will be done - * smoothly and won't be interrupted by channel switch decided within the fw. - */ - - /** - * DOC: The flow against the fw - * - * When the driver needs to make sure we are in a certain channel, at a certain - * time and for a certain duration, it sends a Time Event. The flow against the - * fw goes like this: - * 1) Driver sends a TIME_EVENT_CMD to the fw - * 2) Driver gets the response for that command. This response contains the - * Unique ID (UID) of the event. - * 3) The fw sends notification when the event starts. - * - * Of course the API provides various options that allow to cover parameters - * of the flow. - * What is the duration of the event? - * What is the start time of the event? - * Is there an end-time for the event? - * How much can the event be delayed? - * Can the event be split? - * If yes what is the maximal number of chunks? - * etc... - */ - -/** - * DOC: Abstraction to the driver - * - * In order to simplify the use of time events to the rest of the driver, - * we abstract the use of time events. This component provides the functions - * needed by the driver. - */ - -#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500 -#define IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400 - -/** - * iwl_mvm_protect_session - start / extend the session protection. - * @mvm: the mvm component - * @vif: the virtual interface for which the session is issued - * @duration: the duration of the session in TU. - * @min_duration: will start a new session if the current session will end - * in less than min_duration. - * - * This function can be used to start a session protection which means that the - * fw will stay on the channel for %duration_ms milliseconds. This function - * will block (sleep) until the session starts. This function can also be used - * to extend a currently running session. - * This function is meant to be used for BSS association for example, where we - * want to make sure that the fw stays on the channel during the association. - */ -void iwl_mvm_protect_session(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 min_duration); - -/** - * iwl_mvm_stop_session_protection - cancel the session protection. - * @mvm: the mvm component - * @vif: the virtual interface for which the session is issued - * - * This functions cancels the session protection which is an act of good - * citizenship. If it is not needed any more it should be cancelled because - * the other bindings wait for the medium during that time. - * This funtions doesn't sleep. - */ -void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); - -/* - * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION. - */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); - -/** - * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionlity - * @mvm: the mvm component - * @vif: the virtual interface for which the roc is requested. It is assumed - * that the vif type is NL80211_IFTYPE_P2P_DEVICE - * @duration: the requested duration in millisecond for the fw to be on the - * channel that is bound to the vif. - * - * This function can be used to issue a remain on channel session, - * which means that the fw will stay in the channel for the request %duration - * milliseconds. The function is async, meaning that it only issues the ROC - * request but does not wait for it to start. Once the FW is ready to serve the - * ROC request, it will issue a notification to the driver that it is on the - * requested channel. Once the FW completes the ROC request it will issue - * another notification to the driver. - */ -int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - int duration); - -/** - * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity - * @mvm: the mvm component - * - * This function can be used to cancel an ongoing ROC session. - * The function is async, it will instruct the FW to stop serving the ROC - * session, but will not wait for the actual stopping of the session. - */ -void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm); - -/** - * iwl_mvm_remove_time_event - general function to clean up of time event - * @mvm: the mvm component - * @vif: the vif to which the time event belongs - * @te_data: the time event data that corresponds to that time event - * - * This function can be used to cancel a time event regardless its type. - * It is useful for cleaning up time events running before removing an - * interface. - */ -void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, - struct iwl_mvm_time_event_data *te_data); - -/** - * iwl_mvm_te_clear_data - remove time event from list - * @mvm: the mvm component - * @te_data: the time event data to remove - * - * This function is mostly internal, it is made available here only - * for firmware restart purposes. - */ -void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, - struct iwl_mvm_time_event_data *te_data); - -void iwl_mvm_roc_done_wk(struct work_struct *wk); - -#endif /* __time_event_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/tx.c b/trunk/drivers/net/wireless/iwlwifi/mvm/tx.c deleted file mode 100644 index cada8efe0cca..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/tx.c +++ /dev/null @@ -1,916 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 -#include - -#include "iwl-trans.h" -#include "iwl-eeprom-parse.h" -#include "mvm.h" -#include "sta.h" - -/* - * Sets most of the Tx cmd's fields - */ -static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, - struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_info *info, u8 sta_id) -{ - struct ieee80211_hdr *hdr = (void *)skb->data; - __le16 fc = hdr->frame_control; - u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); - u32 len = skb->len + FCS_LEN; - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - tx_flags |= TX_CMD_FLG_ACK; - else - tx_flags &= ~TX_CMD_FLG_ACK; - - if (ieee80211_is_probe_resp(fc)) - tx_flags |= TX_CMD_FLG_TSF; - else if (ieee80211_is_back_req(fc)) - tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; - - /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ - if (info->band == IEEE80211_BAND_2GHZ && - (skb->protocol == cpu_to_be16(ETH_P_PAE) || - is_multicast_ether_addr(hdr->addr1) || - ieee80211_is_back_req(fc) || - ieee80211_is_mgmt(fc))) - tx_flags |= TX_CMD_FLG_BT_DIS; - - if (ieee80211_has_morefrags(fc)) - tx_flags |= TX_CMD_FLG_MORE_FRAG; - - if (ieee80211_is_data_qos(fc)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - tx_cmd->tid_tspec = qc[0] & 0xf; - tx_flags &= ~TX_CMD_FLG_SEQ_CTL; - } else { - tx_cmd->tid_tspec = IWL_TID_NON_QOS; - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) - tx_flags |= TX_CMD_FLG_SEQ_CTL; - else - tx_flags &= ~TX_CMD_FLG_SEQ_CTL; - } - - if (ieee80211_is_mgmt(fc)) { - if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx_cmd->pm_frame_timeout = cpu_to_le16(3); - else - tx_cmd->pm_frame_timeout = cpu_to_le16(2); - - /* The spec allows Action frames in A-MPDU, we don't support - * it - */ - WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); - } else { - tx_cmd->pm_frame_timeout = 0; - } - - if (info->flags & IEEE80211_TX_CTL_AMPDU) - tx_flags |= TX_CMD_FLG_PROT_REQUIRE; - - if (ieee80211_is_data(fc) && len > mvm->rts_threshold && - !is_multicast_ether_addr(ieee80211_get_DA(hdr))) - tx_flags |= TX_CMD_FLG_PROT_REQUIRE; - - tx_cmd->driver_txop = 0; - tx_cmd->tx_flags = cpu_to_le32(tx_flags); - /* Total # bytes to be transmitted */ - tx_cmd->len = cpu_to_le16((u16)skb->len); - tx_cmd->next_frame_len = 0; - tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); - tx_cmd->sta_id = sta_id; -} - -/* - * Sets the fields in the Tx cmd that are rate related - */ -static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, - struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, - __le16 fc) -{ - u32 rate_flags; - int rate_idx; - u8 rate_plcp; - - /* Set retry limit on RTS packets */ - tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; - - /* Set retry limit on DATA packets and Probe Responses*/ - if (ieee80211_is_probe_resp(fc)) { - tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; - tx_cmd->rts_retry_limit = - min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit); - } else if (ieee80211_is_back_req(fc)) { - tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; - } else { - tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY; - } - - /* - * for data packets, rate info comes from the table inside he fw. This - * table is controlled by LINK_QUALITY commands - */ - - if (ieee80211_is_data(fc)) { - tx_cmd->initial_rate_index = 0; - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); - return; - } else if (ieee80211_is_back_req(fc)) { - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); - } - - /* HT rate doesn't make sense for a non data frame */ - WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS, - "Got an HT rate for a non data frame 0x%x\n", - info->control.rates[0].flags); - - rate_idx = info->control.rates[0].idx; - /* if the rate isn't a well known legacy rate, take the lowest one */ - if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT_LEGACY) - rate_idx = rate_lowest_index( - &mvm->nvm_data->bands[info->band], sta); - - /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ - if (info->band == IEEE80211_BAND_5GHZ) - rate_idx += IWL_FIRST_OFDM_RATE; - - /* For 2.4 GHZ band, check that there is no need to remap */ - BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0); - - /* Get PLCP rate for tx_cmd->rate_n_flags */ - rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); - - mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, - mvm->mgmt_last_antenna_idx); - rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; - - /* Set CCK flag as needed */ - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - /* Set the rate in the TX cmd */ - tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags); -} - -/* - * Sets the fields in the Tx cmd that are crypto related - */ -static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, - struct iwl_tx_cmd *tx_cmd, - struct sk_buff *skb_frag) -{ - struct ieee80211_key_conf *keyconf = info->control.hw_key; - - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); - break; - - case WLAN_CIPHER_SUITE_TKIP: - tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); - break; - - case WLAN_CIPHER_SUITE_WEP104: - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - /* fall through */ - case WLAN_CIPHER_SUITE_WEP40: - tx_cmd->sec_ctl |= TX_CMD_SEC_WEP | - ((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) & - TX_CMD_SEC_WEP_KEY_IDX_MSK); - - memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); - break; - default: - IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher); - break; - } -} - -/* - * Allocates and sets the Tx cmd the driver data pointers in the skb - */ -static struct iwl_device_cmd * -iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 sta_id) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_device_cmd *dev_cmd; - struct iwl_tx_cmd *tx_cmd; - - dev_cmd = iwl_trans_alloc_tx_cmd(mvm->trans); - - if (unlikely(!dev_cmd)) - return NULL; - - memset(dev_cmd, 0, sizeof(*dev_cmd)); - tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; - - if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb); - - iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); - - iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); - - memset(&info->status, 0, sizeof(info->status)); - - info->driver_data[0] = NULL; - info->driver_data[1] = dev_cmd; - - return dev_cmd; -} - -int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_device_cmd *dev_cmd; - struct iwl_tx_cmd *tx_cmd; - u8 sta_id; - - if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU)) - return -1; - - if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && - (!info->control.vif || - info->hw_queue != info->control.vif->cab_queue))) - return -1; - - /* - * If the interface on which frame is sent is the P2P_DEVICE - * or an AP/GO interface use the broadcast station associated - * with it; otherwise use the AUX station. - */ - if (info->control.vif && - (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || - info->control.vif->type == NL80211_IFTYPE_AP)) { - struct iwl_mvm_vif *mvmvif = - iwl_mvm_vif_from_mac80211(info->control.vif); - sta_id = mvmvif->bcast_sta.sta_id; - } else { - sta_id = mvm->aux_sta.sta_id; - } - - IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); - - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); - if (!dev_cmd) - return -1; - - /* From now on, we cannot access info->control */ - tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; - - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); - - if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) { - iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); - return -1; - } - - return 0; -} - -/* - * Sets the fields in the Tx cmd that are crypto related - */ -int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_sta *sta) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_mvm_sta *mvmsta; - struct iwl_device_cmd *dev_cmd; - struct iwl_tx_cmd *tx_cmd; - __le16 fc; - u16 seq_number = 0; - u8 tid = IWL_MAX_TID_COUNT; - u8 txq_id = info->hw_queue; - bool is_data_qos = false, is_ampdu = false; - - mvmsta = (void *)sta->drv_priv; - fc = hdr->frame_control; - - if (WARN_ON_ONCE(!mvmsta)) - return -1; - - if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION)) - return -1; - - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); - if (!dev_cmd) - goto drop; - - tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; - /* From now on, we cannot access info->control */ - - spin_lock(&mvmsta->lock); - - if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { - u8 *qc = NULL; - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) - goto drop_unlock_sta; - - seq_number = mvmsta->tid_data[tid].seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(seq_number); - seq_number += 0x10; - is_data_qos = true; - is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; - } - - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc)); - - WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); - - if (is_ampdu) { - if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) - goto drop_unlock_sta; - txq_id = mvmsta->tid_data[tid].txq_id; - } - - IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id, - tid, txq_id, seq_number); - - /* NOTE: aggregation will need changes here (for txq id) */ - if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id)) - goto drop_unlock_sta; - - if (is_data_qos && !ieee80211_has_morefrags(fc)) - mvmsta->tid_data[tid].seq_number = seq_number; - - spin_unlock(&mvmsta->lock); - - if (mvmsta->vif->type == NL80211_IFTYPE_AP && - txq_id < IWL_FIRST_AMPDU_QUEUE) - atomic_inc(&mvmsta->pending_frames); - - return 0; - -drop_unlock_sta: - iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); - spin_unlock(&mvmsta->lock); -drop: - return -1; -} - -static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, u8 tid) -{ - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - struct ieee80211_vif *vif = mvmsta->vif; - - lockdep_assert_held(&mvmsta->lock); - - if (tid_data->ssn != tid_data->next_reclaimed) - return; - - switch (tid_data->state) { - case IWL_EMPTYING_HW_QUEUE_ADDBA: - IWL_DEBUG_TX_QUEUES(mvm, - "Can continue addBA flow ssn = next_recl = %d\n", - tid_data->next_reclaimed); - tid_data->state = IWL_AGG_STARTING; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - - case IWL_EMPTYING_HW_QUEUE_DELBA: - IWL_DEBUG_TX_QUEUES(mvm, - "Can continue DELBA flow ssn = next_recl = %d\n", - tid_data->next_reclaimed); - iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); - tid_data->state = IWL_AGG_OFF; - /* - * we can't hold the mutex - but since we are after a sequence - * point (call to iwl_trans_txq_disable), so we don't even need - * a memory barrier. - */ - mvm->queue_to_mac80211[tid_data->txq_id] = - IWL_INVALID_MAC80211_QUEUE; - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - - default: - break; - } -} - -#ifdef CONFIG_IWLWIFI_DEBUG -const char *iwl_mvm_get_tx_fail_reason(u32 status) -{ -#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x -#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x - - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_POSTPONE(DELAY); - TX_STATUS_POSTPONE(FEW_BYTES); - TX_STATUS_POSTPONE(BT_PRIO); - TX_STATUS_POSTPONE(QUIET_PERIOD); - TX_STATUS_POSTPONE(CALC_TTAK); - TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); - TX_STATUS_FAIL(SHORT_LIMIT); - TX_STATUS_FAIL(LONG_LIMIT); - TX_STATUS_FAIL(UNDERRUN); - TX_STATUS_FAIL(DRAIN_FLOW); - TX_STATUS_FAIL(RFKILL_FLUSH); - TX_STATUS_FAIL(LIFE_EXPIRE); - TX_STATUS_FAIL(DEST_PS); - TX_STATUS_FAIL(HOST_ABORTED); - TX_STATUS_FAIL(BT_RETRY); - TX_STATUS_FAIL(STA_INVALID); - TX_STATUS_FAIL(FRAG_DROPPED); - TX_STATUS_FAIL(TID_DISABLE); - TX_STATUS_FAIL(FIFO_FLUSHED); - TX_STATUS_FAIL(SMALL_CF_POLL); - TX_STATUS_FAIL(FW_DROP); - TX_STATUS_FAIL(STA_COLOR_MISMATCH); - } - - return "UNKNOWN"; - -#undef TX_STATUS_FAIL -#undef TX_STATUS_POSTPONE -} -#endif /* CONFIG_IWLWIFI_DEBUG */ - -/** - * translate ucode response to mac80211 tx status control values - */ -static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags, - struct ieee80211_tx_info *info) -{ - struct ieee80211_tx_rate *r = &info->status.rates[0]; - - info->status.antenna = - ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); - if (rate_n_flags & RATE_HT_MCS_GF_MSK) - r->flags |= IEEE80211_TX_RC_GREEN_FIELD; - switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { - case RATE_MCS_CHAN_WIDTH_20: - break; - case RATE_MCS_CHAN_WIDTH_40: - r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - break; - case RATE_MCS_CHAN_WIDTH_80: - r->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; - break; - case RATE_MCS_CHAN_WIDTH_160: - r->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH; - break; - } - if (rate_n_flags & RATE_MCS_SGI_MSK) - r->flags |= IEEE80211_TX_RC_SHORT_GI; - if (rate_n_flags & RATE_MCS_HT_MSK) { - r->flags |= IEEE80211_TX_RC_MCS; - r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; - } else if (rate_n_flags & RATE_MCS_VHT_MSK) { - ieee80211_rate_set_vht( - r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK, - ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> - RATE_VHT_MCS_NSS_POS) + 1); - r->flags |= IEEE80211_TX_RC_VHT_MCS; - } else { - r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, - info->band); - } -} - -static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) -{ - struct ieee80211_sta *sta; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; - int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); - int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); - u32 status = le16_to_cpu(tx_resp->status.status); - u16 ssn = iwl_mvm_get_scd_ssn(tx_resp); - struct iwl_mvm_sta *mvmsta; - struct sk_buff_head skbs; - u8 skb_freed = 0; - u16 next_reclaimed, seq_ctl; - - __skb_queue_head_init(&skbs); - - seq_ctl = le16_to_cpu(tx_resp->seq_ctl); - - /* we can free until ssn % q.n_bd not inclusive */ - iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs); - - while (!skb_queue_empty(&skbs)) { - struct sk_buff *skb = __skb_dequeue(&skbs); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - skb_freed++; - - iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); - - memset(&info->status, 0, sizeof(info->status)); - - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - - /* inform mac80211 about what happened with the frame */ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - case TX_STATUS_DIRECT_DONE: - info->flags |= IEEE80211_TX_STAT_ACK; - break; - case TX_STATUS_FAIL_DEST_PS: - info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - break; - default: - break; - } - - info->status.rates[0].count = tx_resp->failure_frame + 1; - iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate), - info); - - /* Single frame failure in an AMPDU queue => send BAR */ - if (txq_id >= IWL_FIRST_AMPDU_QUEUE && - !(info->flags & IEEE80211_TX_STAT_ACK)) { - /* there must be only one skb in the skb_list */ - WARN_ON_ONCE(skb_freed > 1 || - !skb_queue_empty(&skbs)); - info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - } - - /* W/A FW bug: seq_ctl is wrong when the queue is flushed */ - if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { - struct ieee80211_hdr *hdr = (void *)skb->data; - seq_ctl = le16_to_cpu(hdr->seq_ctrl); - } - - ieee80211_tx_status(mvm->hw, skb); - } - - if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { - /* If this is an aggregation queue, we use the ssn since: - * ssn = wifi seq_num % 256. - * The seq_ctl is the sequence control of the packet to which - * this Tx response relates. But if there is a hole in the - * bitmap of the BA we received, this Tx response may allow to - * reclaim the hole and all the subsequent packets that were - * already acked. In that case, seq_ctl != ssn, and the next - * packet to be reclaimed will be ssn and not seq_ctl. In that - * case, several packets will be reclaimed even if - * frame_count = 1. - * - * The ssn is the index (% 256) of the latest packet that has - * treated (acked / dropped) + 1. - */ - next_reclaimed = ssn; - } else { - /* The next packet to be reclaimed is the one after this one */ - next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10); - } - - IWL_DEBUG_TX_REPLY(mvm, - "TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x " - "retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n", - txq_id, iwl_mvm_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->initial_rate), - tx_resp->failure_frame, SEQ_TO_INDEX(sequence), - ssn, next_reclaimed, seq_ctl); - - rcu_read_lock(); - - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - - if (!IS_ERR_OR_NULL(sta)) { - mvmsta = (void *)sta->drv_priv; - - if (tid != IWL_TID_NON_QOS) { - struct iwl_mvm_tid_data *tid_data = - &mvmsta->tid_data[tid]; - - spin_lock(&mvmsta->lock); - tid_data->next_reclaimed = next_reclaimed; - IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", - next_reclaimed); - iwl_mvm_check_ratid_empty(mvm, sta, tid); - spin_unlock(&mvmsta->lock); - } - -#ifdef CONFIG_PM_SLEEP - mvmsta->last_seq_ctl = seq_ctl; -#endif - } else { - sta = NULL; - mvmsta = NULL; - } - - /* - * If the txq is not an AMPDU queue, there is no chance we freed - * several skbs. Check that out... - * If there are no pending frames for this STA, notify mac80211 that - * this station can go to sleep in its STA table. - */ - if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta && - !WARN_ON(skb_freed > 1) && - mvmsta->vif->type == NL80211_IFTYPE_AP && - atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { - ieee80211_sta_block_awake(mvm->hw, sta, false); - set_bit(sta_id, mvm->sta_drained); - schedule_work(&mvm->sta_drained_wk); - } - - rcu_read_unlock(); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -#define AGG_TX_STATE_(x) case AGG_TX_STATE_ ## x: return #x -static const char *iwl_get_agg_tx_status(u16 status) -{ - switch (status & AGG_TX_STATE_STATUS_MSK) { - AGG_TX_STATE_(TRANSMITTED); - AGG_TX_STATE_(UNDERRUN); - AGG_TX_STATE_(BT_PRIO); - AGG_TX_STATE_(FEW_BYTES); - AGG_TX_STATE_(ABORT); - AGG_TX_STATE_(LAST_SENT_TTL); - AGG_TX_STATE_(LAST_SENT_TRY_CNT); - AGG_TX_STATE_(LAST_SENT_BT_KILL); - AGG_TX_STATE_(SCD_QUERY); - AGG_TX_STATE_(TEST_BAD_CRC32); - AGG_TX_STATE_(RESPONSE); - AGG_TX_STATE_(DUMP_TX); - AGG_TX_STATE_(DELAY_TX); - } - - return "UNKNOWN"; -} - -static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) -{ - struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; - struct agg_tx_status *frame_status = &tx_resp->status; - int i; - - for (i = 0; i < tx_resp->frame_count; i++) { - u16 fstatus = le16_to_cpu(frame_status[i].status); - - IWL_DEBUG_TX_REPLY(mvm, - "status %s (0x%04x), try-count (%d) seq (0x%x)\n", - iwl_get_agg_tx_status(fstatus), - fstatus & AGG_TX_STATE_STATUS_MSK, - (fstatus & AGG_TX_STATE_TRY_CNT_MSK) >> - AGG_TX_STATE_TRY_CNT_POS, - le16_to_cpu(frame_status[i].sequence)); - } -} -#else -static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) -{} -#endif /* CONFIG_IWLWIFI_DEBUG */ - -static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) -{ - struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; - int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); - int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - struct ieee80211_sta *sta; - - if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE)) - return; - - if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) - return; - - iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt); - - rcu_read_lock(); - - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - - if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { - struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; - mvmsta->tid_data[tid].rate_n_flags = - le32_to_cpu(tx_resp->initial_rate); - } - - rcu_read_unlock(); -} - -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; - - if (tx_resp->frame_count == 1) - iwl_mvm_rx_tx_cmd_single(mvm, pkt); - else - iwl_mvm_rx_tx_cmd_agg(mvm, pkt); - - return 0; -} - -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; - struct sk_buff_head reclaimed_skbs; - struct iwl_mvm_tid_data *tid_data; - struct ieee80211_tx_info *info; - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - struct ieee80211_hdr *hdr; - struct sk_buff *skb; - int sta_id, tid, freed; - - /* "flow" corresponds to Tx queue */ - u16 scd_flow = le16_to_cpu(ba_notif->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_notif->scd_ssn); - - sta_id = ba_notif->sta_id; - tid = ba_notif->tid; - - rcu_read_lock(); - - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - - /* Reclaiming frames for a station that has been deleted ? */ - if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { - rcu_read_unlock(); - return 0; - } - - mvmsta = (void *)sta->drv_priv; - tid_data = &mvmsta->tid_data[tid]; - - if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d", - tid_data->txq_id, tid, scd_flow)) { - rcu_read_unlock(); - return 0; - } - - spin_lock(&mvmsta->lock); - - __skb_queue_head_init(&reclaimed_skbs); - - /* - * 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). - */ - iwl_trans_reclaim(mvm->trans, scd_flow, ba_resp_scd_ssn, - &reclaimed_skbs); - - IWL_DEBUG_TX_REPLY(mvm, - "BA_NOTIFICATION Received from %pM, sta_id = %d\n", - (u8 *)&ba_notif->sta_addr_lo32, - ba_notif->sta_id); - IWL_DEBUG_TX_REPLY(mvm, - "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n", - ba_notif->tid, le16_to_cpu(ba_notif->seq_ctl), - (unsigned long long)le64_to_cpu(ba_notif->bitmap), - scd_flow, ba_resp_scd_ssn, ba_notif->txed, - ba_notif->txed_2_done); - - tid_data->next_reclaimed = ba_resp_scd_ssn; - - iwl_mvm_check_ratid_empty(mvm, sta, tid); - - freed = 0; - - skb_queue_walk(&reclaimed_skbs, skb) { - hdr = (struct ieee80211_hdr *)skb->data; - - if (ieee80211_is_data_qos(hdr->frame_control)) - freed++; - else - WARN_ON_ONCE(1); - - info = IEEE80211_SKB_CB(skb); - iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); - - if (freed == 1) { - /* this is the first skb we deliver in this batch */ - /* put the rate scaling data there */ - info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; - info->flags |= IEEE80211_TX_STAT_AMPDU; - info->status.ampdu_ack_len = ba_notif->txed_2_done; - info->status.ampdu_len = ba_notif->txed; - iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags, - info); - } - } - - spin_unlock(&mvmsta->lock); - - rcu_read_unlock(); - - while (!skb_queue_empty(&reclaimed_skbs)) { - skb = __skb_dequeue(&reclaimed_skbs); - ieee80211_tx_status(mvm->hw, skb); - } - - return 0; -} - -int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync) -{ - int ret; - struct iwl_tx_path_flush_cmd flush_cmd = { - .queues_ctl = cpu_to_le32(tfd_msk), - .flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH), - }; - - u32 flags = sync ? CMD_SYNC : CMD_ASYNC; - - ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags, - sizeof(flush_cmd), &flush_cmd); - if (ret) - IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret); - return ret; -} diff --git a/trunk/drivers/net/wireless/iwlwifi/mvm/utils.c b/trunk/drivers/net/wireless/iwlwifi/mvm/utils.c deleted file mode 100644 index 000e842c2edd..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/mvm/utils.c +++ /dev/null @@ -1,472 +0,0 @@ -/****************************************************************************** - * - * 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) 2012 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2013 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 - -#include "iwl-debug.h" -#include "iwl-io.h" - -#include "mvm.h" -#include "fw-api-rs.h" - -/* - * Will return 0 even if the cmd failed when RFKILL is asserted unless - * CMD_WANT_SKB is set in cmd->flags. - */ -int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) -{ - int ret; - - /* - * Synchronous commands from this op-mode must hold - * the mutex, this ensures we don't try to send two - * (or more) synchronous commands at a time. - */ - if (!(cmd->flags & CMD_ASYNC)) - lockdep_assert_held(&mvm->mutex); - - ret = iwl_trans_send_cmd(mvm->trans, cmd); - - /* - * If the caller wants the SKB, then don't hide any problems, the - * caller might access the response buffer which will be NULL if - * the command failed. - */ - if (cmd->flags & CMD_WANT_SKB) - return ret; - - /* Silently ignore failures if RFKILL is asserted */ - if (!ret || ret == -ERFKILL) - return 0; - return ret; -} - -int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, - u32 flags, u16 len, const void *data) -{ - struct iwl_host_cmd cmd = { - .id = id, - .len = { len, }, - .data = { data, }, - .flags = flags, - }; - - return iwl_mvm_send_cmd(mvm, &cmd); -} - -/* - * We assume that the caller set the status to the sucess value - */ -int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, - u32 *status) -{ - struct iwl_rx_packet *pkt; - struct iwl_cmd_response *resp; - int ret, resp_len; - - lockdep_assert_held(&mvm->mutex); - - /* - * Only synchronous commands can wait for status, - * we use WANT_SKB so the caller can't. - */ - if (WARN_ONCE(cmd->flags & (CMD_ASYNC | CMD_WANT_SKB), - "cmd flags %x", cmd->flags)) - return -EINVAL; - - cmd->flags |= CMD_SYNC | CMD_WANT_SKB; - - ret = iwl_trans_send_cmd(mvm->trans, cmd); - if (ret == -ERFKILL) { - /* - * The command failed because of RFKILL, don't update - * the status, leave it as success and return 0. - */ - return 0; - } else if (ret) { - return ret; - } - - pkt = cmd->resp_pkt; - /* Can happen if RFKILL is asserted */ - if (!pkt) { - ret = 0; - goto out_free_resp; - } - - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - ret = -EIO; - goto out_free_resp; - } - - resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) { - ret = -EIO; - goto out_free_resp; - } - - resp = (void *)pkt->data; - *status = le32_to_cpu(resp->status); - out_free_resp: - iwl_free_resp(cmd); - return ret; -} - -/* - * We assume that the caller set the status to the sucess value - */ -int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len, - const void *data, u32 *status) -{ - struct iwl_host_cmd cmd = { - .id = id, - .len = { len, }, - .data = { data, }, - }; - - return iwl_mvm_send_cmd_status(mvm, &cmd, status); -} - -#define IWL_DECLARE_RATE_INFO(r) \ - [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP - -/* - * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP - */ -static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = { - IWL_DECLARE_RATE_INFO(1), - IWL_DECLARE_RATE_INFO(2), - IWL_DECLARE_RATE_INFO(5), - IWL_DECLARE_RATE_INFO(11), - IWL_DECLARE_RATE_INFO(6), - IWL_DECLARE_RATE_INFO(9), - IWL_DECLARE_RATE_INFO(12), - IWL_DECLARE_RATE_INFO(18), - IWL_DECLARE_RATE_INFO(24), - IWL_DECLARE_RATE_INFO(36), - IWL_DECLARE_RATE_INFO(48), - IWL_DECLARE_RATE_INFO(54), -}; - -int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, - enum ieee80211_band band) -{ - int rate = rate_n_flags & RATE_LEGACY_RATE_MSK; - int idx; - int band_offset = 0; - - /* Legacy rate format, search for match in table */ - if (band == IEEE80211_BAND_5GHZ) - band_offset = IWL_FIRST_OFDM_RATE; - for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) - if (fw_rate_idx_to_plcp[idx] == rate) - return idx - band_offset; - - return -1; -} - -u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx) -{ - /* Get PLCP rate for tx_cmd->rate_n_flags */ - return fw_rate_idx_to_plcp[rate_idx]; -} - -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_error_resp *err_resp = (void *)pkt->data; - - IWL_ERR(mvm, "FW Error notification: type 0x%08X cmd_id 0x%02X\n", - le32_to_cpu(err_resp->error_type), err_resp->cmd_id); - IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n", - le16_to_cpu(err_resp->bad_cmd_seq_num), - le32_to_cpu(err_resp->error_service)); - IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n", - le64_to_cpu(err_resp->timestamp)); - return 0; -} - -/* - * Returns the first antenna as ANT_[ABC], as defined in iwl-config.h. - * The parameter should also be a combination of ANT_[ABC]. - */ -u8 first_antenna(u8 mask) -{ - BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */ - WARN_ON_ONCE(!mask); /* ffs will return 0 if mask is zeroed */ - return (u8)(BIT(ffs(mask))); -} - -/* - * Toggles between TX antennas to send the probe request on. - * Receives the bitmask of valid TX antennas and the *index* used - * for the last TX, and returns the next valid *index* to use. - * In order to set it in the tx_cmd, must do BIT(idx). - */ -u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) -{ - u8 ind = last_idx; - int i; - - for (i = 0; i < RATE_MCS_ANT_NUM; i++) { - ind = (ind + 1) % RATE_MCS_ANT_NUM; - if (valid & BIT(ind)) - return ind; - } - - WARN_ONCE(1, "Failed to toggle between antennas 0x%x", valid); - return last_idx; -} - -static struct { - char *name; - u8 num; -} advanced_lookup[] = { - { "NMI_INTERRUPT_WDG", 0x34 }, - { "SYSASSERT", 0x35 }, - { "UCODE_VERSION_MISMATCH", 0x37 }, - { "BAD_COMMAND", 0x38 }, - { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, - { "FATAL_ERROR", 0x3D }, - { "NMI_TRM_HW_ERR", 0x46 }, - { "NMI_INTERRUPT_TRM", 0x4C }, - { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, - { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, - { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, - { "NMI_INTERRUPT_HOST", 0x66 }, - { "NMI_INTERRUPT_ACTION_PT", 0x7C }, - { "NMI_INTERRUPT_UNKNOWN", 0x84 }, - { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, - { "ADVANCED_SYSASSERT", 0 }, -}; - -static const char *desc_lookup(u32 num) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(advanced_lookup) - 1; i++) - if (advanced_lookup[i].num == num) - return advanced_lookup[i].name; - - /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */ - return advanced_lookup[i].name; -} - -/* - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 pc; /* program counter */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 gp3; /* GP3 timer register */ - u32 ucode_ver; /* uCode version */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed; - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_error_event_table table; - u32 base; - - base = mvm->error_event_table; - if (mvm->cur_ucode == IWL_UCODE_INIT) { - if (!base) - base = mvm->fw->init_errlog_ptr; - } else { - if (!base) - base = mvm->fw->inst_errlog_ptr; - } - - if (base < 0x800000 || base >= 0x80C000) { - IWL_ERR(mvm, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (mvm->cur_ucode == IWL_UCODE_INIT) - ? "Init" : "RT"); - return; - } - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, - table.data1, table.data2, table.data3, - table.blink1, table.blink2, table.ilink1, - table.ilink2, table.bcon_time, table.gp1, - table.gp2, table.gp3, table.ucode_ver, - table.hw_ver, table.brd_ver); - IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, - desc_lookup(table.error_id)); - IWL_ERR(mvm, "0x%08X | uPc\n", table.pc); - IWL_ERR(mvm, "0x%08X | branchlink1\n", table.blink1); - IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time); - IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low); - IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi); - IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1); - IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(mvm, "0x%08X | time gp3\n", table.gp3); - IWL_ERR(mvm, "0x%08X | uCode version\n", table.ucode_ver); - IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver); - IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver); - IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd); - IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0); - IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1); - IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2); - IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3); - IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4); - IWL_ERR(mvm, "0x%08X | isr_pref\n", table.isr_pref); - IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event); - IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control); - IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration); - IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); - IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); - IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); - IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); - IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); -} - -/** - * iwl_mvm_send_lq_cmd() - Send link quality command - * @init: This command is sent as part of station initialization right - * after station has been added. - * - * The link quality command is sent as the last step of station creation. - * This is the special case in which init is set and we call a callback in - * this case to clear the state indicating that station creation is in - * progress. - */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, - u8 flags, bool init) -{ - struct iwl_host_cmd cmd = { - .id = LQ_CMD, - .len = { sizeof(struct iwl_lq_cmd), }, - .flags = flags, - .data = { lq, }, - }; - - if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) - return -EINVAL; - - if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) - return -EINVAL; - - return iwl_mvm_send_cmd(mvm, &cmd); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/1000.c b/trunk/drivers/net/wireless/iwlwifi/pcie/1000.c index ff3389757281..f8620ecae6b4 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/1000.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/2000.c b/trunk/drivers/net/wireless/iwlwifi/pcie/2000.c index e7de33128b16..244019cec3e1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/2000.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/2000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/5000.c b/trunk/drivers/net/wireless/iwlwifi/pcie/5000.c index 5096f7c96ab6..83ca40321ff1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/5000.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/6000.c b/trunk/drivers/net/wireless/iwlwifi/pcie/6000.c index 801ff49796dd..d4df976d4709 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/6000.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2012 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 diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/7000.c b/trunk/drivers/net/wireless/iwlwifi/pcie/7000.c deleted file mode 100644 index 6e35b2b72332..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/7000.c +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2008 - 2013 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: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" -#include "cfg.h" - -/* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 6 -#define IWL3160_UCODE_API_MAX 6 - -/* Oldest version we won't warn about */ -#define IWL7260_UCODE_API_OK 6 -#define IWL3160_UCODE_API_OK 6 - -/* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN 6 -#define IWL3160_UCODE_API_MIN 6 - -/* NVM versions */ -#define IWL7260_NVM_VERSION 0x0a1d -#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ -#define IWL3160_NVM_VERSION 0x709 -#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ - -#define IWL7260_FW_PRE "iwlwifi-7260-" -#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" - -#define IWL3160_FW_PRE "iwlwifi-3160-" -#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" - -static const struct iwl_base_params iwl7000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .pll_cfg_val = 0, - .shadow_ram_support = true, - .led_compensation = 57, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1000, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ -}; - -static const struct iwl_ht_params iwl7000_ht_params = { - .ht_greenfield_support = true, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), -}; - -#define IWL_DEVICE_7000 \ - .ucode_api_max = IWL7260_UCODE_API_MAX, \ - .ucode_api_ok = IWL7260_UCODE_API_OK, \ - .ucode_api_min = IWL7260_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_7000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .base_params = &iwl7000_base_params, \ - /* TODO: .bt_params? */ \ - .need_temp_offset_calib = true, \ - .led_mode = IWL_LED_RF_STATE, \ - .adv_pm = true \ - - -const struct iwl_cfg iwl7260_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC7260", - .fw_name_pre = IWL7260_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, -}; - -const struct iwl_cfg iwl3160_ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC3160", - .fw_name_pre = IWL3160_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, -}; - -MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); -MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/cfg.h b/trunk/drivers/net/wireless/iwlwifi/pcie/cfg.h index c6f8e83c3551..82152311d73b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/cfg.h +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/cfg.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -109,7 +109,5 @@ extern const struct iwl_cfg iwl6035_2agn_cfg; extern const struct iwl_cfg iwl105_bgn_cfg; extern const struct iwl_cfg iwl105_bgn_d_cfg; extern const struct iwl_cfg iwl135_bgn_cfg; -extern const struct iwl_cfg iwl7260_2ac_cfg; -extern const struct iwl_cfg iwl3160_ac_cfg; #endif /* __iwl_pci_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/drv.c b/trunk/drivers/net/wireless/iwlwifi/pcie/drv.c index 7bc0fb9128dd..c2e141af353c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -255,12 +255,6 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, -/* 7000 Series */ - {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)}, - {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)}, - {0} }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/internal.h b/trunk/drivers/net/wireless/iwlwifi/pcie/internal.h index 5f6bb4e09d42..20735a008cab 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -235,7 +235,6 @@ struct iwl_txq { * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @rx_page_order: page order for receive buffer size * @wd_timeout: queue watchdog timeout (jiffies) - * @reg_lock: protect hw register access */ struct iwl_trans_pcie { struct iwl_rxq rxq; @@ -284,9 +283,6 @@ struct iwl_trans_pcie { /* queue watchdog */ unsigned long wd_timeout; - - /*protect hw register */ - spinlock_t reg_lock; }; /** diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/rx.c b/trunk/drivers/net/wireless/iwlwifi/pcie/rx.c index a9ca1d35fa93..4e6591d24e61 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. @@ -594,7 +594,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, int index, cmd_index, err, len; struct iwl_rx_cmd_buffer rxcb = { ._offset = offset, - ._rx_page_order = trans_pcie->rx_page_order, ._page = rxb->page, ._page_stolen = false, .truesize = max_len, diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/trans.c b/trunk/drivers/net/wireless/iwlwifi/pcie/trans.c index 56d4f72500bc..c57641eb83d5 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2012 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 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -75,33 +75,6 @@ #include "iwl-agn-hw.h" #include "internal.h" -static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, - u32 reg, u32 mask, u32 value) -{ - u32 v; - -#ifdef CONFIG_IWLWIFI_DEBUG - WARN_ON_ONCE(value & ~mask); -#endif - - v = iwl_read32(trans, reg); - v &= ~mask; - v |= value; - iwl_write32(trans, reg, v); -} - -static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, - u32 reg, u32 mask) -{ - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); -} - -static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, - u32 reg, u32 mask) -{ - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); -} - static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) { if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) @@ -806,16 +779,15 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) } #endif /* CONFIG_PM_SLEEP */ -static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, - unsigned long *flags) +static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) { int ret; - struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans); - spin_lock_irqsave(&pcie_trans->reg_lock, *flags); + + lockdep_assert_held(&trans->reg_lock); /* this bit wakes up the NIC */ - __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + __iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * These bits say the device is running, and should keep running for @@ -847,34 +819,18 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, WARN_ONCE(1, "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", val); - spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags); return false; } } - /* - * Fool sparse by faking we release the lock - sparse will - * track nic_access anyway. - */ - __release(&pcie_trans->reg_lock); return true; } -static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, - unsigned long *flags) +static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) { - struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans); - - lockdep_assert_held(&pcie_trans->reg_lock); - - /* - * Fool sparse by faking we acquiring the lock - sparse will - * track nic_access anyway. - */ - __acquire(&pcie_trans->reg_lock); - - __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + lockdep_assert_held(&trans->reg_lock); + __iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * Above we read the CSR_GP_CNTRL register, which will flush * any previous writes, but we need the write that clears the @@ -882,7 +838,6 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, * scheduled on different CPUs (after we drop reg_lock). */ mmiowb(); - spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags); } static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, @@ -892,14 +847,16 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, int offs, ret = 0; u32 *vals = buf; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); for (offs = 0; offs < dwords; offs++) vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } else { ret = -EBUSY; } + spin_unlock_irqrestore(&trans->reg_lock, flags); return ret; } @@ -910,15 +867,17 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, int offs, ret = 0; u32 *vals = buf; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); for (offs = 0; offs < dwords; offs++) iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals ? vals[offs] : 0); - iwl_trans_release_nic_access(trans, &flags); + iwl_trans_release_nic_access(trans); } else { ret = -EBUSY; } + spin_unlock_irqrestore(&trans->reg_lock, flags); return ret; } @@ -993,17 +952,6 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) return ret; } -static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, - u32 mask, u32 value) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; - - spin_lock_irqsave(&trans_pcie->reg_lock, flags); - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, value); - spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); -} - static const char *get_fh_string(int cmd) { #define IWL_CMD(x) case x: return #x @@ -1457,8 +1405,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { .configure = iwl_trans_pcie_configure, .set_pmi = iwl_trans_pcie_set_pmi, .grab_nic_access = iwl_trans_pcie_grab_nic_access, - .release_nic_access = iwl_trans_pcie_release_nic_access, - .set_bits_mask = iwl_trans_pcie_set_bits_mask, + .release_nic_access = iwl_trans_pcie_release_nic_access }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, @@ -1482,7 +1429,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans->cfg = cfg; trans_pcie->trans = trans; spin_lock_init(&trans_pcie->irq_lock); - spin_lock_init(&trans_pcie->reg_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); /* W/A - seems to solve weird behavior. We need to remove this if we @@ -1549,6 +1495,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); + spin_lock_init(&trans->reg_lock); snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), "iwl_cmd_pool:%s", dev_name(trans->dev)); diff --git a/trunk/drivers/net/wireless/iwlwifi/pcie/tx.c b/trunk/drivers/net/wireless/iwlwifi/pcie/tx.c index 041127ad372a..a93f06762b96 100644 --- a/trunk/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2012 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. diff --git a/trunk/drivers/net/wireless/mwifiex/11n.c b/trunk/drivers/net/wireless/mwifiex/11n.c index 48cc46bc152f..9cd6216c61e6 100644 --- a/trunk/drivers/net/wireless/mwifiex/11n.c +++ b/trunk/drivers/net/wireless/mwifiex/11n.c @@ -399,6 +399,45 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, return ret_len; } +/* + * This function reconfigures the Tx buffer size in firmware. + * + * This function prepares a firmware command and issues it, if + * the current Tx buffer size is different from the one requested. + * Maximum configurable Tx buffer size is limited by the HT capability + * field value. + */ +void +mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; + u16 tx_buf, curr_tx_buf_size = 0; + + if (bss_desc->bcn_ht_cap) { + if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & + IEEE80211_HT_CAP_MAX_AMSDU) + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; + else + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; + } + + tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); + + dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", + max_amsdu, priv->adapter->max_tx_buf_size); + + if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; + if (curr_tx_buf_size != tx_buf) + mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, &tx_buf); +} + /* * This function checks if the given pointer is valid entry of * Tx BA Stream table. diff --git a/trunk/drivers/net/wireless/mwifiex/11n.h b/trunk/drivers/net/wireless/mwifiex/11n.h index 29a4c02479d6..46006a54a656 100644 --- a/trunk/drivers/net/wireless/mwifiex/11n.h +++ b/trunk/drivers/net/wireless/mwifiex/11n.h @@ -34,6 +34,8 @@ int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc, u8 **buffer); +void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, struct mwifiex_ie_types_htcap *); int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, diff --git a/trunk/drivers/net/wireless/mwifiex/Kconfig b/trunk/drivers/net/wireless/mwifiex/Kconfig index 4f614aad9ded..b2e27723f801 100644 --- a/trunk/drivers/net/wireless/mwifiex/Kconfig +++ b/trunk/drivers/net/wireless/mwifiex/Kconfig @@ -20,12 +20,12 @@ config MWIFIEX_SDIO mwifiex_sdio. config MWIFIEX_PCIE - tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897" + tristate "Marvell WiFi-Ex Driver for PCIE 8766" depends on MWIFIEX && PCI select FW_LOADER ---help--- This adds support for wireless adapters based on Marvell - 8766/8897 chipsets with PCIe interface. + 8766 chipset with PCIe interface. If you choose to build it as a module, it will be called mwifiex_pcie. diff --git a/trunk/drivers/net/wireless/mwifiex/README b/trunk/drivers/net/wireless/mwifiex/README index 3d64613ebb29..b55badef4660 100644 --- a/trunk/drivers/net/wireless/mwifiex/README +++ b/trunk/drivers/net/wireless/mwifiex/README @@ -121,6 +121,7 @@ info wmm_ac_vi = wmm_ac_be = wmm_ac_bk = + max_tx_buf_size = tx_buf_size = curr_tx_buf_size = ps_mode = <0/1, CAM mode/PS mode> diff --git a/trunk/drivers/net/wireless/mwifiex/debugfs.c b/trunk/drivers/net/wireless/mwifiex/debugfs.c index 753b5682d53f..46e34aa65d1c 100644 --- a/trunk/drivers/net/wireless/mwifiex/debugfs.c +++ b/trunk/drivers/net/wireless/mwifiex/debugfs.c @@ -58,6 +58,8 @@ static struct mwifiex_debug_data items[] = { item_addr(packets_out[WMM_AC_BE]), 1}, {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), item_addr(packets_out[WMM_AC_BK]), 1}, + {"max_tx_buf_size", item_size(max_tx_buf_size), + item_addr(max_tx_buf_size), 1}, {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size), 1}, {"curr_tx_buf_size", item_size(curr_tx_buf_size), diff --git a/trunk/drivers/net/wireless/mwifiex/init.c b/trunk/drivers/net/wireless/mwifiex/init.c index 820a19cfa562..e00b8060aff7 100644 --- a/trunk/drivers/net/wireless/mwifiex/init.c +++ b/trunk/drivers/net/wireless/mwifiex/init.c @@ -317,6 +317,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->pm_wakeup_fw_try = false; + adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; diff --git a/trunk/drivers/net/wireless/mwifiex/ioctl.h b/trunk/drivers/net/wireless/mwifiex/ioctl.h index f3d9d0445529..6095b3e53f4e 100644 --- a/trunk/drivers/net/wireless/mwifiex/ioctl.h +++ b/trunk/drivers/net/wireless/mwifiex/ioctl.h @@ -178,6 +178,7 @@ struct mwifiex_ds_tx_ba_stream_tbl { struct mwifiex_debug_info { u32 int_counter; u32 packets_out[MAX_NUM_TID]; + u32 max_tx_buf_size; u32 tx_buf_size; u32 curr_tx_buf_size; u32 tx_tbl_num; diff --git a/trunk/drivers/net/wireless/mwifiex/join.c b/trunk/drivers/net/wireless/mwifiex/join.c index a537297866c6..893d809ba83c 100644 --- a/trunk/drivers/net/wireless/mwifiex/join.c +++ b/trunk/drivers/net/wireless/mwifiex/join.c @@ -157,8 +157,8 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, memset(rate1, 0, rate1_size); - for (i = 0; i < rate2_size && rate2[i]; i++) { - for (j = 0; j < rate1_size && tmp[j]; j++) { + for (i = 0; rate2[i] && i < rate2_size; i++) { + for (j = 0; tmp[j] && j < rate1_size; j++) { /* Check common rate, excluding the bit for basic rate */ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { @@ -398,6 +398,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, pos = (u8 *) assoc; + mwifiex_cfg_tx_buf(priv, bss_desc); + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); /* Save so we know which BSS Desc to use in the response handler */ diff --git a/trunk/drivers/net/wireless/mwifiex/main.h b/trunk/drivers/net/wireless/mwifiex/main.h index ac799a046eb7..51044e3ea89b 100644 --- a/trunk/drivers/net/wireless/mwifiex/main.h +++ b/trunk/drivers/net/wireless/mwifiex/main.h @@ -631,6 +631,7 @@ struct mwifiex_adapter { /* spin lock for main process */ spinlock_t main_proc_lock; u32 mwifiex_processing; + u16 max_tx_buf_size; u16 tx_buf_size; u16 curr_tx_buf_size; u32 ioport; diff --git a/trunk/drivers/net/wireless/mwifiex/pcie.c b/trunk/drivers/net/wireless/mwifiex/pcie.c index 3b9be7c185cb..237949c070cc 100644 --- a/trunk/drivers/net/wireless/mwifiex/pcie.c +++ b/trunk/drivers/net/wireless/mwifiex/pcie.c @@ -94,13 +94,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->dev = pdev; - if (ent->driver_data) { - struct mwifiex_pcie_device *data = (void *)ent->driver_data; - card->pcie.firmware = data->firmware; - card->pcie.reg = data->reg; - card->pcie.blksz_fw_dl = data->blksz_fw_dl; - } - if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, MWIFIEX_PCIE)) { pr_err("%s failed\n", __func__); @@ -237,16 +230,13 @@ static int mwifiex_pcie_resume(struct pci_dev *pdev) return 0; } +#define PCIE_VENDOR_ID_MARVELL (0x11ab) +#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) + static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { { PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - .driver_data = (unsigned long) &mwifiex_pcie8766, - }, - { - PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - .driver_data = (unsigned long) &mwifiex_pcie8897, }, {}, }; @@ -374,246 +364,12 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter) } /* - * This function initializes TX buffer ring descriptors - */ -static int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; - int i; - - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - card->tx_buf_list[i] = NULL; - if (reg->pfu_enabled) { - card->txbd_ring[i] = (void *)card->txbd_ring_vbase + - (sizeof(*desc2) * i); - desc2 = card->txbd_ring[i]; - memset(desc2, 0, sizeof(*desc2)); - } else { - card->txbd_ring[i] = (void *)card->txbd_ring_vbase + - (sizeof(*desc) * i); - desc = card->txbd_ring[i]; - memset(desc, 0, sizeof(*desc)); - } - } - - return 0; -} - -/* This function initializes RX buffer ring descriptors. Each SKB is allocated - * here and after mapping PCI memory, its physical address is assigned to - * PCIE Rx buffer descriptor's physical address. - */ -static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - struct sk_buff *skb; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; - dma_addr_t buf_pa; - int i; - - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - /* Allocate skb here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for RX ring.\n"); - kfree(card->rxbd_ring_vbase); - return -ENOMEM; - } - - if (mwifiex_map_pci_memory(adapter, skb, - MWIFIEX_RX_DATA_BUF_SIZE, - PCI_DMA_FROMDEVICE)) - return -1; - - MWIFIEX_SKB_PACB(skb, &buf_pa); - - dev_dbg(adapter->dev, - "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n", - skb, skb->len, skb->data, (u32)buf_pa, - (u32)((u64)buf_pa >> 32)); - - card->rx_buf_list[i] = skb; - if (reg->pfu_enabled) { - card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase + - (sizeof(*desc2) * i); - desc2 = card->rxbd_ring[i]; - desc2->paddr = buf_pa; - desc2->len = (u16)skb->len; - desc2->frag_len = (u16)skb->len; - desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop; - desc2->offset = 0; - } else { - card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase + - (sizeof(*desc) * i)); - desc = card->rxbd_ring[i]; - desc->paddr = buf_pa; - desc->len = (u16)skb->len; - desc->flags = 0; - } - } - - return 0; -} - -/* This function initializes event buffer ring descriptors. Each SKB is - * allocated here and after mapping PCI memory, its physical address is assigned - * to PCIE Rx buffer descriptor's physical address - */ -static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - struct mwifiex_evt_buf_desc *desc; - struct sk_buff *skb; - dma_addr_t buf_pa; - int i; - - for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { - /* Allocate skb here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MAX_EVENT_SIZE); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for EVENT buf.\n"); - kfree(card->evtbd_ring_vbase); - return -ENOMEM; - } - skb_put(skb, MAX_EVENT_SIZE); - - if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, - PCI_DMA_FROMDEVICE)) - return -1; - - MWIFIEX_SKB_PACB(skb, &buf_pa); - - dev_dbg(adapter->dev, - "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n", - skb, skb->len, skb->data, (u32)buf_pa, - (u32)((u64)buf_pa >> 32)); - - card->evt_buf_list[i] = skb; - card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase + - (sizeof(*desc) * i)); - desc = card->evtbd_ring[i]; - desc->paddr = buf_pa; - desc->len = (u16)skb->len; - desc->flags = 0; - } - - return 0; -} - -/* This function cleans up TX buffer rings. If any of the buffer list has valid - * SKB address, associated SKB is freed. - */ -static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - struct sk_buff *skb; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; - int i; - - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - if (reg->pfu_enabled) { - desc2 = card->txbd_ring[i]; - if (card->tx_buf_list[i]) { - skb = card->tx_buf_list[i]; - pci_unmap_single(card->dev, desc2->paddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - } - memset(desc2, 0, sizeof(*desc2)); - } else { - desc = card->txbd_ring[i]; - if (card->tx_buf_list[i]) { - skb = card->tx_buf_list[i]; - pci_unmap_single(card->dev, desc->paddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - } - memset(desc, 0, sizeof(*desc)); - } - card->tx_buf_list[i] = NULL; - } - - return; -} - -/* This function cleans up RX buffer rings. If any of the buffer list has valid - * SKB address, associated SKB is freed. - */ -static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; - struct sk_buff *skb; - int i; - - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - if (reg->pfu_enabled) { - desc2 = card->rxbd_ring[i]; - if (card->rx_buf_list[i]) { - skb = card->rx_buf_list[i]; - pci_unmap_single(card->dev, desc2->paddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - } - memset(desc2, 0, sizeof(*desc2)); - } else { - desc = card->rxbd_ring[i]; - if (card->rx_buf_list[i]) { - skb = card->rx_buf_list[i]; - pci_unmap_single(card->dev, desc->paddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - } - memset(desc, 0, sizeof(*desc)); - } - card->rx_buf_list[i] = NULL; - } - - return; -} - -/* This function cleans up event buffer rings. If any of the buffer list has - * valid SKB address, associated SKB is freed. - */ -static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - struct mwifiex_evt_buf_desc *desc; - struct sk_buff *skb; - int i; - - for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { - desc = card->evtbd_ring[i]; - if (card->evt_buf_list[i]) { - skb = card->evt_buf_list[i]; - pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(skb); - } - card->evt_buf_list[i] = NULL; - memset(desc, 0, sizeof(*desc)); - } - - return; -} - -/* This function creates buffer descriptor ring for TX + * This function creates buffer descriptor ring for TX */ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int i; /* * driver maintaines the write pointer and firmware maintaines the read @@ -621,21 +377,12 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) * starts at zero with rollover bit set */ card->txbd_wrptr = 0; - - if (reg->pfu_enabled) - card->txbd_rdptr = 0; - else - card->txbd_rdptr |= reg->tx_rollover_ind; + card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; /* allocate shared memory for the BD ring and divide the same in to several descriptors */ - if (reg->pfu_enabled) - card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) * - MWIFIEX_MAX_TXRX_BD; - else - card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * - MWIFIEX_MAX_TXRX_BD; - + card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_TXRX_BD; dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", card->txbd_ring_size); card->txbd_ring_vbase = pci_alloc_consistent(card->dev, @@ -652,15 +399,40 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase, (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size); - return mwifiex_init_txq_ring(adapter); + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *) + (card->txbd_ring_vbase + + (sizeof(struct mwifiex_pcie_buf_desc) + * i)); + + card->tx_buf_list[i] = NULL; + card->txbd_ring[i]->paddr = 0; + card->txbd_ring[i]->len = 0; + card->txbd_ring[i]->flags = 0; + } + + return 0; } static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct sk_buff *skb; + int i; - mwifiex_cleanup_txq_ring(adapter); + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + if (card->tx_buf_list[i]) { + skb = card->tx_buf_list[i]; + pci_unmap_single(card->dev, card->txbd_ring[i]->paddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + card->tx_buf_list[i] = NULL; + card->txbd_ring[i]->paddr = 0; + card->txbd_ring[i]->len = 0; + card->txbd_ring[i]->flags = 0; + card->txbd_ring[i] = NULL; + } if (card->txbd_ring_vbase) pci_free_consistent(card->dev, card->txbd_ring_size, @@ -668,7 +440,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) card->txbd_ring_pbase); card->txbd_ring_size = 0; card->txbd_wrptr = 0; - card->txbd_rdptr = 0 | reg->tx_rollover_ind; + card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; card->txbd_ring_vbase = NULL; card->txbd_ring_pbase = 0; @@ -681,7 +453,9 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct sk_buff *skb; + int i; + dma_addr_t buf_pa; /* * driver maintaines the read pointer and firmware maintaines the write @@ -689,15 +463,10 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) * starts at zero with rollover bit set */ card->rxbd_wrptr = 0; - card->rxbd_rdptr = reg->rx_rollover_ind; - - if (reg->pfu_enabled) - card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) * - MWIFIEX_MAX_TXRX_BD; - else - card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * - MWIFIEX_MAX_TXRX_BD; + card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_TXRX_BD; dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", card->rxbd_ring_size); card->rxbd_ring_vbase = pci_alloc_consistent(card->dev, @@ -716,7 +485,39 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) (u32)((u64)card->rxbd_ring_pbase >> 32), card->rxbd_ring_size); - return mwifiex_init_rxq_ring(adapter); + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *) + (card->rxbd_ring_vbase + + (sizeof(struct mwifiex_pcie_buf_desc) + * i)); + + /* Allocate skb here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); + if (!skb) { + dev_err(adapter->dev, + "Unable to allocate skb for RX ring.\n"); + kfree(card->rxbd_ring_vbase); + return -ENOMEM; + } + if (mwifiex_map_pci_memory(adapter, skb, + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); + + dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, " + "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", + skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), + skb->len); + + card->rx_buf_list[i] = skb; + card->rxbd_ring[i]->paddr = buf_pa; + card->rxbd_ring[i]->len = (u16)skb->len; + card->rxbd_ring[i]->flags = 0; + } + + return 0; } /* @@ -725,9 +526,23 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct sk_buff *skb; + int i; - mwifiex_cleanup_rxq_ring(adapter); + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + if (card->rx_buf_list[i]) { + skb = card->rx_buf_list[i]; + pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr , + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + } + card->rx_buf_list[i] = NULL; + card->rxbd_ring[i]->paddr = 0; + card->rxbd_ring[i]->len = 0; + card->rxbd_ring[i]->flags = 0; + card->rxbd_ring[i] = NULL; + } if (card->rxbd_ring_vbase) pci_free_consistent(card->dev, card->rxbd_ring_size, @@ -735,7 +550,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) card->rxbd_ring_pbase); card->rxbd_ring_size = 0; card->rxbd_wrptr = 0; - card->rxbd_rdptr = 0 | reg->rx_rollover_ind; + card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; card->rxbd_ring_vbase = NULL; card->rxbd_ring_pbase = 0; @@ -748,7 +563,9 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct sk_buff *skb; + int i; + dma_addr_t buf_pa; /* * driver maintaines the read pointer and firmware maintaines the write @@ -756,11 +573,10 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) * starts at zero with rollover bit set */ card->evtbd_wrptr = 0; - card->evtbd_rdptr = reg->evt_rollover_ind; - - card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) * - MWIFIEX_MAX_EVT_BD; + card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_EVT_BD; dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", card->evtbd_ring_size); card->evtbd_ring_vbase = pci_alloc_consistent(card->dev, @@ -779,7 +595,39 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) (u32)((u64)card->evtbd_ring_pbase >> 32), card->evtbd_ring_size); - return mwifiex_pcie_init_evt_ring(adapter); + for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { + card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *) + (card->evtbd_ring_vbase + + (sizeof(struct mwifiex_pcie_buf_desc) + * i)); + + /* Allocate skb here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MAX_EVENT_SIZE); + if (!skb) { + dev_err(adapter->dev, + "Unable to allocate skb for EVENT buf.\n"); + kfree(card->evtbd_ring_vbase); + return -ENOMEM; + } + skb_put(skb, MAX_EVENT_SIZE); + + if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); + dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, " + "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", + skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), + skb->len); + + card->evt_buf_list[i] = skb; + card->evtbd_ring[i]->paddr = buf_pa; + card->evtbd_ring[i]->len = (u16)skb->len; + card->evtbd_ring[i]->flags = 0; + } + + return 0; } /* @@ -788,16 +636,29 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct sk_buff *skb; + int i; - mwifiex_cleanup_evt_ring(adapter); + for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { + if (card->evt_buf_list[i]) { + skb = card->evt_buf_list[i]; + pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr, + MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + } + card->evt_buf_list[i] = NULL; + card->evtbd_ring[i]->paddr = 0; + card->evtbd_ring[i]->len = 0; + card->evtbd_ring[i]->flags = 0; + card->evtbd_ring[i] = NULL; + } if (card->evtbd_ring_vbase) pci_free_consistent(card->dev, card->evtbd_ring_size, card->evtbd_ring_vbase, card->evtbd_ring_pbase); card->evtbd_wrptr = 0; - card->evtbd_rdptr = 0 | reg->evt_rollover_ind; + card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; card->evtbd_ring_size = 0; card->evtbd_ring_vbase = NULL; card->evtbd_ring_pbase = 0; @@ -910,13 +771,12 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter) static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; u32 rdptr; /* Read the TX ring read pointer set by firmware */ - if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) { + if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { dev_err(adapter->dev, - "Flush TXBD: failed to read reg->tx_rdptr\n"); + "Flush TXBD: failed to read REG_TXBD_RDPTR\n"); return -1; } @@ -940,35 +800,31 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) */ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) { + const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD; struct sk_buff *skb; dma_addr_t buf_pa; - u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; + u32 wrdoneidx, rdptr, unmap_count = 0; struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); /* Read the TX ring read pointer set by firmware */ - if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) { + if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { dev_err(adapter->dev, - "SEND COMP: failed to read reg->tx_rdptr\n"); + "SEND COMP: failed to read REG_TXBD_RDPTR\n"); return -1; } dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n", card->txbd_rdptr, rdptr); - num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr; /* free from previous txbd_rdptr to current txbd_rdptr */ - while (((card->txbd_rdptr & reg->tx_mask) != - (rdptr & reg->tx_mask)) || - ((card->txbd_rdptr & reg->tx_rollover_ind) != - (rdptr & reg->tx_rollover_ind))) { - wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >> - reg->tx_start_ptr; + while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) != + (rdptr & MWIFIEX_TXBD_MASK)) || + ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK; skb = card->tx_buf_list[wrdoneidx]; if (skb) { @@ -989,38 +845,25 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) } card->tx_buf_list[wrdoneidx] = NULL; + card->txbd_ring[wrdoneidx]->paddr = 0; + card->rxbd_ring[wrdoneidx]->len = 0; + card->rxbd_ring[wrdoneidx]->flags = 0; + card->txbd_rdptr++; - if (reg->pfu_enabled) { - desc2 = (void *)card->txbd_ring[wrdoneidx]; - memset(desc2, 0, sizeof(*desc2)); - } else { - desc = card->txbd_ring[wrdoneidx]; - memset(desc, 0, sizeof(*desc)); - } - switch (card->dev->device) { - case PCIE_DEVICE_ID_MARVELL_88W8766P: - card->txbd_rdptr++; - break; - case PCIE_DEVICE_ID_MARVELL_88W8897: - card->txbd_rdptr += reg->ring_tx_start_ptr; - break; - } - - - if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs) + if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs) card->txbd_rdptr = ((card->txbd_rdptr & - reg->tx_rollover_ind) ^ - reg->tx_rollover_ind); + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); } if (unmap_count) adapter->data_sent = false; if (card->txbd_flush) { - if (((card->txbd_wrptr & reg->tx_mask) == - (card->txbd_rdptr & reg->tx_mask)) && - ((card->txbd_wrptr & reg->tx_rollover_ind) != - (card->txbd_rdptr & reg->tx_rollover_ind))) + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == + (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) && + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) card->txbd_flush = 0; else mwifiex_clean_pcie_ring_buf(adapter); @@ -1040,12 +883,9 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, struct mwifiex_tx_param *tx_param) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - u32 wrindx, num_tx_buffs, rx_val; + u32 wrindx; int ret; dma_addr_t buf_pa; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; __le16 *tmp; if (!(skb->data && skb->len)) { @@ -1057,7 +897,6 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); - num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr; dev_dbg(adapter->dev, "info: SEND DATA: \n", card->txbd_rdptr, card->txbd_wrptr); if (mwifiex_pcie_txbd_not_full(card)) { @@ -1074,46 +913,25 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, PCI_DMA_TODEVICE)) return -1; - wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr; + wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; MWIFIEX_SKB_PACB(skb, &buf_pa); card->tx_buf_list[wrindx] = skb; + card->txbd_ring[wrindx]->paddr = buf_pa; + card->txbd_ring[wrindx]->len = (u16)skb->len; + card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | + MWIFIEX_BD_FLAG_LAST_DESC; - if (reg->pfu_enabled) { - desc2 = (void *)card->txbd_ring[wrindx]; - desc2->paddr = buf_pa; - desc2->len = (u16)skb->len; - desc2->frag_len = (u16)skb->len; - desc2->offset = 0; - desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC | - MWIFIEX_BD_FLAG_LAST_DESC; - } else { - desc = card->txbd_ring[wrindx]; - desc->paddr = buf_pa; - desc->len = (u16)skb->len; - desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC | - MWIFIEX_BD_FLAG_LAST_DESC; - } - - switch (card->dev->device) { - case PCIE_DEVICE_ID_MARVELL_88W8766P: - card->txbd_wrptr++; - break; - case PCIE_DEVICE_ID_MARVELL_88W8897: - card->txbd_wrptr += reg->ring_tx_start_ptr; - break; - } - - if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs) + if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) == + MWIFIEX_MAX_TXRX_BD) card->txbd_wrptr = ((card->txbd_wrptr & - reg->tx_rollover_ind) ^ - reg->tx_rollover_ind); + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); - rx_val = card->rxbd_rdptr & reg->rx_wrap_mask; - /* Write the TX ring write pointer in to reg->tx_wrptr */ - if (mwifiex_write_reg(adapter, reg->tx_wrptr, - card->txbd_wrptr | rx_val)) { + /* Write the TX ring write pointer in to REG_TXBD_WRPTR */ + if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR, + card->txbd_wrptr)) { dev_err(adapter->dev, - "SEND DATA: failed to write reg->tx_wrptr\n"); + "SEND DATA: failed to write REG_TXBD_WRPTR\n"); ret = -1; goto done_unmap; } @@ -1153,11 +971,9 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, MWIFIEX_SKB_PACB(skb, &buf_pa); pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE); card->tx_buf_list[wrindx] = NULL; - if (reg->pfu_enabled) - memset(desc2, 0, sizeof(*desc2)); - else - memset(desc, 0, sizeof(*desc)); - + card->txbd_ring[wrindx]->paddr = 0; + card->txbd_ring[wrindx]->len = 0; + card->txbd_ring[wrindx]->flags = 0; return ret; } @@ -1168,35 +984,32 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - u32 wrptr, rd_index, tx_val; + u32 wrptr, rd_index; dma_addr_t buf_pa; int ret = 0; struct sk_buff *skb_tmp = NULL; - struct mwifiex_pcie_buf_desc *desc; - struct mwifiex_pfu_buf_desc *desc2; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); /* Read the RX ring Write pointer set by firmware */ - if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) { + if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { dev_err(adapter->dev, - "RECV DATA: failed to read reg->rx_wrptr\n"); + "RECV DATA: failed to read REG_TXBD_RDPTR\n"); ret = -1; goto done; } card->rxbd_wrptr = wrptr; - while (((wrptr & reg->rx_mask) != - (card->rxbd_rdptr & reg->rx_mask)) || - ((wrptr & reg->rx_rollover_ind) == - (card->rxbd_rdptr & reg->rx_rollover_ind))) { + while (((wrptr & MWIFIEX_RXBD_MASK) != + (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || + ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == + (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { struct sk_buff *skb_data; u16 rx_len; __le16 pkt_len; - rd_index = card->rxbd_rdptr & reg->rx_mask; + rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; skb_data = card->rx_buf_list[rd_index]; MWIFIEX_SKB_PACB(skb_data, &buf_pa); @@ -1234,44 +1047,32 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n", skb_tmp, rd_index); card->rx_buf_list[rd_index] = skb_tmp; + card->rxbd_ring[rd_index]->paddr = buf_pa; + card->rxbd_ring[rd_index]->len = skb_tmp->len; + card->rxbd_ring[rd_index]->flags = 0; - if (reg->pfu_enabled) { - desc2 = (void *)card->rxbd_ring[rd_index]; - desc2->paddr = buf_pa; - desc2->len = skb_tmp->len; - desc2->frag_len = skb_tmp->len; - desc2->offset = 0; - desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop; - } else { - desc = card->rxbd_ring[rd_index]; - desc->paddr = buf_pa; - desc->len = skb_tmp->len; - desc->flags = 0; - } - - if ((++card->rxbd_rdptr & reg->rx_mask) == + if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == MWIFIEX_MAX_TXRX_BD) { card->rxbd_rdptr = ((card->rxbd_rdptr & - reg->rx_rollover_ind) ^ - reg->rx_rollover_ind); + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); } dev_dbg(adapter->dev, "info: RECV DATA: \n", card->rxbd_rdptr, wrptr); - tx_val = card->txbd_wrptr & reg->tx_wrap_mask; - /* Write the RX ring read pointer in to reg->rx_rdptr */ - if (mwifiex_write_reg(adapter, reg->rx_rdptr, - card->rxbd_rdptr | tx_val)) { + /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ + if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, + card->rxbd_rdptr)) { dev_err(adapter->dev, - "RECV DATA: failed to write reg->rx_rdptr\n"); + "RECV DATA: failed to write REG_RXBD_RDPTR\n"); ret = -1; goto done; } /* Read the RX ring Write pointer set by firmware */ - if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) { + if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { dev_err(adapter->dev, - "RECV DATA: failed to read reg->rx_wrptr\n"); + "RECV DATA: failed to read REG_TXBD_RDPTR\n"); ret = -1; goto done; } @@ -1292,7 +1093,6 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) { dma_addr_t buf_pa; struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; if (!(skb->data && skb->len)) { dev_err(adapter->dev, @@ -1306,10 +1106,9 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) MWIFIEX_SKB_PACB(skb, &buf_pa); - /* Write the lower 32bits of the physical address to low command - * address scratch register - */ - if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) { + /* Write the lower 32bits of the physical address to scratch + * register 0 */ + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) { dev_err(adapter->dev, "%s: failed to write download command to boot code.\n", __func__); @@ -1318,10 +1117,9 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -1; } - /* Write the upper 32bits of the physical address to high command - * address scratch register - */ - if (mwifiex_write_reg(adapter, reg->cmd_addr_hi, + /* Write the upper 32bits of the physical address to scratch + * register 1 */ + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG, (u32)((u64)buf_pa >> 32))) { dev_err(adapter->dev, "%s: failed to write download command to boot code.\n", @@ -1331,10 +1129,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -1; } - /* Write the command length to cmd_size scratch register */ - if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) { + /* Write the command length to scratch register 2 */ + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) { dev_err(adapter->dev, - "%s: failed to write command len to cmd_size scratch reg\n", + "%s: failed to write command len to scratch reg 2\n", __func__); pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE); @@ -1360,14 +1158,11 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; - /* Write the RX ring read pointer in to reg->rx_rdptr */ - if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | - tx_wrap)) { + /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ + if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) { dev_err(adapter->dev, - "RECV DATA: failed to write reg->rx_rdptr\n"); + "RECV DATA: failed to write REG_RXBD_RDPTR\n"); return -1; } return 0; @@ -1379,7 +1174,6 @@ static int mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; int ret = 0; dma_addr_t cmd_buf_pa, cmdrsp_buf_pa; u8 *payload = (u8 *)skb->data; @@ -1412,7 +1206,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) /* To send a command, the driver will: 1. Write the 64bit physical address of the data buffer to - cmd response address low + cmd response address high + SCRATCH1 + SCRATCH0 2. Ring the door bell (i.e. set the door bell interrupt) In response to door bell interrupt, the firmware will perform @@ -1424,7 +1218,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa); /* Write the lower 32bits of the cmdrsp buffer physical address */ - if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, (u32)cmdrsp_buf_pa)) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); @@ -1433,7 +1227,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) } /* Write the upper 32bits of the cmdrsp buffer physical address */ - if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, (u32)((u64)cmdrsp_buf_pa >> 32))) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); @@ -1443,16 +1237,15 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) } MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa); - /* Write the lower 32bits of the physical address to reg->cmd_addr_lo */ - if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, - (u32)cmd_buf_pa)) { + /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */ + if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; goto done; } - /* Write the upper 32bits of the physical address to reg->cmd_addr_hi */ - if (mwifiex_write_reg(adapter, reg->cmd_addr_hi, + /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */ + if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI, (u32)((u64)cmd_buf_pa >> 32))) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); @@ -1460,11 +1253,10 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) goto done; } - /* Write the command length to reg->cmd_size */ - if (mwifiex_write_reg(adapter, reg->cmd_size, - card->cmd_buf->len)) { + /* Write the command length to REG_CMD_SIZE */ + if (mwifiex_write_reg(adapter, REG_CMD_SIZE, card->cmd_buf->len)) { dev_err(adapter->dev, - "Failed to write cmd len to reg->cmd_size\n"); + "Failed to write cmd len to REG_CMD_SIZE\n"); ret = -1; goto done; } @@ -1491,7 +1283,6 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; struct sk_buff *skb = card->cmdrsp_buf; int count = 0; u16 rx_len; @@ -1537,14 +1328,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) /* Clear the cmd-rsp buffer address in scratch registers. This will prevent firmware from writing to the same response buffer again. */ - if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) { + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) { dev_err(adapter->dev, "cmd_done: failed to clear cmd_rsp_addr_lo\n"); return -1; } /* Write the upper 32bits of the cmdrsp buffer physical address */ - if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) { + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) { dev_err(adapter->dev, "cmd_done: failed to clear cmd_rsp_addr_hi\n"); return -1; @@ -1589,11 +1380,9 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; u32 wrptr, event; dma_addr_t buf_pa; - struct mwifiex_evt_buf_desc *desc; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); @@ -1610,9 +1399,9 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) } /* Read the event ring write pointer set by firmware */ - if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) { + if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { dev_err(adapter->dev, - "EventReady: failed to read reg->evt_wrptr\n"); + "EventReady: failed to read REG_EVTBD_WRPTR\n"); return -1; } @@ -1620,8 +1409,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) card->evtbd_rdptr, wrptr); if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr & MWIFIEX_EVTBD_MASK)) || - ((wrptr & reg->evt_rollover_ind) == - (card->evtbd_rdptr & reg->evt_rollover_ind))) { + ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == + (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { struct sk_buff *skb_cmd; __le16 data_len = 0; u16 evt_len; @@ -1635,8 +1424,9 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) /* Take the pointer and set it to event pointer in adapter and will return back after event handling callback */ card->evt_buf_list[rdptr] = NULL; - desc = card->evtbd_ring[rdptr]; - memset(desc, 0, sizeof(*desc)); + card->evtbd_ring[rdptr]->paddr = 0; + card->evtbd_ring[rdptr]->len = 0; + card->evtbd_ring[rdptr]->flags = 0; event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN]; adapter->event_cause = event; @@ -1672,12 +1462,10 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; int ret = 0; u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; u32 wrptr; dma_addr_t buf_pa; - struct mwifiex_evt_buf_desc *desc; if (!skb) return 0; @@ -1689,9 +1477,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, } /* Read the event ring write pointer set by firmware */ - if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) { + if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { dev_err(adapter->dev, - "event_complete: failed to read reg->evt_wrptr\n"); + "event_complete: failed to read REG_EVTBD_WRPTR\n"); return -1; } @@ -1704,10 +1492,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, MWIFIEX_SKB_PACB(skb, &buf_pa); card->evt_buf_list[rdptr] = skb; MWIFIEX_SKB_PACB(skb, &buf_pa); - desc = card->evtbd_ring[rdptr]; - desc->paddr = buf_pa; - desc->len = (u16)skb->len; - desc->flags = 0; + card->evtbd_ring[rdptr]->paddr = buf_pa; + card->evtbd_ring[rdptr]->len = (u16)skb->len; + card->evtbd_ring[rdptr]->flags = 0; skb = NULL; } else { dev_dbg(adapter->dev, @@ -1717,18 +1504,17 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) { card->evtbd_rdptr = ((card->evtbd_rdptr & - reg->evt_rollover_ind) ^ - reg->evt_rollover_ind); + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); } dev_dbg(adapter->dev, "info: Updated ", card->evtbd_rdptr, wrptr); - /* Write the event ring read pointer in to reg->evt_rdptr */ - if (mwifiex_write_reg(adapter, reg->evt_rdptr, - card->evtbd_rdptr)) { + /* Write the event ring read pointer in to REG_EVTBD_RDPTR */ + if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) { dev_err(adapter->dev, - "event_complete: failed to read reg->evt_rdptr\n"); + "event_complete: failed to read REG_EVTBD_RDPTR\n"); return -1; } @@ -1757,7 +1543,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, u32 block_retry_cnt = 0; dma_addr_t buf_pa; struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; if (!firmware || !firmware_len) { dev_err(adapter->dev, @@ -1789,7 +1574,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { - ret = mwifiex_read_reg(adapter, reg->cmd_size, + ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG, &len); if (ret) { dev_warn(adapter->dev, @@ -1835,15 +1620,16 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, dev_dbg(adapter->dev, "."); - tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) / - card->pcie.blksz_fw_dl; + tx_blocks = (txlen + + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) / + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD; /* Copy payload to buffer */ memmove(skb->data, &firmware[offset], txlen); } skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); - skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl); + skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD); /* Send the boot command to device */ if (mwifiex_pcie_send_boot_cmd(adapter, skb)) { @@ -1896,8 +1682,6 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) { int ret = 0; u32 firmware_stat, winner_status; - struct pcie_service_card *card = adapter->card; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; u32 tries; /* Mask spurios interrupts */ @@ -1908,8 +1692,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) } dev_dbg(adapter->dev, "Setting driver ready signature\n"); - if (mwifiex_write_reg(adapter, reg->drv_rdy, - FIRMWARE_READY_PCIE)) { + if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) { dev_err(adapter->dev, "Failed to write driver ready signature\n"); return -1; @@ -1917,7 +1700,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) /* Wait for firmware initialization event */ for (tries = 0; tries < poll_num; tries++) { - if (mwifiex_read_reg(adapter, reg->fw_status, + if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, &firmware_stat)) ret = -1; else @@ -1934,7 +1717,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) } if (ret) { - if (mwifiex_read_reg(adapter, reg->fw_status, + if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, &winner_status)) ret = -1; else if (!winner_status) { @@ -2202,7 +1985,6 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) card->pci_mmap = pci_iomap(pdev, 0, 0); if (!card->pci_mmap) { dev_err(adapter->dev, "iomap(0) error\n"); - ret = -EIO; goto err_iomap0; } ret = pci_request_region(pdev, 2, DRV_NAME); @@ -2213,7 +1995,6 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) card->pci_mmap1 = pci_iomap(pdev, 2, 0); if (!card->pci_mmap1) { dev_err(adapter->dev, "iomap(2) error\n"); - ret = -EIO; goto err_iomap2; } @@ -2278,11 +2059,10 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; struct pci_dev *pdev = card->dev; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; if (user_rmmod) { dev_dbg(adapter->dev, "Clearing driver ready signature\n"); - if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000)) + if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000)) dev_err(adapter->dev, "Failed to write driver not-ready signature\n"); } @@ -2320,7 +2100,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) } adapter->dev = &pdev->dev; - strcpy(adapter->fw_name, card->pcie.firmware); + strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME); return 0; } @@ -2380,7 +2160,7 @@ static int mwifiex_pcie_init_module(void) { int ret; - pr_debug("Marvell PCIe Driver\n"); + pr_debug("Marvell 8766 PCIe Driver\n"); sema_init(&add_remove_card_sem, 1); @@ -2423,5 +2203,4 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION); MODULE_VERSION(PCIE_VERSION); MODULE_LICENSE("GPL v2"); -MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME); -MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME); +MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin"); diff --git a/trunk/drivers/net/wireless/mwifiex/pcie.h b/trunk/drivers/net/wireless/mwifiex/pcie.h index 608061578b37..37eeb2ca6b29 100644 --- a/trunk/drivers/net/wireless/mwifiex/pcie.h +++ b/trunk/drivers/net/wireless/mwifiex/pcie.h @@ -29,11 +29,6 @@ #include "main.h" #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" -#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" - -#define PCIE_VENDOR_ID_MARVELL (0x11ab) -#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) -#define PCIE_DEVICE_ID_MARVELL_88W8897 (0x2b38) /* Constants for Buffer Descriptor (BD) rings */ #define MWIFIEX_MAX_TXRX_BD 0x20 @@ -62,8 +57,6 @@ #define PCIE_SCRATCH_10_REG 0xCE8 #define PCIE_SCRATCH_11_REG 0xCEC #define PCIE_SCRATCH_12_REG 0xCF0 -#define PCIE_RD_DATA_PTR_Q0_Q1 0xC08C -#define PCIE_WR_DATA_PTR_Q0_Q1 0xC05C #define CPU_INTR_DNLD_RDY BIT(0) #define CPU_INTR_DOOR_BELL BIT(1) @@ -82,14 +75,27 @@ #define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7) #define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0) #define MWIFIEX_BD_FLAG_LAST_DESC BIT(1) -#define MWIFIEX_BD_FLAG_SOP BIT(0) -#define MWIFIEX_BD_FLAG_EOP BIT(1) -#define MWIFIEX_BD_FLAG_XS_SOP BIT(2) -#define MWIFIEX_BD_FLAG_XS_EOP BIT(3) -#define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND BIT(7) -#define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND BIT(10) -#define MWIFIEX_BD_FLAG_TX_START_PTR BIT(16) -#define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND BIT(26) +#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG +#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG +#define REG_CMD_SIZE PCIE_SCRATCH_2_REG + +#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG +#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG + +/* TX buffer description read pointer */ +#define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG +/* TX buffer description write pointer */ +#define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG +/* RX buffer description read pointer */ +#define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG +/* RX buffer description write pointer */ +#define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG +/* Event buffer description read pointer */ +#define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG +/* Event buffer description write pointer */ +#define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG +/* Driver ready signature write pointer */ +#define REG_DRV_READY PCIE_SCRATCH_12_REG /* Max retry number of command write */ #define MAX_WRITE_IOMEM_RETRY 2 @@ -98,139 +104,15 @@ /* FW awake cookie after FW ready */ #define FW_AWAKE_COOKIE (0xAA55AA55) -struct mwifiex_pcie_card_reg { - u16 cmd_addr_lo; - u16 cmd_addr_hi; - u16 fw_status; - u16 cmd_size; - u16 cmdrsp_addr_lo; - u16 cmdrsp_addr_hi; - u16 tx_rdptr; - u16 tx_wrptr; - u16 rx_rdptr; - u16 rx_wrptr; - u16 evt_rdptr; - u16 evt_wrptr; - u16 drv_rdy; - u16 tx_start_ptr; - u32 tx_mask; - u32 tx_wrap_mask; - u32 rx_mask; - u32 rx_wrap_mask; - u32 tx_rollover_ind; - u32 rx_rollover_ind; - u32 evt_rollover_ind; - u8 ring_flag_sop; - u8 ring_flag_eop; - u8 ring_flag_xs_sop; - u8 ring_flag_xs_eop; - u32 ring_tx_start_ptr; - u8 pfu_enabled; -}; - -static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { - .cmd_addr_lo = PCIE_SCRATCH_0_REG, - .cmd_addr_hi = PCIE_SCRATCH_1_REG, - .cmd_size = PCIE_SCRATCH_2_REG, - .fw_status = PCIE_SCRATCH_3_REG, - .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, - .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, - .tx_rdptr = PCIE_SCRATCH_6_REG, - .tx_wrptr = PCIE_SCRATCH_7_REG, - .rx_rdptr = PCIE_SCRATCH_8_REG, - .rx_wrptr = PCIE_SCRATCH_9_REG, - .evt_rdptr = PCIE_SCRATCH_10_REG, - .evt_wrptr = PCIE_SCRATCH_11_REG, - .drv_rdy = PCIE_SCRATCH_12_REG, - .tx_start_ptr = 0, - .tx_mask = MWIFIEX_TXBD_MASK, - .tx_wrap_mask = 0, - .rx_mask = MWIFIEX_RXBD_MASK, - .rx_wrap_mask = 0, - .tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, - .rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, - .evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, - .ring_flag_sop = 0, - .ring_flag_eop = 0, - .ring_flag_xs_sop = 0, - .ring_flag_xs_eop = 0, - .ring_tx_start_ptr = 0, - .pfu_enabled = 0, -}; - -static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { - .cmd_addr_lo = PCIE_SCRATCH_0_REG, - .cmd_addr_hi = PCIE_SCRATCH_1_REG, - .cmd_size = PCIE_SCRATCH_2_REG, - .fw_status = PCIE_SCRATCH_3_REG, - .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, - .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, - .tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1, - .tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1, - .rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1, - .rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1, - .evt_rdptr = PCIE_SCRATCH_10_REG, - .evt_wrptr = PCIE_SCRATCH_11_REG, - .drv_rdy = PCIE_SCRATCH_12_REG, - .tx_start_ptr = 16, - .tx_mask = 0x03FF0000, - .tx_wrap_mask = 0x07FF0000, - .rx_mask = 0x000003FF, - .rx_wrap_mask = 0x000007FF, - .tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND, - .rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND, - .evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, - .ring_flag_sop = MWIFIEX_BD_FLAG_SOP, - .ring_flag_eop = MWIFIEX_BD_FLAG_EOP, - .ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP, - .ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP, - .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, - .pfu_enabled = 1, -}; - -struct mwifiex_pcie_device { - const char *firmware; - const struct mwifiex_pcie_card_reg *reg; - u16 blksz_fw_dl; -}; - -static const struct mwifiex_pcie_device mwifiex_pcie8766 = { - .firmware = PCIE8766_DEFAULT_FW_NAME, - .reg = &mwifiex_reg_8766, - .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, -}; - -static const struct mwifiex_pcie_device mwifiex_pcie8897 = { - .firmware = PCIE8897_DEFAULT_FW_NAME, - .reg = &mwifiex_reg_8897, - .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, -}; - -struct mwifiex_evt_buf_desc { - u64 paddr; - u16 len; - u16 flags; -} __packed; - struct mwifiex_pcie_buf_desc { u64 paddr; u16 len; u16 flags; } __packed; -struct mwifiex_pfu_buf_desc { - u16 flags; - u16 offset; - u16 frag_len; - u16 len; - u64 paddr; - u32 reserved; -} __packed; - struct pcie_service_card { struct pci_dev *dev; struct mwifiex_adapter *adapter; - struct mwifiex_pcie_device pcie; u8 txbd_flush; u32 txbd_wrptr; @@ -238,7 +120,7 @@ struct pcie_service_card { u32 txbd_ring_size; u8 *txbd_ring_vbase; dma_addr_t txbd_ring_pbase; - void *txbd_ring[MWIFIEX_MAX_TXRX_BD]; + struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; u32 rxbd_wrptr; @@ -246,7 +128,7 @@ struct pcie_service_card { u32 rxbd_ring_size; u8 *rxbd_ring_vbase; dma_addr_t rxbd_ring_pbase; - void *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; + struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; u32 evtbd_wrptr; @@ -254,7 +136,7 @@ struct pcie_service_card { u32 evtbd_ring_size; u8 *evtbd_ring_vbase; dma_addr_t evtbd_ring_pbase; - void *evtbd_ring[MWIFIEX_MAX_EVT_BD]; + struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; struct sk_buff *cmd_buf; @@ -268,24 +150,11 @@ struct pcie_service_card { static inline int mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) { - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - - switch (card->dev->device) { - case PCIE_DEVICE_ID_MARVELL_88W8766P: - if (((card->txbd_wrptr & reg->tx_mask) == - (rdptr & reg->tx_mask)) && - ((card->txbd_wrptr & reg->tx_rollover_ind) != - (rdptr & reg->tx_rollover_ind))) - return 1; - break; - case PCIE_DEVICE_ID_MARVELL_88W8897: - if (((card->txbd_wrptr & reg->tx_mask) == - (rdptr & reg->tx_mask)) && - ((card->txbd_wrptr & reg->tx_rollover_ind) == - (rdptr & reg->tx_rollover_ind))) - return 1; - break; - } + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == + (rdptr & MWIFIEX_TXBD_MASK)) && + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) + return 1; return 0; } @@ -293,24 +162,11 @@ mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) static inline int mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) { - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - - switch (card->dev->device) { - case PCIE_DEVICE_ID_MARVELL_88W8766P: - if (((card->txbd_wrptr & reg->tx_mask) != - (card->txbd_rdptr & reg->tx_mask)) || - ((card->txbd_wrptr & reg->tx_rollover_ind) != - (card->txbd_rdptr & reg->tx_rollover_ind))) - return 1; - break; - case PCIE_DEVICE_ID_MARVELL_88W8897: - if (((card->txbd_wrptr & reg->tx_mask) != - (card->txbd_rdptr & reg->tx_mask)) || - ((card->txbd_wrptr & reg->tx_rollover_ind) == - (card->txbd_rdptr & reg->tx_rollover_ind))) - return 1; - break; - } + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != + (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) || + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) + return 1; return 0; } diff --git a/trunk/drivers/net/wireless/mwifiex/sdio.c b/trunk/drivers/net/wireless/mwifiex/sdio.c index e35b67a9e6a6..5a1c1d0e5599 100644 --- a/trunk/drivers/net/wireless/mwifiex/sdio.c +++ b/trunk/drivers/net/wireless/mwifiex/sdio.c @@ -332,7 +332,7 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, u32 pkt_len, u32 port) { struct sdio_mmc_card *card = adapter->card; - int ret; + int ret = -1; u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; @@ -350,7 +350,8 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, sdio_claim_host(card->func); - ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size); + if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) + ret = 0; sdio_release_host(card->func); @@ -364,7 +365,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, u32 len, u32 port, u8 claim) { struct sdio_mmc_card *card = adapter->card; - int ret; + int ret = -1; u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; @@ -375,7 +376,8 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, if (claim) sdio_claim_host(card->func); - ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size); + if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) + ret = 0; if (claim) sdio_release_host(card->func); diff --git a/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c b/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c index 847056415ac9..65c12eb3e5e7 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -935,8 +935,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, / MWIFIEX_SDIO_BLOCK_SIZE) * MWIFIEX_SDIO_BLOCK_SIZE; adapter->curr_tx_buf_size = adapter->tx_buf_size; - dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n", - adapter->curr_tx_buf_size); + dev_dbg(adapter->dev, + "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", + adapter->max_tx_buf_size, adapter->tx_buf_size); if (adapter->if_ops.update_mp_end_port) adapter->if_ops.update_mp_end_port(adapter, diff --git a/trunk/drivers/net/wireless/mwifiex/usb.c b/trunk/drivers/net/wireless/mwifiex/usb.c index f90fe21e5bfd..5d4a10a8a005 100644 --- a/trunk/drivers/net/wireless/mwifiex/usb.c +++ b/trunk/drivers/net/wireless/mwifiex/usb.c @@ -672,7 +672,7 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, *len, &actual_length, timeout); if (ret) { dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret); - return ret; + ret = -1; } *len = actual_length; @@ -691,7 +691,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, *len, &actual_length, timeout); if (ret) { dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret); - return ret; + ret = -1; } *len = actual_length; diff --git a/trunk/drivers/net/wireless/mwifiex/util.c b/trunk/drivers/net/wireless/mwifiex/util.c index 21553976b550..0982375ba3b1 100644 --- a/trunk/drivers/net/wireless/mwifiex/util.c +++ b/trunk/drivers/net/wireless/mwifiex/util.c @@ -91,7 +91,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, memcpy(info->packets_out, priv->wmm.packets_out, sizeof(priv->wmm.packets_out)); - info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size; + info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; info->tx_buf_size = (u32) adapter->tx_buf_size; info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv, info->rx_tbl); diff --git a/trunk/drivers/net/wireless/mwl8k.c b/trunk/drivers/net/wireless/mwl8k.c index 8186af4ed47b..224cf917744a 100644 --- a/trunk/drivers/net/wireless/mwl8k.c +++ b/trunk/drivers/net/wireless/mwl8k.c @@ -285,9 +285,6 @@ struct mwl8k_priv { char *fw_pref; char *fw_alt; struct completion firmware_loading_complete; - - /* bitmap of running BSSes */ - u32 running_bsses; }; #define MAX_WEP_KEY_LEN 13 @@ -1149,6 +1146,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL); if (rxq->buf == NULL) { + wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); return -ENOMEM; } @@ -1441,6 +1439,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL); if (txq->skb == NULL) { + wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); return -ENOMEM; } @@ -2157,8 +2156,6 @@ static void mwl8k_fw_unlock(struct ieee80211_hw *hw) } } -static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, - u32 bitmap); /* * Command processing. @@ -2177,34 +2174,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) int rc; unsigned long timeout = 0; u8 buf[32]; - u32 bitmap = 0; - - wiphy_dbg(hw->wiphy, "Posting %s [%d]\n", - mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), cmd->macid); - - /* Before posting firmware commands that could change the hardware - * characteristics, make sure that all BSSes are stopped temporary. - * Enable these stopped BSSes after completion of the commands - */ - - rc = mwl8k_fw_lock(hw); - if (rc) - return rc; - - if (priv->ap_fw && priv->running_bsses) { - switch (le16_to_cpu(cmd->code)) { - case MWL8K_CMD_SET_RF_CHANNEL: - case MWL8K_CMD_RADIO_CONTROL: - case MWL8K_CMD_RF_TX_POWER: - case MWL8K_CMD_TX_POWER: - case MWL8K_CMD_RF_ANTENNA: - case MWL8K_CMD_RTS_THRESHOLD: - case MWL8K_CMD_MIMO_CONFIG: - bitmap = priv->running_bsses; - mwl8k_enable_bsses(hw, false, bitmap); - break; - } - } cmd->result = (__force __le16) 0xffff; dma_size = le16_to_cpu(cmd->length); @@ -2213,6 +2182,13 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) if (pci_dma_mapping_error(priv->pdev, dma_addr)) return -ENOMEM; + rc = mwl8k_fw_lock(hw); + if (rc) { + pci_unmap_single(priv->pdev, dma_addr, dma_size, + PCI_DMA_BIDIRECTIONAL); + return rc; + } + priv->hostcmd_wait = &cmd_wait; iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); iowrite32(MWL8K_H2A_INT_DOORBELL, @@ -2225,6 +2201,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) priv->hostcmd_wait = NULL; + mwl8k_fw_unlock(hw); pci_unmap_single(priv->pdev, dma_addr, dma_size, PCI_DMA_BIDIRECTIONAL); @@ -2251,11 +2228,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) ms); } - if (bitmap) - mwl8k_enable_bsses(hw, true, bitmap); - - mwl8k_fw_unlock(hw); - return rc; } @@ -2517,7 +2489,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->hw_rev = cmd->hw_rev; mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); priv->ap_macids_supported = 0x000000ff; - priv->sta_macids_supported = 0x00000100; + priv->sta_macids_supported = 0x00000000; priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" @@ -3536,10 +3508,7 @@ static int mwl8k_cmd_update_mac_addr(struct ieee80211_hw *hw, mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) - if (priv->ap_fw) - mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; - else - mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; + mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; else mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { @@ -3711,16 +3680,8 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int enable) { struct mwl8k_cmd_bss_start *cmd; - struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); - struct mwl8k_priv *priv = hw->priv; int rc; - if (enable && (priv->running_bsses & (1 << mwl8k_vif->macid))) - return 0; - - if (!enable && !(priv->running_bsses & (1 << mwl8k_vif->macid))) - return 0; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -3732,31 +3693,9 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); - if (!rc) { - if (enable) - priv->running_bsses |= (1 << mwl8k_vif->macid); - else - priv->running_bsses &= ~(1 << mwl8k_vif->macid); - } return rc; } -static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, u32 bitmap) -{ - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_vif *mwl8k_vif, *tmp_vif; - struct ieee80211_vif *vif; - - list_for_each_entry_safe(mwl8k_vif, tmp_vif, &priv->vif_list, list) { - vif = mwl8k_vif->vif; - - if (!(bitmap & (1 << mwl8k_vif->macid))) - continue; - - if (vif->type == NL80211_IFTYPE_AP) - mwl8k_cmd_bss_start(hw, vif, enable); - } -} /* * CMD_BASTREAM. */ @@ -4263,9 +4202,8 @@ static int mwl8k_set_key(struct ieee80211_hw *hw, u8 encr_type; u8 *addr; struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); - struct mwl8k_priv *priv = hw->priv; - if (vif->type == NL80211_IFTYPE_STATION && !priv->ap_fw) + if (vif->type == NL80211_IFTYPE_STATION) return -EOPNOTSUPP; if (sta == NULL) @@ -4671,18 +4609,12 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, break; case NL80211_IFTYPE_STATION: if (priv->ap_fw && di->fw_image_sta) { - if (!list_empty(&priv->vif_list)) { - wiphy_warn(hw->wiphy, "AP interface is running.\n" - "Adding STA interface for WDS"); - } else { - /* we must load the sta fw to - * meet this request. - */ - rc = mwl8k_reload_firmware(hw, - di->fw_image_sta); - if (rc) - return rc; - } + /* we must load the sta fw to meet this request */ + if (!list_empty(&priv->vif_list)) + return -EBUSY; + rc = mwl8k_reload_firmware(hw, di->fw_image_sta); + if (rc) + return rc; } macids_supported = priv->sta_macids_supported; break; @@ -4706,7 +4638,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* Set the mac address. */ mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); - if (vif->type == NL80211_IFTYPE_AP) + if (priv->ap_fw) mwl8k_cmd_set_new_stn_add_self(hw, vif); priv->macids_used |= 1 << mwl8k_vif->macid; @@ -4731,7 +4663,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); - if (vif->type == NL80211_IFTYPE_AP) + if (priv->ap_fw) mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); mwl8k_cmd_del_mac_addr(hw, vif, vif->addr); @@ -4805,11 +4737,9 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (rc) goto out; - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - rc = mwl8k_cmd_set_rf_channel(hw, conf); - if (rc) - goto out; - } + rc = mwl8k_cmd_set_rf_channel(hw, conf); + if (rc) + goto out; if (conf->power_level > 18) conf->power_level = 18; @@ -4822,6 +4752,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) goto out; } + rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); + if (rc) + wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); + rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); + if (rc) + wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); } else { rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); @@ -4879,8 +4815,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_read_unlock(); } - if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && - !priv->ap_fw) { + if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); if (rc) goto out; @@ -4888,25 +4823,6 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rc = mwl8k_cmd_use_fixed_rate_sta(hw); if (rc) goto out; - } else { - if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && - priv->ap_fw) { - int idx; - int rate; - - /* Use AP firmware specific rate command. - */ - idx = ffs(vif->bss_conf.basic_rates); - if (idx) - idx--; - - if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) - rate = mwl8k_rates_24[idx].hw_value; - else - rate = mwl8k_rates_50[idx].hw_value; - - mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); - } } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -4916,13 +4832,13 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - if ((changed & BSS_CHANGED_ERP_SLOT) && !priv->ap_fw) { + if (changed & BSS_CHANGED_ERP_SLOT) { rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); if (rc) goto out; } - if (vif->bss_conf.assoc && !priv->ap_fw && + if (vif->bss_conf.assoc && (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))) { rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); @@ -5002,9 +4918,11 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { - if (vif->type == NL80211_IFTYPE_STATION) + struct mwl8k_priv *priv = hw->priv; + + if (!priv->ap_fw) mwl8k_bss_info_changed_sta(hw, vif, info, changed); - if (vif->type == NL80211_IFTYPE_AP) + else mwl8k_bss_info_changed_ap(hw, vif, info, changed); } @@ -5471,8 +5389,6 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, - { PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, }, - { PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, }, { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, { }, }; @@ -5731,15 +5647,6 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_free_irq; } - /* Configure Antennas */ - rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); - if (rc) - wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); - rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); - if (rc) - wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); - - /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); @@ -5827,7 +5734,6 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) static const struct ieee80211_iface_limit ap_if_limits[] = { { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, - { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, }; static const struct ieee80211_iface_combination ap_if_comb = { @@ -5920,7 +5826,6 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) if (priv->ap_macids_supported || priv->device_info->fw_image_ap) { hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); hw->wiphy->iface_combinations = &ap_if_comb; hw->wiphy->n_iface_combinations = 1; } @@ -6043,8 +5948,6 @@ static int mwl8k_probe(struct pci_dev *pdev, priv->hw_restart_in_progress = false; - priv->running_bsses = 0; - return rc; err_stop_firmware: diff --git a/trunk/drivers/net/wireless/p54/p54usb.c b/trunk/drivers/net/wireless/p54/p54usb.c index 1f7858588919..800a16526c8e 100644 --- a/trunk/drivers/net/wireless/p54/p54usb.c +++ b/trunk/drivers/net/wireless/p54/p54usb.c @@ -84,8 +84,8 @@ static struct usb_device_id p54u_table[] = { {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ + {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ - {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */ {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c index a658b4bc7da2..a5c694f23d33 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c @@ -80,7 +80,7 @@ static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev) rt2x00_rf(rt2x00dev, RF3022)) return true; - WARNING(rt2x00dev, "Unknown RF chipset on rt305x\n"); + NOTICE(rt2x00dev, "Unknown RF chipset on rt305x\n"); return false; } diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800pci.c b/trunk/drivers/net/wireless/rt2x00/rt2800pci.c index 48a01aa21f1c..0e8d1705e368 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1152,7 +1152,6 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x3562) }, { PCI_DEVICE(0x1814, 0x3592) }, { PCI_DEVICE(0x1814, 0x3593) }, - { PCI_DEVICE(0x1814, 0x359f) }, #endif #ifdef CONFIG_RT2800PCI_RT53XX { PCI_DEVICE(0x1814, 0x5360) }, diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800usb.c b/trunk/drivers/net/wireless/rt2x00/rt2800usb.c index 098613ed93fb..4721cada1591 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800usb.c @@ -540,9 +540,9 @@ rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { - DEBUG(entry->queue->rt2x00dev, - "TX status report missed for queue %d entry %d\n", - entry->queue->qid, entry->entry_idx); + WARNING(entry->queue->rt2x00dev, + "TX status report missed for queue %d entry %d\n", + entry->queue->qid, entry->entry_idx); return TXDONE_UNKNOWN; } @@ -968,7 +968,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c13) }, { USB_DEVICE(0x07d1, 0x3c15) }, { USB_DEVICE(0x07d1, 0x3c16) }, - { USB_DEVICE(0x07d1, 0x3c17) }, { USB_DEVICE(0x2001, 0x3c1b) }, /* Draytek */ { USB_DEVICE(0x07fa, 0x7712) }, @@ -1099,11 +1098,9 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x15a9, 0x0006) }, /* Sweex */ { USB_DEVICE(0x177f, 0x0153) }, - { USB_DEVICE(0x177f, 0x0164) }, { USB_DEVICE(0x177f, 0x0302) }, { USB_DEVICE(0x177f, 0x0313) }, { USB_DEVICE(0x177f, 0x0323) }, - { USB_DEVICE(0x177f, 0x0324) }, /* U-Media */ { USB_DEVICE(0x157e, 0x300e) }, { USB_DEVICE(0x157e, 0x3013) }, @@ -1118,7 +1115,6 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Zyxel */ { USB_DEVICE(0x0586, 0x3416) }, { USB_DEVICE(0x0586, 0x3418) }, - { USB_DEVICE(0x0586, 0x341a) }, { USB_DEVICE(0x0586, 0x341e) }, { USB_DEVICE(0x0586, 0x343e) }, #ifdef CONFIG_RT2800USB_RT33XX @@ -1135,9 +1131,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x148f, 0x8070) }, /* Sitecom */ { USB_DEVICE(0x0df6, 0x0050) }, - /* Sweex */ - { USB_DEVICE(0x177f, 0x0163) }, - { USB_DEVICE(0x177f, 0x0165) }, #endif #ifdef CONFIG_RT2800USB_RT35XX /* Allwin */ @@ -1173,7 +1166,6 @@ static struct usb_device_id rt2800usb_device_table[] = { #ifdef CONFIG_RT2800USB_RT53XX /* Arcadyan */ { USB_DEVICE(0x043e, 0x7a12) }, - { USB_DEVICE(0x043e, 0x7a32) }, /* Azurewave */ { USB_DEVICE(0x13d3, 0x3329) }, { USB_DEVICE(0x13d3, 0x3365) }, @@ -1185,20 +1177,16 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x2001, 0x3c1e) }, /* LG innotek */ { USB_DEVICE(0x043e, 0x7a22) }, - { USB_DEVICE(0x043e, 0x7a42) }, /* Panasonic */ { USB_DEVICE(0x04da, 0x1801) }, { USB_DEVICE(0x04da, 0x1800) }, - { USB_DEVICE(0x04da, 0x23f6) }, /* Philips */ { USB_DEVICE(0x0471, 0x2104) }, - { USB_DEVICE(0x0471, 0x2126) }, - { USB_DEVICE(0x0471, 0x2180) }, - { USB_DEVICE(0x0471, 0x2181) }, - { USB_DEVICE(0x0471, 0x2182) }, /* Ralink */ { USB_DEVICE(0x148f, 0x5370) }, { USB_DEVICE(0x148f, 0x5372) }, + /* Unknown */ + { USB_DEVICE(0x04da, 0x23f6) }, #endif #ifdef CONFIG_RT2800USB_UNKNOWN /* @@ -1219,15 +1207,10 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1760) }, { USB_DEVICE(0x0b05, 0x1761) }, { USB_DEVICE(0x0b05, 0x1790) }, - { USB_DEVICE(0x0b05, 0x17a7) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3262) }, { USB_DEVICE(0x13d3, 0x3284) }, { USB_DEVICE(0x13d3, 0x3322) }, - { USB_DEVICE(0x13d3, 0x3340) }, - { USB_DEVICE(0x13d3, 0x3399) }, - { USB_DEVICE(0x13d3, 0x3400) }, - { USB_DEVICE(0x13d3, 0x3401) }, /* Belkin */ { USB_DEVICE(0x050d, 0x1003) }, /* Buffalo */ @@ -1240,17 +1223,13 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x18c5, 0x0008) }, /* D-Link */ { USB_DEVICE(0x07d1, 0x3c0b) }, + { USB_DEVICE(0x07d1, 0x3c17) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1) }, - /* EnGenius */ - { USB_DEVICE(0x1740, 0x0600) }, - { USB_DEVICE(0x1740, 0x0602) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010) }, /* Gigabyte */ { USB_DEVICE(0x1044, 0x800c) }, - /* Hercules */ - { USB_DEVICE(0x06f8, 0xe036) }, /* Huawei */ { USB_DEVICE(0x148f, 0xf101) }, /* I-O DATA */ @@ -1277,17 +1256,13 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x004a) }, { USB_DEVICE(0x0df6, 0x004d) }, { USB_DEVICE(0x0df6, 0x0053) }, - { USB_DEVICE(0x0df6, 0x0069) }, - { USB_DEVICE(0x0df6, 0x006f) }, /* SMC */ { USB_DEVICE(0x083a, 0xa512) }, { USB_DEVICE(0x083a, 0xc522) }, { USB_DEVICE(0x083a, 0xd522) }, { USB_DEVICE(0x083a, 0xf511) }, - /* Sweex */ - { USB_DEVICE(0x177f, 0x0254) }, - /* TP-LINK */ - { USB_DEVICE(0xf201, 0x5370) }, + /* Zyxel */ + { USB_DEVICE(0x0586, 0x341a) }, #endif { 0, } }; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00.h b/trunk/drivers/net/wireless/rt2x00/rt2x00.h index 9a3f31a543ce..b52512b8ac5f 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00.h @@ -88,9 +88,11 @@ #define ERROR_PROBE(__msg, __args...) \ DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args) #define WARNING(__dev, __msg, __args...) \ - DEBUG_PRINTK_MSG(__dev, KERN_WARNING, "Warning", __msg, ##__args) + DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args) +#define NOTICE(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args) #define INFO(__dev, __msg, __args...) \ - DEBUG_PRINTK_MSG(__dev, KERN_INFO, "Info", __msg, ##__args) + DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args) #define DEBUG(__dev, __msg, __args...) \ DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args) #define EEPROM(__dev, __msg, __args...) \ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c b/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c index 1031db66474a..b40a53857498 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1236,8 +1236,7 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) */ if_limit = &rt2x00dev->if_limits_ap; if_limit->max = rt2x00dev->ops->max_ap_intf; - if_limit->types = BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT); + if_limit->types = BIT(NL80211_IFTYPE_AP); /* * Build up AP interface combinations structure. @@ -1447,7 +1446,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); #ifdef CONFIG_PM int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) { - DEBUG(rt2x00dev, "Going to sleep.\n"); + NOTICE(rt2x00dev, "Going to sleep.\n"); /* * Prevent mac80211 from accessing driver while suspended. @@ -1487,7 +1486,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_suspend); int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) { - DEBUG(rt2x00dev, "Waking up.\n"); + NOTICE(rt2x00dev, "Waking up.\n"); /* * Restore/enable extra components. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c index 20c6eccce5aa..ed7a1bb3f245 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -731,9 +731,9 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, queue->aifs = params->aifs; queue->txop = params->txop; - DEBUG(rt2x00dev, - "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", - queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); + INFO(rt2x00dev, + "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", + queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); return 0; } diff --git a/trunk/drivers/net/wireless/rtlwifi/rc.c b/trunk/drivers/net/wireless/rtlwifi/rc.c index 204f46c4510d..c1e065f136ba 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rc.c +++ b/trunk/drivers/net/wireless/rtlwifi/rc.c @@ -217,6 +217,19 @@ static void rtl_tx_status(void *ppriv, } } +static void rtl_rate_init(void *ppriv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) +{ +} + +static void rtl_rate_update(void *ppriv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed) +{ +} + static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { @@ -261,6 +274,8 @@ static struct rate_control_ops rtl_rate_ops = { .free = rtl_rate_free, .alloc_sta = rtl_rate_alloc_sta, .free_sta = rtl_rate_free_sta, + .rate_init = rtl_rate_init, + .rate_update = rtl_rate_update, .tx_status = rtl_tx_status, .get_rate = rtl_get_rate, }; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index b793a659a465..1cdf5a271c9f 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -669,8 +669,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw u8 thermalvalue, delta, delta_lck, delta_iqk; long ele_a, ele_d, temp_cck, val_x, value32; long val_y, ele_c = 0; - u8 ofdm_index[2], ofdm_index_old[2], cck_index_old = 0; - s8 cck_index = 0; + u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; int i; bool is2t = IS_92C_SERIAL(rtlhal->version); s8 txpwr_level[2] = {0, 0}; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index da0e9022a99a..c31795e379f7 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -488,7 +488,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, u8 *praddr; __le16 fc; u16 type, c_fc; - bool packet_matchbssid, packet_toself, packet_beacon = false; + bool packet_matchbssid, packet_toself, packet_beacon; tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 85b6bdb163c0..32ff959a0251 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -1084,7 +1084,7 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, u8 *praddr; __le16 fc; u16 type, cpu_fc; - bool packet_matchbssid, packet_toself, packet_beacon = false; + bool packet_matchbssid, packet_toself, packet_beacon; tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; hdr = (struct ieee80211_hdr *)tmp_buf; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index a73a17bc56dd..b7e6607e6b6d 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -76,7 +76,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) GFP_KERNEL, hw, rtl_fw_cb); - return err; + return 0; } static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw) @@ -285,7 +285,6 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, /* RTL8188CUS-VL */ {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, - {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)}, /* 8188 Combo for BC4 */ {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, @@ -364,15 +363,9 @@ static struct usb_device_id rtl8192c_usb_ids[] = { MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids); -static int rtl8192cu_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return rtl_usb_probe(intf, id, &rtl92cu_hal_cfg); -} - static struct usb_driver rtl8192cu_driver = { .name = "rtl8192cu", - .probe = rtl8192cu_probe, + .probe = rtl_usb_probe, .disconnect = rtl_usb_disconnect, .id_table = rtl8192c_usb_ids, diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 5251fb8a111e..fd8df233ff22 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -841,9 +841,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( long ele_a = 0, ele_d, temp_cck, val_x, value32; long val_y, ele_c = 0; u8 ofdm_index[2]; - s8 cck_index = 0; + u8 cck_index = 0; u8 ofdm_index_old[2]; - s8 cck_index_old = 0; + u8 cck_index_old = 0; u8 index; int i; bool is2t = IS_92D_SINGLEPHY(rtlhal->version); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c index 35cb8f83eed4..f55b1767ef57 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c @@ -252,7 +252,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, u16 box_reg = 0, box_extreg = 0; u8 u1tmp; bool isfw_rd = false; - bool bwrite_success = false; + bool bwrite_sucess = false; u8 wait_h2c_limmit = 100; u8 wait_writeh2c_limmit = 100; u8 boxcontent[4], boxextcontent[2]; @@ -291,7 +291,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, } } - while (!bwrite_success) { + while (!bwrite_sucess) { wait_writeh2c_limmit--; if (wait_writeh2c_limmit == 0) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -429,7 +429,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw, break; } - bwrite_success = true; + bwrite_sucess = true; rtlhal->last_hmeboxnum = boxnum + 1; if (rtlhal->last_hmeboxnum == 4) @@ -512,6 +512,7 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw, struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; + u8 own; unsigned long flags; struct sk_buff *pskb = NULL; @@ -524,6 +525,7 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw, spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c index 68c28340f791..887d521fe690 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c @@ -1433,6 +1433,7 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 bt_retry_cnt; u8 bt_info_original; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, "[BTCoex] Get bt info by fw!!\n"); @@ -1444,6 +1445,7 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw) "[BTCoex] c2h for btInfo not rcvd yet!!\n"); } + bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt; bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original; /* when bt inquiry or page scan, we have to set h2c 0x25 diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 149804816ac4..0a8c03863fb2 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -703,9 +703,11 @@ static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); u8 reg_bw_opmode; - u32 reg_prsr; + u32 reg_ratr, reg_prsr; reg_bw_opmode = BW_OPMODE_20MHZ; + reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | + RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); @@ -2028,7 +2030,7 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_phy *rtlphy = &(rtlpriv->phy); - enum rf_pwrstate e_rfpowerstate_toset; + enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; u8 u1tmp; bool actuallyset = false; @@ -2047,6 +2049,8 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) spin_unlock(&rtlpriv->locks.rf_ps_lock); } + cur_rfstate = ppsc->rfpwr_state; + rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2, rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1))); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index eafbb18dd48e..3d8536bb0d2b 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c @@ -614,11 +614,17 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); int i; + bool rtstatus = true; u32 *radioa_array_table; - u16 radioa_arraylen; + u32 *radiob_array_table; + u16 radioa_arraylen, radiob_arraylen; radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH; radioa_array_table = RTL8723E_RADIOA_1TARRAY; + radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH; + radiob_array_table = RTL8723E_RADIOB_1TARRAY; + + rtstatus = true; switch (rfpath) { case RF90_PATH_A: @@ -1525,8 +1531,11 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, 0x522, 0x550, 0x551, 0x040 }; const u32 retrycount = 2; + u32 bbvalue; if (t == 0) { + bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD); + phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); } @@ -1703,7 +1712,8 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) long result[4][8]; u8 i, final_candidate; bool patha_ok, pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0; + long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, + reg_ecc, reg_tmp = 0; bool is12simular, is13simular, is23simular; bool start_conttx = false, singletone = false; u32 iqk_bb_reg[10] = { @@ -1770,15 +1780,21 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; + reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; + reg_ec4 = result[i][6]; + reg_ecc = result[i][7]; } if (final_candidate != 0xff) { rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; + reg_eac = result[final_candidate][3]; rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; + reg_ec4 = result[final_candidate][6]; + reg_ecc = result[final_candidate][7]; patha_ok = pathb_ok = true; } else { rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index b1fd2b328abf..ce8ad12bce5b 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -244,6 +244,7 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr; u8 *tmp_buf; u8 *praddr; + u8 *psaddr; __le16 fc; u16 type; bool packet_matchbssid, packet_toself, packet_beacon = false; @@ -254,6 +255,7 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw, fc = hdr->frame_control; type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; + psaddr = ieee80211_get_SA(hdr); packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && (!compare_ether_addr(mac->bssid, diff --git a/trunk/drivers/net/wireless/rtlwifi/usb.c b/trunk/drivers/net/wireless/rtlwifi/usb.c index 80730c72e0d6..f2ecdeb3a90d 100644 --- a/trunk/drivers/net/wireless/rtlwifi/usb.c +++ b/trunk/drivers/net/wireless/rtlwifi/usb.c @@ -825,6 +825,8 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, u32 ep_num; struct urb *_urb = NULL; struct sk_buff *_skb = NULL; + struct sk_buff_head *skb_list; + struct usb_anchor *urb_list; WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); if (unlikely(IS_USB_STOP(rtlusb))) { @@ -834,6 +836,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, return; } ep_num = rtlusb->ep_map.ep_mapping[qnum]; + skb_list = &rtlusb->tx_skb_queue[ep_num]; _skb = skb; _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num); if (unlikely(!_urb)) { @@ -841,6 +844,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, "Can't allocate urb. Drop skb!\n"); return; } + urb_list = &rtlusb->tx_pending[ep_num]; _rtl_submit_tx_urb(hw, _urb); } @@ -937,8 +941,7 @@ static struct rtl_intf_ops rtl_usb_ops = { }; int rtl_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id, - struct rtl_hal_cfg *rtl_hal_cfg) + const struct usb_device_id *id) { int err; struct ieee80211_hw *hw = NULL; @@ -973,7 +976,7 @@ int rtl_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, hw); /* init cfg & intf_ops */ rtlpriv->rtlhal.interface = INTF_USB; - rtlpriv->cfg = rtl_hal_cfg; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info); rtlpriv->intf_ops = &rtl_usb_ops; rtl_dbgp_flag_init(hw); /* Init IO handler */ diff --git a/trunk/drivers/net/wireless/rtlwifi/usb.h b/trunk/drivers/net/wireless/rtlwifi/usb.h index fb986f98d1df..5235136f6dd2 100644 --- a/trunk/drivers/net/wireless/rtlwifi/usb.h +++ b/trunk/drivers/net/wireless/rtlwifi/usb.h @@ -157,8 +157,7 @@ struct rtl_usb_priv { int rtl_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id, - struct rtl_hal_cfg *rtl92cu_hal_cfg); + const struct usb_device_id *id); void rtl_usb_disconnect(struct usb_interface *intf); int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message); int rtl_usb_resume(struct usb_interface *pusb_intf); diff --git a/trunk/drivers/net/wireless/rtlwifi/wifi.h b/trunk/drivers/net/wireless/rtlwifi/wifi.h index f13258a8d995..21a5f4f4a135 100644 --- a/trunk/drivers/net/wireless/rtlwifi/wifi.h +++ b/trunk/drivers/net/wireless/rtlwifi/wifi.h @@ -1702,7 +1702,7 @@ struct rtl_works { struct rtl_debug { u32 dbgp_type[DBGP_TYPE_MAX]; - int global_debuglevel; + u32 global_debuglevel; u64 global_debugcomponents; /* add for proc debug */ diff --git a/trunk/drivers/net/wireless/ti/Kconfig b/trunk/drivers/net/wireless/ti/Kconfig index cbe1e7fef61b..be800119d0a3 100644 --- a/trunk/drivers/net/wireless/ti/Kconfig +++ b/trunk/drivers/net/wireless/ti/Kconfig @@ -12,13 +12,4 @@ source "drivers/net/wireless/ti/wl18xx/Kconfig" # keep last for automatic dependencies source "drivers/net/wireless/ti/wlcore/Kconfig" - -config WILINK_PLATFORM_DATA - bool "TI WiLink platform data" - depends on WLCORE_SDIO || WL1251_SDIO - default y - ---help--- - Small platform data bit needed to pass data to the sdio modules. - - endif # WL_TI diff --git a/trunk/drivers/net/wireless/ti/Makefile b/trunk/drivers/net/wireless/ti/Makefile index af14231aeede..4d6823983c04 100644 --- a/trunk/drivers/net/wireless/ti/Makefile +++ b/trunk/drivers/net/wireless/ti/Makefile @@ -1,7 +1,5 @@ obj-$(CONFIG_WLCORE) += wlcore/ obj-$(CONFIG_WL12XX) += wl12xx/ +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/ obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL18XX) += wl18xx/ - -# small builtin driver bit -obj-$(CONFIG_WILINK_PLATFORM_DATA) += wilink_platform_data.o diff --git a/trunk/drivers/net/wireless/ti/wl1251/Kconfig b/trunk/drivers/net/wireless/ti/wl1251/Kconfig index 8fec4ed36ac2..1fb65849414f 100644 --- a/trunk/drivers/net/wireless/ti/wl1251/Kconfig +++ b/trunk/drivers/net/wireless/ti/wl1251/Kconfig @@ -1,6 +1,6 @@ menuconfig WL1251 tristate "TI wl1251 driver support" - depends on MAC80211 && GENERIC_HARDIRQS + depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS select FW_LOADER select CRC7 ---help--- diff --git a/trunk/drivers/net/wireless/ti/wl12xx/Makefile b/trunk/drivers/net/wireless/ti/wl12xx/Makefile index e6a24056b3c8..da509aa7d009 100644 --- a/trunk/drivers/net/wireless/ti/wl12xx/Makefile +++ b/trunk/drivers/net/wireless/ti/wl12xx/Makefile @@ -1,3 +1,3 @@ -wl12xx-objs = main.o cmd.o acx.o debugfs.o scan.o event.o +wl12xx-objs = main.o cmd.o acx.o debugfs.o obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/trunk/drivers/net/wireless/ti/wl12xx/cmd.c b/trunk/drivers/net/wireless/ti/wl12xx/cmd.c index 7dc9f965037d..622206241e83 100644 --- a/trunk/drivers/net/wireless/ti/wl12xx/cmd.c +++ b/trunk/drivers/net/wireless/ti/wl12xx/cmd.c @@ -284,40 +284,3 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl) kfree(radio_parms); return ret; } - -int wl12xx_cmd_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch) -{ - struct wl12xx_cmd_channel_switch *cmd; - int ret; - - wl1271_debug(DEBUG_ACX, "cmd channel switch"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->role_id = wlvif->role_id; - cmd->channel = ch_switch->channel->hw_value; - cmd->switch_time = ch_switch->count; - cmd->stop_tx = ch_switch->block_tx; - - /* FIXME: control from mac80211 in the future */ - /* Enable TX on the target channel */ - cmd->post_switch_tx_disable = 0; - - ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send channel switch command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} diff --git a/trunk/drivers/net/wireless/ti/wl12xx/cmd.h b/trunk/drivers/net/wireless/ti/wl12xx/cmd.h index 32cbad54e993..140a0e8829d5 100644 --- a/trunk/drivers/net/wireless/ti/wl12xx/cmd.h +++ b/trunk/drivers/net/wireless/ti/wl12xx/cmd.h @@ -103,30 +103,10 @@ struct wl1271_ext_radio_parms_cmd { u8 padding[3]; } __packed; -struct wl12xx_cmd_channel_switch { - struct wl1271_cmd_header header; - - u8 role_id; - - /* The new serving channel */ - u8 channel; - /* Relative time of the serving channel switch in TBTT units */ - u8 switch_time; - /* Stop the role TX, should expect it after radar detection */ - u8 stop_tx; - /* The target channel tx status 1-stopped 0-open*/ - u8 post_switch_tx_disable; - - u8 padding[3]; -} __packed; - int wl1271_cmd_general_parms(struct wl1271 *wl); int wl128x_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); int wl128x_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); -int wl12xx_cmd_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch); #endif /* __WL12XX_CMD_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wl12xx/event.c b/trunk/drivers/net/wireless/ti/wl12xx/event.c deleted file mode 100644 index 6ac0ed751da8..000000000000 --- a/trunk/drivers/net/wireless/ti/wl12xx/event.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "event.h" -#include "scan.h" -#include "../wlcore/cmd.h" -#include "../wlcore/debug.h" - -int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, - bool *timeout) -{ - u32 local_event; - - switch (event) { - case WLCORE_EVENT_ROLE_STOP_COMPLETE: - local_event = ROLE_STOP_COMPLETE_EVENT_ID; - break; - - case WLCORE_EVENT_PEER_REMOVE_COMPLETE: - local_event = PEER_REMOVE_COMPLETE_EVENT_ID; - break; - - default: - /* event not implemented */ - return 0; - } - return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); -} - -int wl12xx_process_mailbox_events(struct wl1271 *wl) -{ - struct wl12xx_event_mailbox *mbox = wl->mbox; - u32 vector; - - - vector = le32_to_cpu(mbox->events_vector); - vector &= ~(le32_to_cpu(mbox->events_mask)); - - wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, "status: 0x%x", - mbox->scheduled_scan_status); - - if (wl->scan_wlvif) - wl12xx_scan_completed(wl, wl->scan_wlvif); - } - - if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, - "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)", - mbox->scheduled_scan_status); - - wlcore_scan_sched_scan_results(wl); - } - - if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) - wlcore_event_sched_scan_completed(wl, - mbox->scheduled_scan_status); - if (vector & SOFT_GEMINI_SENSE_EVENT_ID) - wlcore_event_soft_gemini_sense(wl, - mbox->soft_gemini_sense_info); - - if (vector & BSS_LOSE_EVENT_ID) - wlcore_event_beacon_loss(wl, 0xff); - - if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) - wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric); - - if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) - wlcore_event_ba_rx_constraint(wl, - BIT(mbox->role_id), - mbox->rx_ba_allowed); - - if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) - wlcore_event_channel_switch(wl, 0xff, - mbox->channel_switch_status); - - if (vector & DUMMY_PACKET_EVENT_ID) - wlcore_event_dummy_packet(wl); - - /* - * "TX retries exceeded" has a different meaning according to mode. - * In AP mode the offending station is disconnected. - */ - if (vector & MAX_TX_RETRY_EVENT_ID) - wlcore_event_max_tx_failure(wl, - le16_to_cpu(mbox->sta_tx_retry_exceeded)); - - if (vector & INACTIVE_STA_EVENT_ID) - wlcore_event_inactive_sta(wl, - le16_to_cpu(mbox->sta_aging_status)); - - if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) - wlcore_event_roc_complete(wl); - - return 0; -} diff --git a/trunk/drivers/net/wireless/ti/wl12xx/event.h b/trunk/drivers/net/wireless/ti/wl12xx/event.h deleted file mode 100644 index a5cc3fcd9eea..000000000000 --- a/trunk/drivers/net/wireless/ti/wl12xx/event.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_EVENT_H__ -#define __WL12XX_EVENT_H__ - -#include "../wlcore/wlcore.h" - -enum { - MEASUREMENT_START_EVENT_ID = BIT(8), - MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), - SCAN_COMPLETE_EVENT_ID = BIT(10), - WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), - AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), - RESERVED1 = BIT(13), - PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), - ROLE_STOP_COMPLETE_EVENT_ID = BIT(15), - RADAR_DETECTED_EVENT_ID = BIT(16), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), - BSS_LOSE_EVENT_ID = BIT(18), - REGAINED_BSS_EVENT_ID = BIT(19), - MAX_TX_RETRY_EVENT_ID = BIT(20), - DUMMY_PACKET_EVENT_ID = BIT(21), - SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), - CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23), - SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), - PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), - INACTIVE_STA_EVENT_ID = BIT(26), - PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), - PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), - PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), - BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), - REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), -}; - -struct wl12xx_event_mailbox { - __le32 events_vector; - __le32 events_mask; - __le32 reserved_1; - __le32 reserved_2; - - u8 number_of_scan_results; - u8 scan_tag; - u8 completed_scan_status; - u8 reserved_3; - - u8 soft_gemini_sense_info; - u8 soft_gemini_protective_info; - s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; - u8 change_auto_mode_timeout; - u8 scheduled_scan_status; - u8 reserved4; - /* tuned channel (roc) */ - u8 roc_channel; - - __le16 hlid_removed_bitmap; - - /* bitmap of aged stations (by HLID) */ - __le16 sta_aging_status; - - /* bitmap of stations (by HLID) which exceeded max tx retries */ - __le16 sta_tx_retry_exceeded; - - /* discovery completed results */ - u8 discovery_tag; - u8 number_of_preq_results; - u8 number_of_prsp_results; - u8 reserved_5; - - /* rx ba constraint */ - u8 role_id; /* 0xFF means any role. */ - u8 rx_ba_allowed; - u8 reserved_6[2]; - - /* Channel switch results */ - - u8 channel_switch_role_id; - u8 channel_switch_status; - u8 reserved_7[2]; - - u8 ps_poll_delivery_failure_role_ids; - u8 stopped_role_ids; - u8 started_role_ids; - - u8 reserved_8[9]; -} __packed; - -int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, - bool *timeout); -int wl12xx_process_mailbox_events(struct wl1271 *wl); - -#endif - diff --git a/trunk/drivers/net/wireless/ti/wl12xx/main.c b/trunk/drivers/net/wireless/ti/wl12xx/main.c index 09694e39bb14..e5f5f8f39144 100644 --- a/trunk/drivers/net/wireless/ti/wl12xx/main.c +++ b/trunk/drivers/net/wireless/ti/wl12xx/main.c @@ -38,8 +38,6 @@ #include "reg.h" #include "cmd.h" #include "acx.h" -#include "scan.h" -#include "event.h" #include "debugfs.h" static char *fref_param; @@ -210,8 +208,6 @@ static struct wlcore_conf wl12xx_conf = { .tmpl_short_retry_limit = 10, .tmpl_long_retry_limit = 10, .tx_watchdog_timeout = 5000, - .slow_link_thold = 3, - .fast_link_thold = 10, }, .conn = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, @@ -269,10 +265,8 @@ static struct wlcore_conf wl12xx_conf = { .scan = { .min_dwell_time_active = 7500, .max_dwell_time_active = 30000, - .min_dwell_time_active_long = 25000, - .max_dwell_time_active_long = 50000, - .dwell_time_passive = 100000, - .dwell_time_dfs = 150000, + .min_dwell_time_passive = 100000, + .max_dwell_time_passive = 100000, .num_probe_reqs = 2, .split_scan_timeout = 50000, }, @@ -374,10 +368,6 @@ static struct wlcore_conf wl12xx_conf = { .increase_time = 1, .window_size = 16, }, - .recovery = { - .bug_on_recovery = 0, - .no_recovery = 0, - }, }; static struct wl12xx_priv_conf wl12xx_default_priv_conf = { @@ -611,9 +601,9 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) { int ret; - if (wl->chip.id != CHIP_ID_128X_PG20) { + if (wl->chip.id != CHIP_ID_1283_PG20) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; - struct wl12xx_priv *priv = wl->priv; + struct wl127x_rx_mem_pool_addr rx_mem_addr; /* * Choose the block we want to read @@ -622,13 +612,13 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) */ u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK; - priv->rx_mem_addr->addr = (mem_block << 8) + + rx_mem_addr.addr = (mem_block << 8) + le32_to_cpu(wl_mem_map->packet_memory_pool_start); - priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4; + rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; - ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr, - sizeof(*priv->rx_mem_addr), false); + ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr, + sizeof(rx_mem_addr), false); if (ret < 0) return ret; } @@ -641,15 +631,13 @@ static int wl12xx_identify_chip(struct wl1271 *wl) int ret = 0; switch (wl->chip.id) { - case CHIP_ID_127X_PG10: + case CHIP_ID_1271_PG10: wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", wl->chip.id); wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | WLCORE_QUIRK_DUAL_PROBE_TMPL | - WLCORE_QUIRK_TKIP_HEADER_SPACE | - WLCORE_QUIRK_START_STA_FAILS | - WLCORE_QUIRK_AP_ZERO_SESSION_ID; + WLCORE_QUIRK_TKIP_HEADER_SPACE; wl->sr_fw_name = WL127X_FW_NAME_SINGLE; wl->mr_fw_name = WL127X_FW_NAME_MULTI; memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, @@ -658,22 +646,18 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* read data preparation is only needed by wl127x */ wl->ops->prepare_read = wl127x_prepare_read; - wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, - WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, - WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER, - WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER, - WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER); + wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, + WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, + WL127X_MINOR_VER); break; - case CHIP_ID_127X_PG20: + case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | WLCORE_QUIRK_DUAL_PROBE_TMPL | - WLCORE_QUIRK_TKIP_HEADER_SPACE | - WLCORE_QUIRK_START_STA_FAILS | - WLCORE_QUIRK_AP_ZERO_SESSION_ID; + WLCORE_QUIRK_TKIP_HEADER_SPACE; wl->plt_fw_name = WL127X_PLT_FW_NAME; wl->sr_fw_name = WL127X_FW_NAME_SINGLE; wl->mr_fw_name = WL127X_FW_NAME_MULTI; @@ -683,14 +667,12 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* read data preparation is only needed by wl127x */ wl->ops->prepare_read = wl127x_prepare_read; - wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, - WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, - WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER, - WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER, - WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER); + wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, + WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, + WL127X_MINOR_VER); break; - case CHIP_ID_128X_PG20: + case CHIP_ID_1283_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", wl->chip.id); wl->plt_fw_name = WL128X_PLT_FW_NAME; @@ -700,29 +682,19 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* wl128x requires TX blocksize alignment */ wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | WLCORE_QUIRK_DUAL_PROBE_TMPL | - WLCORE_QUIRK_TKIP_HEADER_SPACE | - WLCORE_QUIRK_START_STA_FAILS | - WLCORE_QUIRK_AP_ZERO_SESSION_ID; - - wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, - WL128X_IFTYPE_SR_VER, WL128X_MAJOR_SR_VER, - WL128X_SUBTYPE_SR_VER, WL128X_MINOR_SR_VER, - WL128X_IFTYPE_MR_VER, WL128X_MAJOR_MR_VER, - WL128X_SUBTYPE_MR_VER, WL128X_MINOR_MR_VER); + WLCORE_QUIRK_TKIP_HEADER_SPACE; + + wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER, + WL128X_MAJOR_VER, WL128X_SUBTYPE_VER, + WL128X_MINOR_VER); break; - case CHIP_ID_128X_PG10: + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; goto out; } - /* common settings */ - wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY; - wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY; - wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; - wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; - wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ; out: return ret; } @@ -1095,7 +1067,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl) u32 clk; int selected_clock = -1; - if (wl->chip.id == CHIP_ID_128X_PG20) { + if (wl->chip.id == CHIP_ID_1283_PG20) { ret = wl128x_boot_clk(wl, &selected_clock); if (ret < 0) goto out; @@ -1126,7 +1098,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - if (wl->chip.id == CHIP_ID_128X_PG20) + if (wl->chip.id == CHIP_ID_1283_PG20) clk |= ((selected_clock & 0x3) << 1) << 4; else clk |= (priv->ref_clock << 1) << 4; @@ -1180,7 +1152,7 @@ static int wl12xx_pre_upload(struct wl1271 *wl) /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ - if (wl->chip.id == CHIP_ID_128X_PG20) { + if (wl->chip.id == CHIP_ID_1283_PG20) { ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); if (ret < 0) goto out; @@ -1247,23 +1219,6 @@ static int wl12xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl->event_mask = BSS_LOSE_EVENT_ID | - REGAINED_BSS_EVENT_ID | - SCAN_COMPLETE_EVENT_ID | - ROLE_STOP_COMPLETE_EVENT_ID | - RSSI_SNR_TRIGGER_0_EVENT_ID | - PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID | - PERIODIC_SCAN_REPORT_EVENT_ID | - PERIODIC_SCAN_COMPLETE_EVENT_ID | - DUMMY_PACKET_EVENT_ID | - PEER_REMOVE_COMPLETE_EVENT_ID | - BA_SESSION_RX_CONSTRAINT_EVENT_ID | - REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | - INACTIVE_STA_EVENT_ID | - MAX_TX_RETRY_EVENT_ID | - CHANNEL_SWITCH_COMPLETE_EVENT_ID; - ret = wlcore_boot_run_firmware(wl); if (ret < 0) goto out; @@ -1306,7 +1261,7 @@ static void wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, u32 blks, u32 spare_blks) { - if (wl->chip.id == CHIP_ID_128X_PG20) { + if (wl->chip.id == CHIP_ID_1283_PG20) { desc->wl128x_mem.total_mem_blocks = blks; } else { desc->wl127x_mem.extra_blocks = spare_blks; @@ -1320,7 +1275,7 @@ wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, { u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len); - if (wl->chip.id == CHIP_ID_128X_PG20) { + if (wl->chip.id == CHIP_ID_1283_PG20) { desc->wl128x_mem.extra_bytes = aligned_len - skb->len; desc->length = cpu_to_le16(aligned_len >> 2); @@ -1384,7 +1339,7 @@ static int wl12xx_hw_init(struct wl1271 *wl) { int ret; - if (wl->chip.id == CHIP_ID_128X_PG20) { + if (wl->chip.id == CHIP_ID_1283_PG20) { u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; ret = wl128x_cmd_general_parms(wl); @@ -1439,6 +1394,22 @@ static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl, return wlvif->rate_set; } +static int wl12xx_identify_fw(struct wl1271 *wl) +{ + unsigned int *fw_ver = wl->chip.fw_ver; + + /* Only new station firmwares support routing fw logs to the host */ + if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) + wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; + + /* This feature is not yet supported for AP mode */ + if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) + wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; + + return 0; +} + static void wl12xx_conf_init(struct wl1271 *wl) { struct wl12xx_priv *priv = wl->priv; @@ -1455,7 +1426,7 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl) bool supported = false; u8 major, minor; - if (wl->chip.id == CHIP_ID_128X_PG20) { + if (wl->chip.id == CHIP_ID_1283_PG20) { major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); @@ -1511,7 +1482,7 @@ static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver) u16 die_info; int ret; - if (wl->chip.id == CHIP_ID_128X_PG20) + if (wl->chip.id == CHIP_ID_1283_PG20) ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1, &die_info); else @@ -1618,46 +1589,16 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, return wlcore_set_key(wl, cmd, vif, sta, key_conf); } -static int wl12xx_set_peer_cap(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, - u32 rate_set, u8 hlid) -{ - return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation, - hlid); -} - -static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk) -{ - u8 thold; - - if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map)) - thold = wl->conf.tx.fast_link_thold; - else - thold = wl->conf.tx.slow_link_thold; - - return lnk->allocated_pkts < thold; -} - -static bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk) -{ - /* any link is good for low priority */ - return true; -} - static int wl12xx_setup(struct wl1271 *wl); static struct wlcore_ops wl12xx_ops = { .setup = wl12xx_setup, .identify_chip = wl12xx_identify_chip, + .identify_fw = wl12xx_identify_fw, .boot = wl12xx_boot, .plt_init = wl12xx_plt_init, .trigger_cmd = wl12xx_trigger_cmd, .ack_event = wl12xx_ack_event, - .wait_for_event = wl12xx_wait_for_event, - .process_mailbox_events = wl12xx_process_mailbox_events, .calc_tx_blocks = wl12xx_calc_tx_blocks, .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, @@ -1674,17 +1615,9 @@ static struct wlcore_ops wl12xx_ops = { .set_rx_csum = NULL, .ap_get_mimo_wide_rate_mask = NULL, .debugfs_init = wl12xx_debugfs_add_files, - .scan_start = wl12xx_scan_start, - .scan_stop = wl12xx_scan_stop, - .sched_scan_start = wl12xx_sched_scan_start, - .sched_scan_stop = wl12xx_scan_sched_scan_stop, .get_spare_blocks = wl12xx_get_spare_blocks, .set_key = wl12xx_set_key, - .channel_switch = wl12xx_cmd_channel_switch, .pre_pkt_send = NULL, - .set_peer_cap = wl12xx_set_peer_cap, - .lnk_high_prio = wl12xx_lnk_high_prio, - .lnk_low_prio = wl12xx_lnk_low_prio, }; static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { @@ -1703,13 +1636,11 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { static int wl12xx_setup(struct wl1271 *wl) { struct wl12xx_priv *priv = wl->priv; - struct wlcore_platdev_data *pdev_data = wl->pdev->dev.platform_data; - struct wl12xx_platform_data *pdata = pdev_data->pdata; + struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data; wl->rtable = wl12xx_rtable; wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS; - wl->num_channels = 1; wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES; wl->band_rate_to_idx = wl12xx_band_rate_to_idx; wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; @@ -1762,10 +1693,6 @@ static int wl12xx_setup(struct wl1271 *wl) wl1271_error("Invalid tcxo parameter %s", tcxo_param); } - priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL); - if (!priv->rx_mem_addr) - return -ENOMEM; - return 0; } @@ -1776,8 +1703,7 @@ static int wl12xx_probe(struct platform_device *pdev) int ret; hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv), - WL12XX_AGGR_BUFFER_SIZE, - sizeof(struct wl12xx_event_mailbox)); + WL12XX_AGGR_BUFFER_SIZE); if (IS_ERR(hw)) { wl1271_error("can't allocate hw"); ret = PTR_ERR(hw); @@ -1799,21 +1725,6 @@ static int wl12xx_probe(struct platform_device *pdev) return ret; } -static int wl12xx_remove(struct platform_device *pdev) -{ - struct wl1271 *wl = platform_get_drvdata(pdev); - struct wl12xx_priv *priv; - - if (!wl) - goto out; - priv = wl->priv; - - kfree(priv->rx_mem_addr); - -out: - return wlcore_remove(pdev); -} - static const struct platform_device_id wl12xx_id_table[] = { { "wl12xx", 0 }, { } /* Terminating Entry */ @@ -1822,7 +1733,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table); static struct platform_driver wl12xx_driver = { .probe = wl12xx_probe, - .remove = wl12xx_remove, + .remove = wlcore_remove, .id_table = wl12xx_id_table, .driver = { .name = "wl12xx_driver", diff --git a/trunk/drivers/net/wireless/ti/wl12xx/scan.c b/trunk/drivers/net/wireless/ti/wl12xx/scan.c deleted file mode 100644 index affdb3ec6225..000000000000 --- a/trunk/drivers/net/wireless/ti/wl12xx/scan.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include "scan.h" -#include "../wlcore/debug.h" -#include "../wlcore/tx.h" - -static int wl1271_get_scan_channels(struct wl1271 *wl, - struct cfg80211_scan_request *req, - struct basic_scan_channel_params *channels, - enum ieee80211_band band, bool passive) -{ - struct conf_scan_settings *c = &wl->conf.scan; - int i, j; - u32 flags; - - for (i = 0, j = 0; - i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; - i++) { - flags = req->channels[i]->flags; - - if (!test_bit(i, wl->scan.scanned_ch) && - !(flags & IEEE80211_CHAN_DISABLED) && - (req->channels[i]->band == band) && - /* - * In passive scans, we scan all remaining - * channels, even if not marked as such. - * In active scans, we only scan channels not - * marked as passive. - */ - (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { - wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", - req->channels[i]->band, - req->channels[i]->center_freq); - wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", - req->channels[i]->hw_value, - req->channels[i]->flags); - wl1271_debug(DEBUG_SCAN, - "max_antenna_gain %d, max_power %d", - req->channels[i]->max_antenna_gain, - req->channels[i]->max_power); - wl1271_debug(DEBUG_SCAN, "beacon_found %d", - req->channels[i]->beacon_found); - - if (!passive) { - channels[j].min_duration = - cpu_to_le32(c->min_dwell_time_active); - channels[j].max_duration = - cpu_to_le32(c->max_dwell_time_active); - } else { - channels[j].min_duration = - cpu_to_le32(c->dwell_time_passive); - channels[j].max_duration = - cpu_to_le32(c->dwell_time_passive); - } - channels[j].early_termination = 0; - channels[j].tx_power_att = req->channels[i]->max_power; - channels[j].channel = req->channels[i]->hw_value; - - memset(&channels[j].bssid_lsb, 0xff, 4); - memset(&channels[j].bssid_msb, 0xff, 2); - - /* Mark the channels we already used */ - set_bit(i, wl->scan.scanned_ch); - - j++; - } - } - - return j; -} - -#define WL1271_NOTHING_TO_SCAN 1 - -static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum ieee80211_band band, - bool passive, u32 basic_rate) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct wl1271_cmd_scan *cmd; - struct wl1271_cmd_trigger_scan_to *trigger; - int ret; - u16 scan_options = 0; - - /* skip active scans if we don't have SSIDs */ - if (!passive && wl->scan.req->n_ssids == 0) - return WL1271_NOTHING_TO_SCAN; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!cmd || !trigger) { - ret = -ENOMEM; - goto out; - } - - if (wl->conf.scan.split_scan_timeout) - scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; - - if (passive) - scan_options |= WL1271_SCAN_OPT_PASSIVE; - - cmd->params.role_id = wlvif->role_id; - - if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { - ret = -EINVAL; - goto out; - } - - cmd->params.scan_options = cpu_to_le16(scan_options); - - cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, - cmd->channels, - band, passive); - if (cmd->params.n_ch == 0) { - ret = WL1271_NOTHING_TO_SCAN; - goto out; - } - - cmd->params.tx_rate = cpu_to_le32(basic_rate); - cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; - cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; - cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; - - if (band == IEEE80211_BAND_2GHZ) - cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; - else - cmd->params.band = WL1271_SCAN_BAND_5_GHZ; - - if (wl->scan.ssid_len && wl->scan.ssid) { - cmd->params.ssid_len = wl->scan.ssid_len; - memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); - } - - memcpy(cmd->addr, vif->addr, ETH_ALEN); - - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - cmd->params.role_id, band, - wl->scan.ssid, wl->scan.ssid_len, - wl->scan.req->ie, - wl->scan.req->ie_len, false); - if (ret < 0) { - wl1271_error("PROBE request template failed"); - goto out; - } - - trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); - ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger), 0); - if (ret < 0) { - wl1271_error("trigger scan to failed for hw scan"); - goto out; - } - - wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("SCAN failed"); - goto out; - } - -out: - kfree(cmd); - kfree(trigger); - return ret; -} - -int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl1271_cmd_header *cmd = NULL; - int ret = 0; - - if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) - return -EINVAL; - - wl1271_debug(DEBUG_CMD, "cmd scan stop"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, - sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("cmd stop_scan failed"); - goto out; - } -out: - kfree(cmd); - return ret; -} - -void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret = 0; - enum ieee80211_band band; - u32 rate, mask; - - switch (wl->scan.state) { - case WL1271_SCAN_STATE_IDLE: - break; - - case WL1271_SCAN_STATE_2GHZ_ACTIVE: - band = IEEE80211_BAND_2GHZ; - mask = wlvif->bitrate_masks[band]; - if (wl->scan.req->no_cck) { - mask &= ~CONF_TX_CCK_RATES; - if (!mask) - mask = CONF_TX_RATE_MASK_BASIC_P2P; - } - rate = wl1271_tx_min_rate_get(wl, mask); - ret = wl1271_scan_send(wl, wlvif, band, false, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; - wl1271_scan_stm(wl, wlvif); - } - - break; - - case WL1271_SCAN_STATE_2GHZ_PASSIVE: - band = IEEE80211_BAND_2GHZ; - mask = wlvif->bitrate_masks[band]; - if (wl->scan.req->no_cck) { - mask &= ~CONF_TX_CCK_RATES; - if (!mask) - mask = CONF_TX_RATE_MASK_BASIC_P2P; - } - rate = wl1271_tx_min_rate_get(wl, mask); - ret = wl1271_scan_send(wl, wlvif, band, true, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - if (wl->enable_11a) - wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; - else - wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl, wlvif); - } - - break; - - case WL1271_SCAN_STATE_5GHZ_ACTIVE: - band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); - ret = wl1271_scan_send(wl, wlvif, band, false, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; - wl1271_scan_stm(wl, wlvif); - } - - break; - - case WL1271_SCAN_STATE_5GHZ_PASSIVE: - band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); - ret = wl1271_scan_send(wl, wlvif, band, true, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl, wlvif); - } - - break; - - case WL1271_SCAN_STATE_DONE: - wl->scan.failed = false; - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); - break; - - default: - wl1271_error("invalid scan state"); - break; - } - - if (ret < 0) { - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); - } -} - -static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd, - struct wlcore_scan_channels *cmd_channels) -{ - memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive)); - memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active)); - cmd->dfs = cmd_channels->dfs; - cmd->n_pactive_ch = cmd_channels->passive_active; - - memcpy(cmd->channels_2, cmd_channels->channels_2, - sizeof(cmd->channels_2)); - memcpy(cmd->channels_5, cmd_channels->channels_5, - sizeof(cmd->channels_2)); - /* channels_4 are not supported, so no need to copy them */ -} - -int wl1271_scan_sched_scan_config(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) -{ - struct wl1271_cmd_sched_scan_config *cfg = NULL; - struct wlcore_scan_channels *cfg_channels = NULL; - struct conf_sched_scan_settings *c = &wl->conf.sched_scan; - int i, ret; - bool force_passive = !req->n_ssids; - - wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); - - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) - return -ENOMEM; - - cfg->role_id = wlvif->role_id; - cfg->rssi_threshold = c->rssi_threshold; - cfg->snr_threshold = c->snr_threshold; - cfg->n_probe_reqs = c->num_probe_reqs; - /* cycles set to 0 it means infinite (until manually stopped) */ - cfg->cycles = 0; - /* report APs when at least 1 is found */ - cfg->report_after = 1; - /* don't stop scanning automatically when something is found */ - cfg->terminate = 0; - cfg->tag = WL1271_SCAN_DEFAULT_TAG; - /* don't filter on BSS type */ - cfg->bss_type = SCAN_BSS_TYPE_ANY; - /* currently NL80211 supports only a single interval */ - for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) - cfg->intervals[i] = cpu_to_le32(req->interval); - - cfg->ssid_len = 0; - ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); - if (ret < 0) - goto out; - - cfg->filter_type = ret; - - wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); - - cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL); - if (!cfg_channels) { - ret = -ENOMEM; - goto out; - } - - if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels, - req->n_channels, req->n_ssids, - SCAN_TYPE_PERIODIC)) { - wl1271_error("scan channel list is empty"); - ret = -EINVAL; - goto out; - } - wl12xx_adjust_channels(cfg, cfg_channels); - - if (!force_passive && cfg->active[0]) { - u8 band = IEEE80211_BAND_2GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - wlvif->role_id, band, - req->ssids[0].ssid, - req->ssids[0].ssid_len, - ies->ie[band], - ies->len[band], true); - if (ret < 0) { - wl1271_error("2.4GHz PROBE request template failed"); - goto out; - } - } - - if (!force_passive && cfg->active[1]) { - u8 band = IEEE80211_BAND_5GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - wlvif->role_id, band, - req->ssids[0].ssid, - req->ssids[0].ssid_len, - ies->ie[band], - ies->len[band], true); - if (ret < 0) { - wl1271_error("5GHz PROBE request template failed"); - goto out; - } - } - - wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); - - ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, - sizeof(*cfg), 0); - if (ret < 0) { - wl1271_error("SCAN configuration failed"); - goto out; - } -out: - kfree(cfg_channels); - kfree(cfg); - return ret; -} - -int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl1271_cmd_sched_scan_start *start; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); - - if (wlvif->bss_type != BSS_TYPE_STA_BSS) - return -EOPNOTSUPP; - - if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) && - test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) - return -EBUSY; - - start = kzalloc(sizeof(*start), GFP_KERNEL); - if (!start) - return -ENOMEM; - - start->role_id = wlvif->role_id; - start->tag = WL1271_SCAN_DEFAULT_TAG; - - ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, - sizeof(*start), 0); - if (ret < 0) { - wl1271_error("failed to send scan start command"); - goto out_free; - } - -out_free: - kfree(start); - return ret; -} - -int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) -{ - int ret; - - ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); - if (ret < 0) - return ret; - - return wl1271_scan_sched_scan_start(wl, wlvif); -} - -void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl1271_cmd_sched_scan_stop *stop; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); - - /* FIXME: what to do if alloc'ing to stop fails? */ - stop = kzalloc(sizeof(*stop), GFP_KERNEL); - if (!stop) { - wl1271_error("failed to alloc memory to send sched scan stop"); - return; - } - - stop->role_id = wlvif->role_id; - stop->tag = WL1271_SCAN_DEFAULT_TAG; - - ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, - sizeof(*stop), 0); - if (ret < 0) { - wl1271_error("failed to send sched scan stop command"); - goto out_free; - } - -out_free: - kfree(stop); -} - -int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_scan_request *req) -{ - wl1271_scan_stm(wl, wlvif); - return 0; -} - -void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - wl1271_scan_stm(wl, wlvif); -} diff --git a/trunk/drivers/net/wireless/ti/wl12xx/scan.h b/trunk/drivers/net/wireless/ti/wl12xx/scan.h deleted file mode 100644 index 264af7ac2785..000000000000 --- a/trunk/drivers/net/wireless/ti/wl12xx/scan.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_SCAN_H__ -#define __WL12XX_SCAN_H__ - -#include "../wlcore/wlcore.h" -#include "../wlcore/cmd.h" -#include "../wlcore/scan.h" - -#define WL12XX_MAX_CHANNELS_5GHZ 23 - -struct basic_scan_params { - /* Scan option flags (WL1271_SCAN_OPT_*) */ - __le16 scan_options; - u8 role_id; - /* Number of scan channels in the list (maximum 30) */ - u8 n_ch; - /* This field indicates the number of probe requests to send - per channel for an active scan */ - u8 n_probe_reqs; - u8 tid_trigger; - u8 ssid_len; - u8 use_ssid_list; - - /* Rate bit field for sending the probes */ - __le32 tx_rate; - - u8 ssid[IEEE80211_MAX_SSID_LEN]; - /* Band to scan */ - u8 band; - - u8 scan_tag; - u8 padding2[2]; -} __packed; - -struct basic_scan_channel_params { - /* Duration in TU to wait for frames on a channel for active scan */ - __le32 min_duration; - __le32 max_duration; - __le32 bssid_lsb; - __le16 bssid_msb; - u8 early_termination; - u8 tx_power_att; - u8 channel; - /* FW internal use only! */ - u8 dfs_candidate; - u8 activity_detected; - u8 pad; -} __packed; - -struct wl1271_cmd_scan { - struct wl1271_cmd_header header; - - struct basic_scan_params params; - struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; - - /* src mac address */ - u8 addr[ETH_ALEN]; - u8 padding[2]; -} __packed; - -struct wl1271_cmd_sched_scan_config { - struct wl1271_cmd_header header; - - __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; - - s8 rssi_threshold; /* for filtering (in dBm) */ - s8 snr_threshold; /* for filtering (in dB) */ - - u8 cycles; /* maximum number of scan cycles */ - u8 report_after; /* report when this number of results are received */ - u8 terminate; /* stop scanning after reporting */ - - u8 tag; - u8 bss_type; /* for filtering */ - u8 filter_type; - - u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ - u8 ssid[IEEE80211_MAX_SSID_LEN]; - - u8 n_probe_reqs; /* Number of probes requests per channel */ - - u8 passive[SCAN_MAX_BANDS]; - u8 active[SCAN_MAX_BANDS]; - - u8 dfs; - - u8 n_pactive_ch; /* number of pactive (passive until fw detects energy) - channels in BG band */ - u8 role_id; - u8 padding[1]; - struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; - struct conn_scan_ch_params channels_5[WL12XX_MAX_CHANNELS_5GHZ]; - struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; -} __packed; - -struct wl1271_cmd_sched_scan_start { - struct wl1271_cmd_header header; - - u8 tag; - u8 role_id; - u8 padding[2]; -} __packed; - -struct wl1271_cmd_sched_scan_stop { - struct wl1271_cmd_header header; - - u8 tag; - u8 role_id; - u8 padding[2]; -} __packed; - -int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_scan_request *req); -int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); -void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); -void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); -#endif diff --git a/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h b/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h index d4552857480c..7182bbf6625d 100644 --- a/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h @@ -24,37 +24,19 @@ #include "conf.h" -/* WiLink 6/7 chip IDs */ -#define CHIP_ID_127X_PG10 (0x04030101) -#define CHIP_ID_127X_PG20 (0x04030111) -#define CHIP_ID_128X_PG10 (0x05030101) -#define CHIP_ID_128X_PG20 (0x05030111) - -/* FW chip version for wl127x */ +/* minimum FW required for driver for wl127x */ #define WL127X_CHIP_VER 6 -/* minimum single-role FW version for wl127x */ -#define WL127X_IFTYPE_SR_VER 3 -#define WL127X_MAJOR_SR_VER 10 -#define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE -#define WL127X_MINOR_SR_VER 115 -/* minimum multi-role FW version for wl127x */ -#define WL127X_IFTYPE_MR_VER 5 -#define WL127X_MAJOR_MR_VER 7 -#define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE -#define WL127X_MINOR_MR_VER 115 +#define WL127X_IFTYPE_VER 3 +#define WL127X_MAJOR_VER 10 +#define WL127X_SUBTYPE_VER 2 +#define WL127X_MINOR_VER 115 -/* FW chip version for wl128x */ +/* minimum FW required for driver for wl128x */ #define WL128X_CHIP_VER 7 -/* minimum single-role FW version for wl128x */ -#define WL128X_IFTYPE_SR_VER 3 -#define WL128X_MAJOR_SR_VER 10 -#define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE -#define WL128X_MINOR_SR_VER 115 -/* minimum multi-role FW version for wl128x */ -#define WL128X_IFTYPE_MR_VER 5 -#define WL128X_MAJOR_MR_VER 7 -#define WL128X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE -#define WL128X_MINOR_MR_VER 42 +#define WL128X_IFTYPE_VER 3 +#define WL128X_MAJOR_VER 10 +#define WL128X_SUBTYPE_VER 2 +#define WL128X_MINOR_VER 115 #define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) @@ -73,8 +55,6 @@ struct wl12xx_priv { int ref_clock; int tcxo_clock; - - struct wl127x_rx_mem_pool_addr *rx_mem_addr; }; #endif /* __WL12XX_PRIV_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wl18xx/Makefile b/trunk/drivers/net/wireless/ti/wl18xx/Makefile index ae2b81735785..67c098734c7f 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/Makefile +++ b/trunk/drivers/net/wireless/ti/wl18xx/Makefile @@ -1,3 +1,3 @@ -wl18xx-objs = main.o acx.o tx.o io.o debugfs.o scan.o cmd.o event.o +wl18xx-objs = main.o acx.o tx.o io.o debugfs.o obj-$(CONFIG_WL18XX) += wl18xx.o diff --git a/trunk/drivers/net/wireless/ti/wl18xx/acx.c b/trunk/drivers/net/wireless/ti/wl18xx/acx.c index a169bb5a5dbf..72840e23bf59 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/acx.c +++ b/trunk/drivers/net/wireless/ti/wl18xx/acx.c @@ -75,7 +75,7 @@ int wl18xx_acx_set_checksum_state(struct wl1271 *wl) acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED; - ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx)); + ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("failed to set Tx checksum state: %d", ret); goto out; @@ -109,88 +109,3 @@ int wl18xx_acx_clear_statistics(struct wl1271 *wl) kfree(acx); return ret; } - -int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide) -{ - struct wlcore_peer_ht_operation_mode *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d", - hlid, wide); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->hlid = hlid; - acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ; - - ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx, - sizeof(*acx)); - - if (ret < 0) { - wl1271_warning("acx peer ht operation mode failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; - -} - -/* - * this command is basically the same as wl1271_acx_ht_capabilities, - * with the addition of supported rates. they should be unified in - * the next fw api change - */ -int wl18xx_acx_set_peer_cap(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, - u32 rate_set, u8 hlid) -{ - struct wlcore_acx_peer_cap *acx; - int ret = 0; - u32 ht_capabilites = 0; - - wl1271_debug(DEBUG_ACX, - "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x", - ht_cap->ht_supported, ht_cap->cap, rate_set); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - if (allow_ht_operation && ht_cap->ht_supported) { - /* no need to translate capabilities - use the spec values */ - ht_capabilites = ht_cap->cap; - - /* - * this bit is not employed by the spec but only by FW to - * indicate peer HT support - */ - ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; - - /* get data from A-MPDU parameters field */ - acx->ampdu_max_length = ht_cap->ampdu_factor; - acx->ampdu_min_spacing = ht_cap->ampdu_density; - } - - acx->hlid = hlid; - acx->ht_capabilites = cpu_to_le32(ht_capabilites); - acx->supported_rates = cpu_to_le32(rate_set); - - ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ht capabilities setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} diff --git a/trunk/drivers/net/wireless/ti/wl18xx/acx.h b/trunk/drivers/net/wireless/ti/wl18xx/acx.h index 0e636def1217..e2609a6b7341 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/acx.h +++ b/trunk/drivers/net/wireless/ti/wl18xx/acx.h @@ -26,13 +26,7 @@ #include "../wlcore/acx.h" enum { - ACX_NS_IPV6_FILTER = 0x0050, - ACX_PEER_HT_OPERATION_MODE_CFG = 0x0051, - ACX_CSUM_CONFIG = 0x0052, - ACX_SIM_CONFIG = 0x0053, - ACX_CLEAR_STATISTICS = 0x0054, - ACX_AUTO_RX_STREAMING = 0x0055, - ACX_PEER_CAP = 0x0056 + ACX_CLEAR_STATISTICS = 0x0047, }; /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -284,57 +278,10 @@ struct wl18xx_acx_clear_statistics { struct acx_header header; }; -enum wlcore_bandwidth { - WLCORE_BANDWIDTH_20MHZ, - WLCORE_BANDWIDTH_40MHZ, -}; - -struct wlcore_peer_ht_operation_mode { - struct acx_header header; - - u8 hlid; - u8 bandwidth; /* enum wlcore_bandwidth */ - u8 padding[2]; -}; - -/* - * ACX_PEER_CAP - * this struct is very similar to wl1271_acx_ht_capabilities, with the - * addition of supported rates - */ -struct wlcore_acx_peer_cap { - struct acx_header header; - - /* bitmask of capability bits supported by the peer */ - __le32 ht_capabilites; - - /* rates supported by the remote peer */ - __le32 supported_rates; - - /* Indicates to which link these capabilities apply. */ - u8 hlid; - - /* - * This the maximum A-MPDU length supported by the AP. The FW may not - * exceed this length when sending A-MPDUs - */ - u8 ampdu_max_length; - - /* This is the minimal spacing required when sending A-MPDUs to the AP*/ - u8 ampdu_min_spacing; - - u8 padding; -} __packed; - int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, u32 len_field_size); int wl18xx_acx_set_checksum_state(struct wl1271 *wl); int wl18xx_acx_clear_statistics(struct wl1271 *wl); -int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide); -int wl18xx_acx_set_peer_cap(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, - u32 rate_set, u8 hlid); #endif /* __WL18XX_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wl18xx/cmd.c b/trunk/drivers/net/wireless/ti/wl18xx/cmd.c deleted file mode 100644 index 1d1f6cc7a50a..000000000000 --- a/trunk/drivers/net/wireless/ti/wl18xx/cmd.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of wl18xx - * - * Copyright (C) 2011 Texas Instruments Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "../wlcore/cmd.h" -#include "../wlcore/debug.h" -#include "../wlcore/hw_ops.h" - -#include "cmd.h" - -int wl18xx_cmd_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch) -{ - struct wl18xx_cmd_channel_switch *cmd; - u32 supported_rates; - int ret; - - wl1271_debug(DEBUG_ACX, "cmd channel switch"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->role_id = wlvif->role_id; - cmd->channel = ch_switch->channel->hw_value; - cmd->switch_time = ch_switch->count; - cmd->stop_tx = ch_switch->block_tx; - - switch (ch_switch->channel->band) { - case IEEE80211_BAND_2GHZ: - cmd->band = WLCORE_BAND_2_4GHZ; - break; - case IEEE80211_BAND_5GHZ: - cmd->band = WLCORE_BAND_5GHZ; - break; - default: - wl1271_error("invalid channel switch band: %d", - ch_switch->channel->band); - ret = -EINVAL; - goto out_free; - } - - supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | - wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); - if (wlvif->p2p) - supported_rates &= ~CONF_TX_CCK_RATES; - cmd->local_supported_rates = cpu_to_le32(supported_rates); - cmd->channel_type = wlvif->channel_type; - - ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send channel switch command"); - goto out_free; - } - -out_free: - kfree(cmd); -out: - return ret; -} diff --git a/trunk/drivers/net/wireless/ti/wl18xx/cmd.h b/trunk/drivers/net/wireless/ti/wl18xx/cmd.h deleted file mode 100644 index 6687d10899ac..000000000000 --- a/trunk/drivers/net/wireless/ti/wl18xx/cmd.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of wl18xx - * - * Copyright (C) 2011 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL18XX_CMD_H__ -#define __WL18XX_CMD_H__ - -#include "../wlcore/wlcore.h" -#include "../wlcore/acx.h" - -struct wl18xx_cmd_channel_switch { - struct wl1271_cmd_header header; - - u8 role_id; - - /* The new serving channel */ - u8 channel; - /* Relative time of the serving channel switch in TBTT units */ - u8 switch_time; - /* Stop the role TX, should expect it after radar detection */ - u8 stop_tx; - - __le32 local_supported_rates; - - u8 channel_type; - u8 band; - - u8 padding[2]; -} __packed; - -int wl18xx_cmd_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch); - -#endif diff --git a/trunk/drivers/net/wireless/ti/wl18xx/conf.h b/trunk/drivers/net/wireless/ti/wl18xx/conf.h index e34302e3b51d..4d426cc20274 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/conf.h +++ b/trunk/drivers/net/wireless/ti/wl18xx/conf.h @@ -23,21 +23,20 @@ #define __WL18XX_CONF_H__ #define WL18XX_CONF_MAGIC 0x10e100ca -#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006) +#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0003) #define WL18XX_CONF_MASK 0x0000ffff #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ sizeof(struct wl18xx_priv_conf)) #define NUM_OF_CHANNELS_11_ABG 150 #define NUM_OF_CHANNELS_11_P 7 +#define WL18XX_NUM_OF_SUB_BANDS 9 #define SRF_TABLE_LEN 16 #define PIN_MUXING_SIZE 2 -#define WL18XX_TRACE_LOSS_GAPS_TX 10 -#define WL18XX_TRACE_LOSS_GAPS_RX 18 struct wl18xx_mac_and_phy_params { u8 phy_standalone; - u8 spare0; + u8 rdl; u8 enable_clpc; u8 enable_tx_low_pwr_on_siso_rdl; u8 auto_detect; @@ -70,27 +69,18 @@ struct wl18xx_mac_and_phy_params { u8 pwr_limit_reference_11_abg; u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P]; u8 pwr_limit_reference_11p; - u8 spare1; - u8 per_chan_bo_mode_11_abg[13]; - u8 per_chan_bo_mode_11_p[4]; + u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS]; + u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS]; u8 primary_clock_setting_time; u8 clock_valid_on_wake_up; u8 secondary_clock_setting_time; u8 board_type; /* enable point saturation */ u8 psat; - /* low/medium/high Tx power in dBm for STA-HP BG */ + /* low/medium/high Tx power in dBm */ s8 low_power_val; s8 med_power_val; s8 high_power_val; - s8 per_sub_band_tx_trace_loss[WL18XX_TRACE_LOSS_GAPS_TX]; - s8 per_sub_band_rx_trace_loss[WL18XX_TRACE_LOSS_GAPS_RX]; - u8 tx_rf_margin; - /* low/medium/high Tx power in dBm for other role */ - s8 low_power_val_2nd; - s8 med_power_val_2nd; - s8 high_power_val_2nd; - u8 padding[1]; } __packed; diff --git a/trunk/drivers/net/wireless/ti/wl18xx/event.c b/trunk/drivers/net/wireless/ti/wl18xx/event.c deleted file mode 100644 index c9199d7804c6..000000000000 --- a/trunk/drivers/net/wireless/ti/wl18xx/event.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "event.h" -#include "scan.h" -#include "../wlcore/cmd.h" -#include "../wlcore/debug.h" - -int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, - bool *timeout) -{ - u32 local_event; - - switch (event) { - case WLCORE_EVENT_PEER_REMOVE_COMPLETE: - local_event = PEER_REMOVE_COMPLETE_EVENT_ID; - break; - - case WLCORE_EVENT_DFS_CONFIG_COMPLETE: - local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT; - break; - - default: - /* event not implemented */ - return 0; - } - return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); -} - -int wl18xx_process_mailbox_events(struct wl1271 *wl) -{ - struct wl18xx_event_mailbox *mbox = wl->mbox; - u32 vector; - - vector = le32_to_cpu(mbox->events_vector); - wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, "scan results: %d", - mbox->number_of_scan_results); - - if (wl->scan_wlvif) - wl18xx_scan_completed(wl, wl->scan_wlvif); - } - - if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, - "PERIODIC_SCAN_REPORT_EVENT (results %d)", - mbox->number_of_sched_scan_results); - - wlcore_scan_sched_scan_results(wl); - } - - if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) - wlcore_event_sched_scan_completed(wl, 1); - - if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) - wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric); - - if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) - wlcore_event_ba_rx_constraint(wl, - le16_to_cpu(mbox->rx_ba_role_id_bitmap), - le16_to_cpu(mbox->rx_ba_allowed_bitmap)); - - if (vector & BSS_LOSS_EVENT_ID) - wlcore_event_beacon_loss(wl, - le16_to_cpu(mbox->bss_loss_bitmap)); - - if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) - wlcore_event_channel_switch(wl, - le16_to_cpu(mbox->channel_switch_role_id_bitmap), - true); - - if (vector & DUMMY_PACKET_EVENT_ID) - wlcore_event_dummy_packet(wl); - - /* - * "TX retries exceeded" has a different meaning according to mode. - * In AP mode the offending station is disconnected. - */ - if (vector & MAX_TX_FAILURE_EVENT_ID) - wlcore_event_max_tx_failure(wl, - le32_to_cpu(mbox->tx_retry_exceeded_bitmap)); - - if (vector & INACTIVE_STA_EVENT_ID) - wlcore_event_inactive_sta(wl, - le32_to_cpu(mbox->inactive_sta_bitmap)); - - if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) - wlcore_event_roc_complete(wl); - - return 0; -} diff --git a/trunk/drivers/net/wireless/ti/wl18xx/event.h b/trunk/drivers/net/wireless/ti/wl18xx/event.h deleted file mode 100644 index 398f3d2c0a6c..000000000000 --- a/trunk/drivers/net/wireless/ti/wl18xx/event.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of wl18xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL18XX_EVENT_H__ -#define __WL18XX_EVENT_H__ - -#include "../wlcore/wlcore.h" - -enum { - SCAN_COMPLETE_EVENT_ID = BIT(8), - RADAR_DETECTED_EVENT_ID = BIT(9), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(10), - BSS_LOSS_EVENT_ID = BIT(11), - MAX_TX_FAILURE_EVENT_ID = BIT(12), - DUMMY_PACKET_EVENT_ID = BIT(13), - INACTIVE_STA_EVENT_ID = BIT(14), - PEER_REMOVE_COMPLETE_EVENT_ID = BIT(15), - PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(16), - BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(17), - REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), - DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), - PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), -}; - -struct wl18xx_event_mailbox { - __le32 events_vector; - - u8 number_of_scan_results; - u8 number_of_sched_scan_results; - - __le16 channel_switch_role_id_bitmap; - - s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; - - /* bitmap of removed links */ - __le32 hlid_removed_bitmap; - - /* rx ba constraint */ - __le16 rx_ba_role_id_bitmap; /* 0xfff means any role. */ - __le16 rx_ba_allowed_bitmap; - - /* bitmap of roc completed (by role id) */ - __le16 roc_completed_bitmap; - - /* bitmap of stations (by role id) with bss loss */ - __le16 bss_loss_bitmap; - - /* bitmap of stations (by HLID) which exceeded max tx retries */ - __le32 tx_retry_exceeded_bitmap; - - /* bitmap of inactive stations (by HLID) */ - __le32 inactive_sta_bitmap; -} __packed; - -int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, - bool *timeout); -int wl18xx_process_mailbox_events(struct wl1271 *wl); - -#endif diff --git a/trunk/drivers/net/wireless/ti/wl18xx/main.c b/trunk/drivers/net/wireless/ti/wl18xx/main.c index a10b7a7a215a..8d8c1f8c63b7 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/main.c +++ b/trunk/drivers/net/wireless/ti/wl18xx/main.c @@ -34,13 +34,10 @@ #include "reg.h" #include "conf.h" -#include "cmd.h" #include "acx.h" #include "tx.h" #include "wl18xx.h" #include "io.h" -#include "scan.h" -#include "event.h" #include "debugfs.h" #define WL18XX_RX_CHECKSUM_MASK 0x40 @@ -337,8 +334,6 @@ static struct wlcore_conf wl18xx_conf = { .tmpl_short_retry_limit = 10, .tmpl_long_retry_limit = 10, .tx_watchdog_timeout = 5000, - .slow_link_thold = 3, - .fast_link_thold = 30, }, .conn = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, @@ -396,10 +391,8 @@ static struct wlcore_conf wl18xx_conf = { .scan = { .min_dwell_time_active = 7500, .max_dwell_time_active = 30000, - .min_dwell_time_active_long = 25000, - .max_dwell_time_active_long = 50000, - .dwell_time_passive = 100000, - .dwell_time_dfs = 150000, + .min_dwell_time_passive = 100000, + .max_dwell_time_passive = 100000, .num_probe_reqs = 2, .split_scan_timeout = 50000, }, @@ -496,10 +489,6 @@ static struct wlcore_conf wl18xx_conf = { .increase_time = 1, .window_size = 16, }, - .recovery = { - .bug_on_recovery = 0, - .no_recovery = 0, - }, }; static struct wl18xx_priv_conf wl18xx_default_priv_conf = { @@ -512,6 +501,7 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { .clock_valid_on_wake_up = 0x00, .secondary_clock_setting_time = 0x05, .board_type = BOARD_TYPE_HDK_18XX, + .rdl = 0x01, .auto_detect = 0x00, .dedicated_fem = FEM_NONE, .low_band_component = COMPONENT_3_WAY_SWITCH, @@ -527,44 +517,14 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { .enable_clpc = 0x00, .enable_tx_low_pwr_on_siso_rdl = 0x00, .rx_profile = 0x00, - .pwr_limit_reference_11_abg = 0x64, - .per_chan_pwr_limit_arr_11abg = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - .pwr_limit_reference_11p = 0x64, - .per_chan_bo_mode_11_abg = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00 }, - .per_chan_bo_mode_11_p = { 0x00, 0x00, 0x00, 0x00 }, - .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff }, + .pwr_limit_reference_11_abg = 0xc8, .psat = 0, - .low_power_val = 0x08, - .med_power_val = 0x12, - .high_power_val = 0x18, - .low_power_val_2nd = 0x05, - .med_power_val_2nd = 0x0a, - .high_power_val_2nd = 0x14, + .low_power_val = 0x00, + .med_power_val = 0x0a, + .high_power_val = 0x1e, .external_pa_dc2dc = 0, - .number_of_assembled_ant2_4 = 2, + .number_of_assembled_ant2_4 = 1, .number_of_assembled_ant5 = 1, - .tx_rf_margin = 1, }, }; @@ -635,7 +595,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { }; /* TODO: maybe move to a new header file? */ -#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-2.bin" +#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin" static int wl18xx_identify_chip(struct wl1271 *wl) { @@ -648,18 +608,15 @@ static int wl18xx_identify_chip(struct wl1271 *wl) wl->sr_fw_name = WL18XX_FW_NAME; /* wl18xx uses the same firmware for PLT */ wl->plt_fw_name = WL18XX_FW_NAME; - wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | + wl->quirks |= WLCORE_QUIRK_NO_ELP | + WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN | - WLCORE_QUIRK_TX_PAD_LAST_FRAME | - WLCORE_QUIRK_REGDOMAIN_CONF | - WLCORE_QUIRK_DUAL_PROBE_TMPL; - - wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, - WL18XX_IFTYPE_VER, WL18XX_MAJOR_VER, - WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER, - /* there's no separate multi-role FW */ - 0, 0, 0, 0); + WLCORE_QUIRK_TX_PAD_LAST_FRAME; + + wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER, + WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER, + WL18XX_MINOR_VER); break; case CHIP_ID_185x_PG10: wl1271_warning("chip id 0x%x (185x PG10) is deprecated", @@ -673,11 +630,6 @@ static int wl18xx_identify_chip(struct wl1271 *wl) goto out; } - wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; - wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; - wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC; - wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC; - wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ; out: return ret; } @@ -891,20 +843,6 @@ static int wl18xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl->event_mask = BSS_LOSS_EVENT_ID | - SCAN_COMPLETE_EVENT_ID | - RSSI_SNR_TRIGGER_0_EVENT_ID | - PERIODIC_SCAN_COMPLETE_EVENT_ID | - PERIODIC_SCAN_REPORT_EVENT_ID | - DUMMY_PACKET_EVENT_ID | - PEER_REMOVE_COMPLETE_EVENT_ID | - BA_SESSION_RX_CONSTRAINT_EVENT_ID | - REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | - INACTIVE_STA_EVENT_ID | - MAX_TX_FAILURE_EVENT_ID | - CHANNEL_SWITCH_COMPLETE_EVENT_ID | - DFS_CHANNELS_CONFIG_COMPLETE_EVENT; - ret = wlcore_boot_run_firmware(wl); if (ret < 0) goto out; @@ -1026,7 +964,7 @@ static int wl18xx_hw_init(struct wl1271 *wl) /* (re)init private structures. Relevant on recovery as well. */ priv->last_fw_rls_idx = 0; - priv->extra_spare_key_count = 0; + priv->extra_spare_vif_count = 0; /* set the default amount of spare blocks in the bitmap */ ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE); @@ -1084,12 +1022,7 @@ static bool wl18xx_is_mimo_supported(struct wl1271 *wl) { struct wl18xx_priv *priv = wl->priv; - /* only support MIMO with multiple antennas, and when SISO - * is not forced through config - */ - return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) && - (priv->conf.ht.mode != HT_MODE_WIDE) && - (priv->conf.ht.mode != HT_MODE_SISO20); + return priv->conf.phy.number_of_assembled_ant2_4 >= 2; } /* @@ -1290,8 +1223,8 @@ static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem) { struct wl18xx_priv *priv = wl->priv; - /* If we have keys requiring extra spare, indulge them */ - if (priv->extra_spare_key_count) + /* If we have VIFs requiring extra spare, indulge them */ + if (priv->extra_spare_vif_count) return WL18XX_TX_HW_EXTRA_BLOCK_SPARE; return WL18XX_TX_HW_BLOCK_SPARE; @@ -1303,48 +1236,42 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, struct ieee80211_key_conf *key_conf) { struct wl18xx_priv *priv = wl->priv; - bool change_spare = false, special_enc; + bool change_spare = false; int ret; - wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d", - priv->extra_spare_key_count); - - special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM || - key_conf->cipher == WLAN_CIPHER_SUITE_TKIP; - - ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); - if (ret < 0) - goto out; - /* - * when adding the first or removing the last GEM/TKIP key, + * when adding the first or removing the last GEM/TKIP interface, * we have to adjust the number of spare blocks. */ - if (special_enc) { - if (cmd == SET_KEY) { - /* first key */ - change_spare = (priv->extra_spare_key_count == 0); - priv->extra_spare_key_count++; - } else if (cmd == DISABLE_KEY) { - /* last key */ - change_spare = (priv->extra_spare_key_count == 1); - priv->extra_spare_key_count--; - } - } - - wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d", - priv->extra_spare_key_count); + change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM || + key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) && + ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) || + (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY)); + /* no need to change spare - just regular set_key */ if (!change_spare) + return wlcore_set_key(wl, cmd, vif, sta, key_conf); + + ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); + if (ret < 0) goto out; /* key is now set, change the spare blocks */ - if (priv->extra_spare_key_count) + if (cmd == SET_KEY) { ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_EXTRA_BLOCK_SPARE); - else + if (ret < 0) + goto out; + + priv->extra_spare_vif_count++; + } else { ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE); + if (ret < 0) + goto out; + + priv->extra_spare_vif_count--; + } out: return ret; @@ -1369,92 +1296,6 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, return buf_offset; } -static void wl18xx_sta_rc_update(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, - u32 changed) -{ - bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; - - wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); - - if (!(changed & IEEE80211_RC_BW_CHANGED)) - return; - - mutex_lock(&wl->mutex); - - /* sanity */ - if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) - goto out; - - /* ignore the change before association */ - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - goto out; - - /* - * If we started out as wide, we can change the operation mode. If we - * thought this was a 20mhz AP, we have to reconnect - */ - if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS || - wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS) - wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide); - else - ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif)); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl18xx_set_peer_cap(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, - u32 rate_set, u8 hlid) -{ - return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation, - rate_set, hlid); -} - -static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk) -{ - u8 thold; - struct wl18xx_fw_status_priv *status_priv = - (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv; - u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); - - /* suspended links are never high priority */ - if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) - return false; - - /* the priority thresholds are taken from FW */ - if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && - !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map)) - thold = status_priv->tx_fast_link_prio_threshold; - else - thold = status_priv->tx_slow_link_prio_threshold; - - return lnk->allocated_pkts < thold; -} - -static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk) -{ - u8 thold; - struct wl18xx_fw_status_priv *status_priv = - (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv; - u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); - - if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) - thold = status_priv->tx_suspend_threshold; - else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && - !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map)) - thold = status_priv->tx_fast_stop_threshold; - else - thold = status_priv->tx_slow_stop_threshold; - - return lnk->allocated_pkts < thold; -} - static int wl18xx_setup(struct wl1271 *wl); static struct wlcore_ops wl18xx_ops = { @@ -1464,8 +1305,6 @@ static struct wlcore_ops wl18xx_ops = { .plt_init = wl18xx_plt_init, .trigger_cmd = wl18xx_trigger_cmd, .ack_event = wl18xx_ack_event, - .wait_for_event = wl18xx_wait_for_event, - .process_mailbox_events = wl18xx_process_mailbox_events, .calc_tx_blocks = wl18xx_calc_tx_blocks, .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks, .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len, @@ -1481,26 +1320,16 @@ static struct wlcore_ops wl18xx_ops = { .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask, .get_mac = wl18xx_get_mac, .debugfs_init = wl18xx_debugfs_add_files, - .scan_start = wl18xx_scan_start, - .scan_stop = wl18xx_scan_stop, - .sched_scan_start = wl18xx_sched_scan_start, - .sched_scan_stop = wl18xx_scan_sched_scan_stop, .handle_static_data = wl18xx_handle_static_data, .get_spare_blocks = wl18xx_get_spare_blocks, .set_key = wl18xx_set_key, - .channel_switch = wl18xx_cmd_channel_switch, .pre_pkt_send = wl18xx_pre_pkt_send, - .sta_rc_update = wl18xx_sta_rc_update, - .set_peer_cap = wl18xx_set_peer_cap, - .lnk_high_prio = wl18xx_lnk_high_prio, - .lnk_low_prio = wl18xx_lnk_low_prio, }; /* HT cap appropriate for wide channels in 2Ghz */ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = { .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 | - IEEE80211_HT_CAP_GRN_FLD, + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, @@ -1514,8 +1343,7 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = { /* HT cap appropriate for wide channels in 5Ghz */ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = { .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD, + IEEE80211_HT_CAP_SUP_WIDTH_20_40, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, @@ -1528,8 +1356,7 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = { /* HT cap appropriate for SISO 20 */ static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { - .cap = IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_GRN_FLD, + .cap = IEEE80211_HT_CAP_SGI_20, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, @@ -1542,8 +1369,7 @@ static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { /* HT cap appropriate for MIMO rates in 20mhz channel */ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { - .cap = IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_GRN_FLD, + .cap = IEEE80211_HT_CAP_SGI_20, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, @@ -1561,8 +1387,7 @@ static int wl18xx_setup(struct wl1271 *wl) wl->rtable = wl18xx_rtable; wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS; - wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS; - wl->num_channels = 2; + wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS; wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES; wl->band_rate_to_idx = wl18xx_band_rate_to_idx; wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; @@ -1681,8 +1506,7 @@ static int wl18xx_probe(struct platform_device *pdev) int ret; hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv), - WL18XX_AGGR_BUFFER_SIZE, - sizeof(struct wl18xx_event_mailbox)); + WL18XX_AGGR_BUFFER_SIZE); if (IS_ERR(hw)) { wl1271_error("can't allocate hw"); ret = PTR_ERR(hw); diff --git a/trunk/drivers/net/wireless/ti/wl18xx/scan.c b/trunk/drivers/net/wireless/ti/wl18xx/scan.c deleted file mode 100644 index 09d944505ac0..000000000000 --- a/trunk/drivers/net/wireless/ti/wl18xx/scan.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * This file is part of wl18xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include "scan.h" -#include "../wlcore/debug.h" - -static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd, - struct wlcore_scan_channels *cmd_channels) -{ - memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive)); - memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active)); - cmd->dfs = cmd_channels->dfs; - cmd->passive_active = cmd_channels->passive_active; - - memcpy(cmd->channels_2, cmd_channels->channels_2, - sizeof(cmd->channels_2)); - memcpy(cmd->channels_5, cmd_channels->channels_5, - sizeof(cmd->channels_2)); - /* channels_4 are not supported, so no need to copy them */ -} - -static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_scan_request *req) -{ - struct wl18xx_cmd_scan_params *cmd; - struct wlcore_scan_channels *cmd_channels = NULL; - int ret; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->role_id = wlvif->role_id; - - if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { - ret = -EINVAL; - goto out; - } - - cmd->scan_type = SCAN_TYPE_SEARCH; - cmd->rssi_threshold = -127; - cmd->snr_threshold = 0; - - cmd->bss_type = SCAN_BSS_TYPE_ANY; - - cmd->ssid_from_list = 0; - cmd->filter = 0; - cmd->add_broadcast = 0; - - cmd->urgency = 0; - cmd->protect = 0; - - cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs; - cmd->terminate_after = 0; - - /* configure channels */ - WARN_ON(req->n_ssids > 1); - - cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); - if (!cmd_channels) { - ret = -ENOMEM; - goto out; - } - - wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, - req->n_channels, req->n_ssids, - SCAN_TYPE_SEARCH); - wl18xx_adjust_channels(cmd, cmd_channels); - - /* - * all the cycles params (except total cycles) should - * remain 0 for normal scan - */ - cmd->total_cycles = 1; - - if (req->no_cck) - cmd->rate = WL18XX_SCAN_RATE_6; - - cmd->tag = WL1271_SCAN_DEFAULT_TAG; - - if (req->n_ssids) { - cmd->ssid_len = req->ssids[0].ssid_len; - memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len); - } - - /* TODO: per-band ies? */ - if (cmd->active[0]) { - u8 band = IEEE80211_BAND_2GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - cmd->role_id, band, - req->ssids ? req->ssids[0].ssid : NULL, - req->ssids ? req->ssids[0].ssid_len : 0, - req->ie, - req->ie_len, - false); - if (ret < 0) { - wl1271_error("2.4GHz PROBE request template failed"); - goto out; - } - } - - if (cmd->active[1] || cmd->dfs) { - u8 band = IEEE80211_BAND_5GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - cmd->role_id, band, - req->ssids ? req->ssids[0].ssid : NULL, - req->ssids ? req->ssids[0].ssid_len : 0, - req->ie, - req->ie_len, - false); - if (ret < 0) { - wl1271_error("5GHz PROBE request template failed"); - goto out; - } - } - - wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("SCAN failed"); - goto out; - } - -out: - kfree(cmd_channels); - kfree(cmd); - return ret; -} - -void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - wl->scan.failed = false; - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); -} - -static -int wl18xx_scan_sched_scan_config(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) -{ - struct wl18xx_cmd_scan_params *cmd; - struct wlcore_scan_channels *cmd_channels = NULL; - struct conf_sched_scan_settings *c = &wl->conf.sched_scan; - int ret; - int filter_type; - - wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); - - filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); - if (filter_type < 0) - return filter_type; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->role_id = wlvif->role_id; - - if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { - ret = -EINVAL; - goto out; - } - - cmd->scan_type = SCAN_TYPE_PERIODIC; - cmd->rssi_threshold = c->rssi_threshold; - cmd->snr_threshold = c->snr_threshold; - - /* don't filter on BSS type */ - cmd->bss_type = SCAN_BSS_TYPE_ANY; - - cmd->ssid_from_list = 1; - if (filter_type == SCAN_SSID_FILTER_LIST) - cmd->filter = 1; - cmd->add_broadcast = 0; - - cmd->urgency = 0; - cmd->protect = 0; - - cmd->n_probe_reqs = c->num_probe_reqs; - /* don't stop scanning automatically when something is found */ - cmd->terminate_after = 0; - - cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); - if (!cmd_channels) { - ret = -ENOMEM; - goto out; - } - - /* configure channels */ - wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, - req->n_channels, req->n_ssids, - SCAN_TYPE_PERIODIC); - wl18xx_adjust_channels(cmd, cmd_channels); - - cmd->short_cycles_sec = 0; - cmd->long_cycles_sec = cpu_to_le16(req->interval); - cmd->short_cycles_count = 0; - - cmd->total_cycles = 0; - - cmd->tag = WL1271_SCAN_DEFAULT_TAG; - - /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */ - cmd->report_threshold = 1; - cmd->terminate_on_report = 0; - - if (cmd->active[0]) { - u8 band = IEEE80211_BAND_2GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - cmd->role_id, band, - req->ssids ? req->ssids[0].ssid : NULL, - req->ssids ? req->ssids[0].ssid_len : 0, - ies->ie[band], - ies->len[band], - true); - if (ret < 0) { - wl1271_error("2.4GHz PROBE request template failed"); - goto out; - } - } - - if (cmd->active[1] || cmd->dfs) { - u8 band = IEEE80211_BAND_5GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - cmd->role_id, band, - req->ssids ? req->ssids[0].ssid : NULL, - req->ssids ? req->ssids[0].ssid_len : 0, - ies->ie[band], - ies->len[band], - true); - if (ret < 0) { - wl1271_error("5GHz PROBE request template failed"); - goto out; - } - } - - wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("SCAN failed"); - goto out; - } - -out: - kfree(cmd_channels); - kfree(cmd); - return ret; -} - -int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) -{ - return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); -} - -static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 scan_type) -{ - struct wl18xx_cmd_scan_stop *stop; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); - - stop = kzalloc(sizeof(*stop), GFP_KERNEL); - if (!stop) { - wl1271_error("failed to alloc memory to send sched scan stop"); - return -ENOMEM; - } - - stop->role_id = wlvif->role_id; - stop->scan_type = scan_type; - - ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0); - if (ret < 0) { - wl1271_error("failed to send sched scan stop command"); - goto out_free; - } - -out_free: - kfree(stop); - return ret; -} - -void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC); -} -int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_scan_request *req) -{ - return wl18xx_scan_send(wl, wlvif, req); -} - -int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH); -} diff --git a/trunk/drivers/net/wireless/ti/wl18xx/scan.h b/trunk/drivers/net/wireless/ti/wl18xx/scan.h deleted file mode 100644 index eadee42689d1..000000000000 --- a/trunk/drivers/net/wireless/ti/wl18xx/scan.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of wl18xx - * - * Copyright (C) 2012 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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 St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL18XX_SCAN_H__ -#define __WL18XX_SCAN_H__ - -#include "../wlcore/wlcore.h" -#include "../wlcore/cmd.h" -#include "../wlcore/scan.h" - -struct tracking_ch_params { - struct conn_scan_ch_params channel; - - __le32 bssid_lsb; - __le16 bssid_msb; - - u8 padding[2]; -} __packed; - -/* probe request rate */ -enum -{ - WL18XX_SCAN_RATE_1 = 0, - WL18XX_SCAN_RATE_5_5 = 1, - WL18XX_SCAN_RATE_6 = 2, -}; - -#define WL18XX_MAX_CHANNELS_5GHZ 32 - -struct wl18xx_cmd_scan_params { - struct wl1271_cmd_header header; - - u8 role_id; - u8 scan_type; - - s8 rssi_threshold; /* for filtering (in dBm) */ - s8 snr_threshold; /* for filtering (in dB) */ - - u8 bss_type; /* for filtering */ - u8 ssid_from_list; /* use ssid from configured ssid list */ - u8 filter; /* forward only results with matching ssids */ - - /* - * add broadcast ssid in addition to the configured ssids. - * the driver should add dummy entry for it (?). - */ - u8 add_broadcast; - - u8 urgency; - u8 protect; /* ??? */ - u8 n_probe_reqs; /* Number of probes requests per channel */ - u8 terminate_after; /* early terminate scan operation */ - - u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */ - u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */ - u8 dfs; /* number of dfs channels in 5ghz */ - u8 passive_active; /* number of passive before active channels 2.4ghz */ - - __le16 short_cycles_sec; - __le16 long_cycles_sec; - u8 short_cycles_count; - u8 total_cycles; /* 0 - infinite */ - u8 padding[2]; - - union { - struct { - struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; - struct conn_scan_ch_params channels_5[WL18XX_MAX_CHANNELS_5GHZ]; - struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; - }; - struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS]; - } ; - - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ - u8 tag; - u8 rate; - - /* send SCAN_REPORT_EVENT in periodic scans after each cycle - * if number of results >= report_threshold. Must be 0 for - * non periodic scans - */ - u8 report_threshold; - - /* Should periodic scan stop after a report event was created. - * Must be 0 for non periodic scans. - */ - u8 terminate_on_report; - - u8 padding1[3]; -} __packed; - -struct wl18xx_cmd_scan_stop { - struct wl1271_cmd_header header; - - u8 role_id; - u8 scan_type; - u8 padding[2]; -} __packed; - -int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_scan_request *req); -int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); -void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); -void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); -#endif diff --git a/trunk/drivers/net/wireless/ti/wl18xx/tx.c b/trunk/drivers/net/wireless/ti/wl18xx/tx.c index 57c694396647..5b1fb10d9fd7 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/tx.c +++ b/trunk/drivers/net/wireless/ti/wl18xx/tx.c @@ -28,49 +28,6 @@ #include "wl18xx.h" #include "tx.h" -static -void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, - struct ieee80211_tx_rate *rate) -{ - u8 fw_rate = wl->fw_status_2->counters.tx_last_rate; - - if (fw_rate > CONF_HW_RATE_INDEX_MAX) { - wl1271_error("last Tx rate invalid: %d", fw_rate); - rate->idx = 0; - rate->flags = 0; - return; - } - - if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) { - rate->idx = fw_rate; - rate->flags = 0; - } else { - rate->flags = IEEE80211_TX_RC_MCS; - rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0; - - /* SGI modifier is counted as a separate rate */ - if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI) - (rate->idx)--; - if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) - (rate->idx)--; - - /* this also covers the 40Mhz SGI case (= MCS15) */ - if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI || - fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI) - rate->flags |= IEEE80211_TX_RC_SHORT_GI; - - if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) { - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || - wlvif->channel_type == NL80211_CHAN_HT40PLUS) { - /* adjustment needed for range 0-7 */ - rate->idx -= 8; - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - } - } - } -} - static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) { struct ieee80211_tx_info *info; @@ -87,6 +44,7 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) /* a zero bit indicates Tx success */ tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX)); + skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); @@ -98,13 +56,11 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) /* update the TX status info */ if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_ACK; - /* - * first pass info->control.vif while it's valid, and then fill out - * the info->status structures - */ - wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]); - info->status.rates[0].count = 1; /* no data about retries */ + /* no real data about Tx completion */ + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + info->status.rates[0].flags = 0; info->status.ack_signal = -1; if (!tx_success) diff --git a/trunk/drivers/net/wireless/ti/wl18xx/wl18xx.h b/trunk/drivers/net/wireless/ti/wl18xx/wl18xx.h index b6739e79efcf..96a1e438d677 100644 --- a/trunk/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/trunk/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -26,10 +26,10 @@ /* minimum FW required for driver */ #define WL18XX_CHIP_VER 8 -#define WL18XX_IFTYPE_VER 5 -#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE -#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE -#define WL18XX_MINOR_VER 28 +#define WL18XX_IFTYPE_VER 2 +#define WL18XX_MAJOR_VER 0 +#define WL18XX_SUBTYPE_VER 0 +#define WL18XX_MINOR_VER 100 #define WL18XX_CMD_MAX_SIZE 740 @@ -49,8 +49,8 @@ struct wl18xx_priv { /* Index of last released Tx desc in FW */ u8 last_fw_rls_idx; - /* number of keys requiring extra spare mem-blocks */ - int extra_spare_key_count; + /* number of VIFs requiring extra spare mem-blocks */ + int extra_spare_vif_count; }; #define WL18XX_FW_MAX_TX_STATUS_DESC 33 @@ -68,43 +68,7 @@ struct wl18xx_fw_status_priv { */ u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC]; - /* A bitmap representing the currently suspended links. The suspend - * is short lived, for multi-channel Tx requirements. - */ - __le32 link_suspend_bitmap; - - /* packet threshold for an "almost empty" AC, - * for Tx schedulng purposes - */ - u8 tx_ac_threshold; - - /* number of packets to queue up for a link in PS */ - u8 tx_ps_threshold; - - /* number of packet to queue up for a suspended link */ - u8 tx_suspend_threshold; - - /* Should have less than this number of packets in queue of a slow - * link to qualify as high priority link - */ - u8 tx_slow_link_prio_threshold; - - /* Should have less than this number of packets in queue of a fast - * link to qualify as high priority link - */ - u8 tx_fast_link_prio_threshold; - - /* Should have less than this number of packets in queue of a slow - * link before we stop queuing up packets for it. - */ - u8 tx_slow_stop_threshold; - - /* Should have less than this number of packets in queue of a fast - * link before we stop queuing up packets for it. - */ - u8 tx_fast_stop_threshold; - - u8 padding[3]; + u8 padding[2]; }; #define WL18XX_PHY_VERSION_MAX_LEN 20 diff --git a/trunk/drivers/net/wireless/ti/wlcore/Kconfig b/trunk/drivers/net/wireless/ti/wlcore/Kconfig index 2b832825c3d4..d7b907e67170 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/Kconfig +++ b/trunk/drivers/net/wireless/ti/wlcore/Kconfig @@ -33,3 +33,8 @@ config WLCORE_SDIO If you choose to build a module, it'll be called wlcore_sdio. Say N if unsure. + +config WL12XX_PLATFORM_DATA + bool + depends on WLCORE_SDIO != n || WL1251_SDIO != n + default y diff --git a/trunk/drivers/net/wireless/ti/wlcore/Makefile b/trunk/drivers/net/wireless/ti/wlcore/Makefile index b21398f6c3ec..d9fba9e32130 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/Makefile +++ b/trunk/drivers/net/wireless/ti/wlcore/Makefile @@ -9,4 +9,7 @@ obj-$(CONFIG_WLCORE) += wlcore.o obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o +# small builtin driver bit +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o + ccflags-y += -D__CHECK_ENDIAN__ diff --git a/trunk/drivers/net/wireless/ti/wlcore/acx.c b/trunk/drivers/net/wireless/ti/wlcore/acx.c index c79654323396..ce108a736bd0 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/acx.c +++ b/trunk/drivers/net/wireless/ti/wlcore/acx.c @@ -1340,8 +1340,6 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, kfree(acx); return ret; } -EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities); - int wl1271_acx_set_ht_information(struct wl1271 *wl, struct wl12xx_vif *wlvif, @@ -1435,22 +1433,13 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, acx->win_size = wl->conf.ht.rx_ba_win_size; acx->ssn = ssn; - ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx, - sizeof(*acx), - BIT(CMD_STATUS_NO_RX_BA_SESSION)); + ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, + sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ba receiver session failed: %d", ret); goto out; } - /* sometimes we can't start the session */ - if (ret == CMD_STATUS_NO_RX_BA_SESSION) { - wl1271_warning("no fw rx ba on tid %d", tid_index); - ret = -EBUSY; - goto out; - } - - ret = 0; out: kfree(acx); return ret; diff --git a/trunk/drivers/net/wireless/ti/wlcore/acx.h b/trunk/drivers/net/wireless/ti/wlcore/acx.h index 126536c6a393..d03215d6b3bd 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/acx.h +++ b/trunk/drivers/net/wireless/ti/wlcore/acx.h @@ -1025,6 +1025,7 @@ enum { ACX_CONFIG_HANGOVER = 0x0042, ACX_FEATURE_CFG = 0x0043, ACX_PROTECTION_CFG = 0x0044, + ACX_CHECKSUM_CONFIG = 0x0045, }; diff --git a/trunk/drivers/net/wireless/ti/wlcore/boot.c b/trunk/drivers/net/wireless/ti/wlcore/boot.c index 77752b03f189..375ea574eafb 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/boot.c +++ b/trunk/drivers/net/wireless/ti/wlcore/boot.c @@ -84,57 +84,47 @@ static int wlcore_boot_parse_fw_ver(struct wl1271 *wl, static int wlcore_validate_fw_ver(struct wl1271 *wl) { unsigned int *fw_ver = wl->chip.fw_ver; - unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_MULTI) ? - wl->min_mr_fw_ver : wl->min_sr_fw_ver; - char min_fw_str[32] = ""; - int i; + unsigned int *min_ver = wl->min_fw_ver; /* the chip must be exactly equal */ - if ((min_ver[FW_VER_CHIP] != WLCORE_FW_VER_IGNORE) && - (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP])) + if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]) goto fail; - /* the firmware type must be equal */ - if ((min_ver[FW_VER_IF_TYPE] != WLCORE_FW_VER_IGNORE) && - (min_ver[FW_VER_IF_TYPE] != fw_ver[FW_VER_IF_TYPE])) + /* always check the next digit if all previous ones are equal */ + + if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE]) + goto out; + else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE]) goto fail; - /* the project number must be equal */ - if ((min_ver[FW_VER_SUBTYPE] != WLCORE_FW_VER_IGNORE) && - (min_ver[FW_VER_SUBTYPE] != fw_ver[FW_VER_SUBTYPE])) + if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR]) + goto out; + else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]) goto fail; - /* the API version must be greater or equal */ - if ((min_ver[FW_VER_MAJOR] != WLCORE_FW_VER_IGNORE) && - (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR])) + if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE]) + goto out; + else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE]) goto fail; - /* if the API version is equal... */ - if (((min_ver[FW_VER_MAJOR] == WLCORE_FW_VER_IGNORE) || - (min_ver[FW_VER_MAJOR] == fw_ver[FW_VER_MAJOR])) && - /* ...the minor must be greater or equal */ - ((min_ver[FW_VER_MINOR] != WLCORE_FW_VER_IGNORE) && - (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR]))) + if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR]) + goto out; + else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR]) goto fail; +out: return 0; fail: - for (i = 0; i < NUM_FW_VER; i++) - if (min_ver[i] == WLCORE_FW_VER_IGNORE) - snprintf(min_fw_str, sizeof(min_fw_str), - "%s*.", min_fw_str); - else - snprintf(min_fw_str, sizeof(min_fw_str), - "%s%u.", min_fw_str, min_ver[i]); - - wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n" - "Please use at least FW %s\n" - "You can get the latest firmwares at:\n" - "git://github.com/TI-OpenLink/firmwares.git", + wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n" + "Please use at least FW %u.%u.%u.%u.%u.\n" + "You can get more information at:\n" + "http://wireless.kernel.org/en/users/Drivers/wl12xx", fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE], fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], - fw_ver[FW_VER_MINOR], min_fw_str); + fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP], + min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR], + min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]); return -EINVAL; } @@ -501,7 +491,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) if (ret < 0) return ret; - wl->mbox_ptr[1] = wl->mbox_ptr[0] + wl->mbox_size; + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", wl->mbox_ptr[0], wl->mbox_ptr[1]); @@ -518,6 +508,23 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) */ /* unmask required mbox events */ + wl->event_mask = BSS_LOSE_EVENT_ID | + REGAINED_BSS_EVENT_ID | + SCAN_COMPLETE_EVENT_ID | + ROLE_STOP_COMPLETE_EVENT_ID | + RSSI_SNR_TRIGGER_0_EVENT_ID | + PSPOLL_DELIVERY_FAILURE_EVENT_ID | + SOFT_GEMINI_SENSE_EVENT_ID | + PERIODIC_SCAN_REPORT_EVENT_ID | + PERIODIC_SCAN_COMPLETE_EVENT_ID | + DUMMY_PACKET_EVENT_ID | + PEER_REMOVE_COMPLETE_EVENT_ID | + BA_SESSION_RX_CONSTRAINT_EVENT_ID | + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID | + MAX_TX_RETRY_EVENT_ID | + CHANNEL_SWITCH_COMPLETE_EVENT_ID; + ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); diff --git a/trunk/drivers/net/wireless/ti/wlcore/cmd.c b/trunk/drivers/net/wireless/ti/wlcore/cmd.c index 6331f9e1cb39..27f83f72a93b 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/cmd.c +++ b/trunk/drivers/net/wireless/ti/wlcore/cmd.c @@ -48,15 +48,14 @@ * @id: command id * @buf: buffer containing the command, must work with dma * @len: length of the buffer - * return the cmd status code on success. */ -static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, - size_t len, size_t res_len) +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; - int ret; + int ret = 0; u16 status; u16 poll_count = 0; @@ -72,7 +71,7 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); if (ret < 0) - return ret; + goto fail; /* * TODO: we just need this because one bit is in a different @@ -80,18 +79,19 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, */ ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); if (ret < 0) - return ret; + goto fail; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) - return ret; + goto fail; while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto fail; } poll_count++; @@ -102,7 +102,7 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) - return ret; + goto fail; } /* read back the status code of the command */ @@ -111,66 +111,33 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); if (ret < 0) - return ret; + goto fail; status = le16_to_cpu(cmd->status); + if (status != CMD_STATUS_SUCCESS) { + wl1271_error("command execute failure %d", status); + ret = -EIO; + goto fail; + } ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); - if (ret < 0) - return ret; - - return status; -} - -/* - * send command to fw and return cmd status on success - * valid_rets contains a bitmap of allowed error codes - */ -int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len, unsigned long valid_rets) -{ - int ret = __wlcore_cmd_send(wl, id, buf, len, res_len); - if (ret < 0) goto fail; - /* success is always a valid status */ - valid_rets |= BIT(CMD_STATUS_SUCCESS); + return 0; - if (ret >= MAX_COMMAND_STATUS || - !test_bit(ret, &valid_rets)) { - wl1271_error("command execute failure %d", ret); - ret = -EIO; - goto fail; - } - return ret; fail: wl12xx_queue_recovery_work(wl); return ret; } -EXPORT_SYMBOL_GPL(wl1271_cmd_send); - -/* - * wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS - * return 0 on success. - */ -int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len) -{ - int ret = wlcore_cmd_send_failsafe(wl, id, buf, len, res_len, 0); - - if (ret < 0) - return ret; - return 0; -} /* * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) */ -int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, - u32 mask, bool *timeout) +static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, + u32 mask, bool *timeout) { u32 *events_vector; u32 event; @@ -220,7 +187,20 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, kfree(events_vector); return ret; } -EXPORT_SYMBOL_GPL(wlcore_cmd_wait_for_event_or_timeout); + +static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) +{ + int ret; + bool timeout = false; + + ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout); + if (ret != 0 || timeout) { + wl12xx_queue_recovery_work(wl); + return ret; + } + + return 0; +} int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, u8 *role_id) @@ -298,16 +278,6 @@ int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) return ret; } -static int wlcore_get_new_session_id(struct wl1271 *wl, u8 hlid) -{ - if (wl->session_ids[hlid] >= SESSION_COUNTER_MAX) - wl->session_ids[hlid] = 0; - - wl->session_ids[hlid]++; - - return wl->session_ids[hlid]; -} - int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) { unsigned long flags; @@ -315,21 +285,12 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) if (link >= WL12XX_MAX_LINKS) return -EBUSY; - wl->session_ids[link] = wlcore_get_new_session_id(wl, link); - /* these bits are used by op_tx */ spin_lock_irqsave(&wl->wl_lock, flags); __set_bit(link, wl->links_map); __set_bit(link, wlvif->links_map); spin_unlock_irqrestore(&wl->wl_lock, flags); - - /* take the last "freed packets" value from the current FW status */ - wl->links[link].prev_freed_pkts = - wl->fw_status_2->counters.tx_lnk_free_pkts[link]; - wl->links[link].wlvif = wlvif; *hlid = link; - - wl->active_link_count++; return 0; } @@ -346,21 +307,24 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) __clear_bit(*hlid, wlvif->links_map); spin_unlock_irqrestore(&wl->wl_lock, flags); - wl->links[*hlid].allocated_pkts = 0; - wl->links[*hlid].prev_freed_pkts = 0; - wl->links[*hlid].ba_bitmap = 0; - memset(wl->links[*hlid].addr, 0, ETH_ALEN); - /* * At this point op_tx() will not add more packets to the queues. We * can purge them. */ wl1271_tx_reset_link_queues(wl, *hlid); - wl->links[*hlid].wlvif = NULL; *hlid = WL12XX_INVALID_LINK_ID; - wl->active_link_count--; - WARN_ON_ONCE(wl->active_link_count < 0); +} + +static int wl12xx_get_new_session_id(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + if (wlvif->session_counter >= SESSION_COUNTER_MAX) + wlvif->session_counter = 0; + + wlvif->session_counter++; + + return wlvif->session_counter; } static u8 wlcore_get_native_channel_type(u8 nl_channel_type) @@ -381,9 +345,7 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type) } static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - enum ieee80211_band band, - int channel) + struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_start *cmd; int ret; @@ -397,9 +359,9 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); cmd->role_id = wlvif->dev_role_id; - if (band == IEEE80211_BAND_5GHZ) + if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WLCORE_BAND_5GHZ; - cmd->channel = channel; + cmd->channel = wlvif->channel; if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); @@ -407,7 +369,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, goto out_free; } cmd->device.hlid = wlvif->dev_hlid; - cmd->device.session = wl->session_ids[wlvif->dev_hlid]; + cmd->device.session = wl12xx_get_new_session_id(wl, wlvif); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", cmd->role_id, cmd->device.hlid, cmd->device.session); @@ -458,6 +420,12 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, goto out_free; } + ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); + if (ret < 0) { + wl1271_error("cmd role stop dev event completion error"); + goto out_free; + } + wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); out_free: @@ -471,7 +439,6 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_cmd_role_start *cmd; - u32 supported_rates; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -492,14 +459,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) cmd->sta.ssid_len = wlvif->ssid_len; memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); - - supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | - wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); - if (wlvif->p2p) - supported_rates &= ~CONF_TX_CCK_RATES; - - cmd->sta.local_rates = cpu_to_le32(supported_rates); - + cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { @@ -508,14 +468,8 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) goto out_free; } cmd->sta.hlid = wlvif->sta.hlid; - cmd->sta.session = wl->session_ids[wlvif->sta.hlid]; - /* - * We don't have the correct remote rates in this stage. The - * rates will be reconfigured later, after association, if the - * firmware supports ACX_PEER_CAP. Otherwise, there's nothing - * we can do, so use all supported_rates here. - */ - cmd->sta.remote_rates = cpu_to_le32(supported_rates); + cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); + cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " "basic_rate_set: 0x%x, remote_rates: 0x%x", @@ -528,7 +482,6 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) goto err_hlid; } - wlvif->sta.role_chan_type = wlvif->channel_type; goto out_free; err_hlid: @@ -547,6 +500,7 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_stop *cmd; int ret; + bool timeout = false; if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) return -EINVAL; @@ -569,6 +523,17 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) goto out_free; } + /* + * Sometimes the firmware doesn't send this event, so we just + * time out without failing. Queue recovery for other + * failures. + */ + ret = wl1271_cmd_wait_for_event_or_timeout(wl, + ROLE_STOP_COMPLETE_EVENT_ID, + &timeout); + if (ret) + wl12xx_queue_recovery_work(wl); + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: @@ -614,15 +579,12 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) cmd->ap.bss_index = WL1271_AP_BSS_INDEX; cmd->ap.global_hlid = wlvif->ap.global_hlid; cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; - cmd->ap.global_session_id = wl->session_ids[wlvif->ap.global_hlid]; - cmd->ap.bcast_session_id = wl->session_ids[wlvif->ap.bcast_hlid]; cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; /* FIXME: Change when adding DFS */ cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ - cmd->ap.wmm = wlvif->wmm_enabled; cmd->channel = wlvif->channel; cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); @@ -637,10 +599,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); } - supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | + supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES | wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); - if (wlvif->p2p) - supported_rates &= ~CONF_TX_CCK_RATES; wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x", supported_rates); @@ -839,11 +799,8 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) * @id: acx id * @buf: buffer containing acx, including all headers, must work with dma * @len: length of buf - * @valid_rets: bitmap of valid cmd status codes (i.e. return values). - * return the cmd status on success. */ -int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf, - size_t len, unsigned long valid_rets) +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) { struct acx_header *acx = buf; int ret; @@ -855,26 +812,12 @@ int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf, /* payload length, does not include any headers */ acx->len = cpu_to_le16(len - sizeof(*acx)); - ret = wlcore_cmd_send_failsafe(wl, CMD_CONFIGURE, acx, len, 0, - valid_rets); + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); if (ret < 0) { wl1271_warning("CONFIGURE command NOK"); return ret; } - return ret; -} - -/* - * wrapper for wlcore_cmd_configure that accepts only success status. - * return 0 on success - */ -int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) -{ - int ret = wlcore_cmd_configure_failsafe(wl, id, buf, len, 0); - - if (ret < 0) - return ret; return 0; } EXPORT_SYMBOL_GPL(wl1271_cmd_configure); @@ -1091,8 +1034,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct sk_buff *skb; int ret; u32 rate; - u16 template_id_2_4 = wl->scan_templ_id_2_4; - u16 template_id_5 = wl->scan_templ_id_5; + u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; + u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie_len); @@ -1105,10 +1048,10 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); - if (sched_scan && + if (!sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { - template_id_2_4 = wl->sched_scan_templ_id_2_4; - template_id_5 = wl->sched_scan_templ_id_5; + template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4; + template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5; } rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); @@ -1125,7 +1068,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, dev_kfree_skb(skb); return ret; } -EXPORT_SYMBOL_GPL(wl12xx_cmd_build_probe_req); struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, @@ -1437,8 +1379,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, return ret; } -int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 hlid) +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) { struct wl12xx_cmd_set_peer_state *cmd; int ret = 0; @@ -1454,10 +1395,6 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, cmd->hlid = hlid; cmd->state = WL1271_CMD_STA_STATE_CONNECTED; - /* wmm param is valid only for station role */ - if (wlvif->bss_type == BSS_TYPE_STA_BSS) - cmd->wmm = wlvif->wmm_enabled; - ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to send set peer state command"); @@ -1492,7 +1429,6 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, cmd->hlid = hlid; cmd->sp_len = sta->max_sp; cmd->wmm = sta->wme ? 1 : 0; - cmd->session_id = wl->session_ids[hlid]; for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) if (sta->wme && (sta->uapsd_queues & BIT(i))) @@ -1554,10 +1490,9 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) goto out_free; } - ret = wl->ops->wait_for_event(wl, - WLCORE_EVENT_PEER_REMOVE_COMPLETE, - &timeout); - + ret = wl1271_cmd_wait_for_event_or_timeout(wl, + PEER_REMOVE_COMPLETE_EVENT_ID, + &timeout); /* * We are ok with a timeout here. The event is sometimes not sent * due to a firmware bug. In case of another error (like SDIO timeout) @@ -1573,131 +1508,6 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) return ret; } -static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch) -{ - int idx = -1; - - switch (band) { - case IEEE80211_BAND_5GHZ: - if (ch >= 8 && ch <= 16) - idx = ((ch-8)/4 + 18); - else if (ch >= 34 && ch <= 64) - idx = ((ch-34)/2 + 3 + 18); - else if (ch >= 100 && ch <= 140) - idx = ((ch-100)/4 + 15 + 18); - else if (ch >= 149 && ch <= 165) - idx = ((ch-149)/4 + 26 + 18); - else - idx = -1; - break; - case IEEE80211_BAND_2GHZ: - if (ch >= 1 && ch <= 14) - idx = ch - 1; - else - idx = -1; - break; - default: - wl1271_error("get reg conf ch idx - unknown band: %d", - (int)band); - } - - return idx; -} - -void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, - enum ieee80211_band band) -{ - int ch_bit_idx = 0; - - if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF)) - return; - - ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel); - - if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) - set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending); -} - -int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) -{ - struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL; - int ret = 0, i, b, ch_bit_idx; - struct ieee80211_channel *channel; - u32 tmp_ch_bitmap[2]; - u16 ch; - struct wiphy *wiphy = wl->hw->wiphy; - struct ieee80211_supported_band *band; - bool timeout = false; - - if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF)) - return 0; - - wl1271_debug(DEBUG_CMD, "cmd reg domain config"); - - memset(tmp_ch_bitmap, 0, sizeof(tmp_ch_bitmap)); - - for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) { - band = wiphy->bands[b]; - for (i = 0; i < band->n_channels; i++) { - channel = &band->channels[i]; - ch = channel->hw_value; - - if (channel->flags & (IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN)) - continue; - - ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); - if (ch_bit_idx < 0) - continue; - - set_bit(ch_bit_idx, (long *)tmp_ch_bitmap); - } - } - - tmp_ch_bitmap[0] |= wl->reg_ch_conf_pending[0]; - tmp_ch_bitmap[1] |= wl->reg_ch_conf_pending[1]; - - if (!memcmp(tmp_ch_bitmap, wl->reg_ch_conf_last, sizeof(tmp_ch_bitmap))) - goto out; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]); - cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]); - - wl1271_debug(DEBUG_CMD, - "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x", - cmd->ch_bit_map1, cmd->ch_bit_map2); - - ret = wl1271_cmd_send(wl, CMD_DFS_CHANNEL_CONFIG, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send reg domain dfs config"); - goto out; - } - - ret = wl->ops->wait_for_event(wl, - WLCORE_EVENT_DFS_CONFIG_COMPLETE, - &timeout); - if (ret < 0 || timeout) { - wl1271_error("reg domain conf %serror", - timeout ? "completion " : ""); - ret = timeout ? -ETIMEDOUT : ret; - goto out; - } - - memcpy(wl->reg_ch_conf_last, tmp_ch_bitmap, sizeof(tmp_ch_bitmap)); - memset(wl->reg_ch_conf_pending, 0, sizeof(wl->reg_ch_conf_pending)); - -out: - kfree(cmd); - return ret; -} - int wl12xx_cmd_config_fwlog(struct wl1271 *wl) { struct wl12xx_cmd_config_fwlog *cmd; @@ -1783,12 +1593,12 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) } static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 role_id, enum ieee80211_band band, u8 channel) + u8 role_id) { struct wl12xx_cmd_roc *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", channel, role_id); + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) return -EINVAL; @@ -1800,8 +1610,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, } cmd->role_id = role_id; - cmd->channel = channel; - switch (band) { + cmd->channel = wlvif->channel; + switch (wlvif->band) { case IEEE80211_BAND_2GHZ: cmd->band = WLCORE_BAND_2_4GHZ; break; @@ -1856,18 +1666,30 @@ static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) return ret; } -int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, - enum ieee80211_band band, u8 channel) +int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) { int ret = 0; + bool is_first_roc; if (WARN_ON(test_bit(role_id, wl->roc_map))) return 0; - ret = wl12xx_cmd_roc(wl, wlvif, role_id, band, channel); + is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >= + WL12XX_MAX_ROLES); + + ret = wl12xx_cmd_roc(wl, wlvif, role_id); if (ret < 0) goto out; + if (is_first_roc) { + ret = wl1271_cmd_wait_for_event(wl, + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); + if (ret < 0) { + wl1271_error("cmd roc event completion error"); + goto out; + } + } + __set_bit(role_id, wl->roc_map); out: return ret; @@ -1897,12 +1719,14 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id) return ret; } -int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif) +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_channel_switch *ch_switch) { - struct wl12xx_cmd_stop_channel_switch *cmd; + struct wl12xx_cmd_channel_switch *cmd; int ret; - wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); + wl1271_debug(DEBUG_ACX, "cmd channel switch"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1911,6 +1735,38 @@ int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif) } cmd->role_id = wlvif->role_id; + cmd->channel = ch_switch->channel->hw_value; + cmd->switch_time = ch_switch->count; + cmd->stop_tx = ch_switch->block_tx; + + /* FIXME: control from mac80211 in the future */ + cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ + + ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send channel switch command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) +{ + struct wl12xx_cmd_stop_channel_switch *cmd; + int ret; + + wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); if (ret < 0) { @@ -1926,8 +1782,7 @@ int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif) } /* start dev role and roc on its channel */ -int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum ieee80211_band band, int channel) +int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; @@ -1942,11 +1797,11 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ret < 0) goto out; - ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel); + ret = wl12xx_cmd_role_start_dev(wl, wlvif); if (ret < 0) goto out_disable; - ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id, band, channel); + ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); if (ret < 0) goto out_stop; diff --git a/trunk/drivers/net/wireless/ti/wlcore/cmd.h b/trunk/drivers/net/wireless/ti/wlcore/cmd.h index fd34123047cd..2409f3d71f63 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/cmd.h +++ b/trunk/drivers/net/wireless/ti/wlcore/cmd.h @@ -31,8 +31,6 @@ struct acx_header; int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len); -int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len, unsigned long valid_rets); int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, u8 *role_id); int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); @@ -41,14 +39,11 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum ieee80211_band band, int channel); +int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf, - size_t len, unsigned long valid_rets); int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 ps_mode, u16 auto_ps_timeout); @@ -80,30 +75,22 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); -int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 hlid); -int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, - enum ieee80211_band band, u8 channel); +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); +int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id); int wl12xx_croc(struct wl1271 *wl, u8 role_id); int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_sta *sta, u8 hlid); int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); -void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, - enum ieee80211_band band); -int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); int wl12xx_cmd_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); -int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif); +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); -int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, - u32 mask, bool *timeout); enum wl1271_commands { CMD_INTERROGATE = 1, /* use this to read information elements */ @@ -162,11 +149,8 @@ enum wl1271_commands { CMD_WFD_START_DISCOVERY = 45, CMD_WFD_STOP_DISCOVERY = 46, CMD_WFD_ATTRIBUTE_CONFIG = 47, - CMD_GENERIC_CFG = 48, - CMD_NOP = 49, - - /* start of 18xx specific commands */ - CMD_DFS_CHANNEL_CONFIG = 60, + CMD_NOP = 48, + CMD_LAST_COMMAND, MAX_COMMAND_ID = 0xFFFF, }; @@ -183,8 +167,8 @@ enum cmd_templ { CMD_TEMPL_PS_POLL, CMD_TEMPL_KLV, CMD_TEMPL_DISCONNECT, - CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY, - CMD_TEMPL_APP_PROBE_REQ_5_LEGACY, + CMD_TEMPL_APP_PROBE_REQ_2_4, + CMD_TEMPL_APP_PROBE_REQ_5, CMD_TEMPL_BAR, /* for firmware internal use only */ CMD_TEMPL_CTS, /* * For CTS-to-self (FastCTS) mechanism @@ -195,8 +179,6 @@ enum cmd_templ { CMD_TEMPL_DEAUTH_AP, CMD_TEMPL_TEMPORARY, CMD_TEMPL_LINK_MEASUREMENT_REPORT, - CMD_TEMPL_PROBE_REQ_2_4_PERIODIC, - CMD_TEMPL_PROBE_REQ_5_PERIODIC, CMD_TEMPL_MAX = 0xff }; @@ -238,8 +220,7 @@ enum { CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ CMD_STATUS_TEMPLATE_OOM = 23, CMD_STATUS_NO_RX_BA_SESSION = 24, - - MAX_COMMAND_STATUS + MAX_COMMAND_STATUS = 0xff }; #define CMDMBOX_HEADER_LEN 4 @@ -364,15 +345,7 @@ struct wl12xx_cmd_role_start { u8 reset_tsf; - /* - * ap supports wmm (note that there is additional - * per-sta wmm configuration) - */ - u8 wmm; - - u8 bcast_session_id; - u8 global_session_id; - u8 padding_1[1]; + u8 padding_1[4]; } __packed ap; }; } __packed; @@ -542,14 +515,7 @@ struct wl12xx_cmd_set_peer_state { u8 hlid; u8 state; - - /* - * wmm is relevant for sta role only. - * ap role configures the per-sta wmm params in - * the add_peer command. - */ - u8 wmm; - u8 padding[1]; + u8 padding[2]; } __packed; struct wl12xx_cmd_roc { @@ -592,7 +558,7 @@ struct wl12xx_cmd_add_peer { u8 bss_index; u8 sp_len; u8 wmm; - u8 session_id; + u8 padding1; } __packed; struct wl12xx_cmd_remove_peer { @@ -631,13 +597,6 @@ enum wl12xx_fwlogger_output { WL12XX_FWLOG_OUTPUT_HOST, }; -struct wl12xx_cmd_regdomain_dfs_config { - struct wl1271_cmd_header header; - - __le32 ch_bit_map1; - __le32 ch_bit_map2; -} __packed; - struct wl12xx_cmd_config_fwlog { struct wl1271_cmd_header header; @@ -667,13 +626,27 @@ struct wl12xx_cmd_stop_fwlog { struct wl1271_cmd_header header; } __packed; -struct wl12xx_cmd_stop_channel_switch { +struct wl12xx_cmd_channel_switch { struct wl1271_cmd_header header; u8 role_id; + + /* The new serving channel */ + u8 channel; + /* Relative time of the serving channel switch in TBTT units */ + u8 switch_time; + /* Stop the role TX, should expect it after radar detection */ + u8 stop_tx; + /* The target channel tx status 1-stopped 0-open*/ + u8 post_switch_tx_disable; + u8 padding[3]; } __packed; +struct wl12xx_cmd_stop_channel_switch { + struct wl1271_cmd_header header; +} __packed; + /* Used to check radio status after calibration */ #define MAX_TLV_LENGTH 500 #define TEST_CMD_P2G_CAL 2 /* TX BiP */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/conf.h b/trunk/drivers/net/wireless/ti/wlcore/conf.h index 2b96ff821341..9e40760bafe1 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/conf.h +++ b/trunk/drivers/net/wireless/ti/wlcore/conf.h @@ -57,49 +57,20 @@ enum { }; enum { - CONF_HW_RATE_INDEX_1MBPS = 0, - CONF_HW_RATE_INDEX_2MBPS = 1, - CONF_HW_RATE_INDEX_5_5MBPS = 2, - CONF_HW_RATE_INDEX_11MBPS = 3, - CONF_HW_RATE_INDEX_6MBPS = 4, - CONF_HW_RATE_INDEX_9MBPS = 5, - CONF_HW_RATE_INDEX_12MBPS = 6, - CONF_HW_RATE_INDEX_18MBPS = 7, - CONF_HW_RATE_INDEX_24MBPS = 8, - CONF_HW_RATE_INDEX_36MBPS = 9, - CONF_HW_RATE_INDEX_48MBPS = 10, - CONF_HW_RATE_INDEX_54MBPS = 11, - CONF_HW_RATE_INDEX_MCS0 = 12, - CONF_HW_RATE_INDEX_MCS1 = 13, - CONF_HW_RATE_INDEX_MCS2 = 14, - CONF_HW_RATE_INDEX_MCS3 = 15, - CONF_HW_RATE_INDEX_MCS4 = 16, - CONF_HW_RATE_INDEX_MCS5 = 17, - CONF_HW_RATE_INDEX_MCS6 = 18, - CONF_HW_RATE_INDEX_MCS7 = 19, - CONF_HW_RATE_INDEX_MCS7_SGI = 20, - CONF_HW_RATE_INDEX_MCS0_40MHZ = 21, - CONF_HW_RATE_INDEX_MCS1_40MHZ = 22, - CONF_HW_RATE_INDEX_MCS2_40MHZ = 23, - CONF_HW_RATE_INDEX_MCS3_40MHZ = 24, - CONF_HW_RATE_INDEX_MCS4_40MHZ = 25, - CONF_HW_RATE_INDEX_MCS5_40MHZ = 26, - CONF_HW_RATE_INDEX_MCS6_40MHZ = 27, - CONF_HW_RATE_INDEX_MCS7_40MHZ = 28, - CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI = 29, - - /* MCS8+ rates overlap with 40Mhz rates */ - CONF_HW_RATE_INDEX_MCS8 = 21, - CONF_HW_RATE_INDEX_MCS9 = 22, - CONF_HW_RATE_INDEX_MCS10 = 23, - CONF_HW_RATE_INDEX_MCS11 = 24, - CONF_HW_RATE_INDEX_MCS12 = 25, - CONF_HW_RATE_INDEX_MCS13 = 26, - CONF_HW_RATE_INDEX_MCS14 = 27, - CONF_HW_RATE_INDEX_MCS15 = 28, - CONF_HW_RATE_INDEX_MCS15_SGI = 29, - - CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI, + CONF_HW_RATE_INDEX_1MBPS = 0, + CONF_HW_RATE_INDEX_2MBPS = 1, + CONF_HW_RATE_INDEX_5_5MBPS = 2, + CONF_HW_RATE_INDEX_6MBPS = 3, + CONF_HW_RATE_INDEX_9MBPS = 4, + CONF_HW_RATE_INDEX_11MBPS = 5, + CONF_HW_RATE_INDEX_12MBPS = 6, + CONF_HW_RATE_INDEX_18MBPS = 7, + CONF_HW_RATE_INDEX_22MBPS = 8, + CONF_HW_RATE_INDEX_24MBPS = 9, + CONF_HW_RATE_INDEX_36MBPS = 10, + CONF_HW_RATE_INDEX_48MBPS = 11, + CONF_HW_RATE_INDEX_54MBPS = 12, + CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, }; #define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff @@ -444,11 +415,11 @@ struct conf_rx_settings { #define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS /* - * Rates supported for data packets when operating as STA/AP. Note the absence + * Rates supported for data packets when operating as AP. Note the absence * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop * one. The rate dropped is not mandatory under any operating mode. */ -#define CONF_TX_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ +#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ @@ -706,18 +677,6 @@ struct conf_tx_settings { /* Time in ms for Tx watchdog timer to expire */ u32 tx_watchdog_timeout; - - /* - * when a slow link has this much packets pending, it becomes a low - * priority link, scheduling-wise - */ - u8 slow_link_thold; - - /* - * when a fast link has this much packets pending, it becomes a low - * priority link, scheduling-wise - */ - u8 fast_link_thold; } __packed; enum { @@ -1088,7 +1047,6 @@ struct conf_roam_trigger_settings { struct conf_scan_settings { /* * The minimum time to wait on each channel for active scans - * This value will be used whenever there's a connected interface. * * Range: u32 tu/1000 */ @@ -1096,37 +1054,24 @@ struct conf_scan_settings { /* * The maximum time to wait on each channel for active scans - * This value will be currently used whenever there's a - * connected interface. It shouldn't exceed 30000 (~30ms) to avoid - * possible interference of voip traffic going on while scanning. * * Range: u32 tu/1000 */ u32 max_dwell_time_active; - /* The minimum time to wait on each channel for active scans - * when it's possible to have longer scan dwell times. - * Currently this is used whenever we're idle on all interfaces. - * Longer dwell times improve detection of networks within a - * single scan. + /* + * The minimum time to wait on each channel for passive scans * * Range: u32 tu/1000 */ - u32 min_dwell_time_active_long; + u32 min_dwell_time_passive; - /* The maximum time to wait on each channel for active scans - * when it's possible to have longer scan dwell times. - * See min_dwell_time_active_long + /* + * The maximum time to wait on each channel for passive scans * * Range: u32 tu/1000 */ - u32 max_dwell_time_active_long; - - /* time to wait on the channel for passive scans (in TU/1000) */ - u32 dwell_time_passive; - - /* time to wait on the channel for DFS scans (in TU/1000) */ - u32 dwell_time_dfs; + u32 max_dwell_time_passive; /* * Number of probe requests to transmit on each active scan channel @@ -1331,20 +1276,12 @@ struct conf_hangover_settings { u8 window_size; } __packed; -struct conf_recovery_settings { - /* BUG() on fw recovery */ - u8 bug_on_recovery; - - /* Prevent HW recovery. FW will remain stuck. */ - u8 no_recovery; -} __packed; - /* * The conf version consists of 4 bytes. The two MSB are the wlcore * version, the two LSB are the lower driver's private conf * version. */ -#define WLCORE_CONF_VERSION (0x0005 << 16) +#define WLCORE_CONF_VERSION (0x0002 << 16) #define WLCORE_CONF_MASK 0xffff0000 #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ sizeof(struct wlcore_conf)) @@ -1372,7 +1309,6 @@ struct wlcore_conf { struct conf_fwlog fwlog; struct conf_rate_policy_settings rate; struct conf_hangover_settings hangover; - struct conf_recovery_settings recovery; } __packed; struct wlcore_conf_file { diff --git a/trunk/drivers/net/wireless/ti/wlcore/debugfs.c b/trunk/drivers/net/wireless/ti/wlcore/debugfs.c index e70a7c864865..c86bb00c2488 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/trunk/drivers/net/wireless/ti/wlcore/debugfs.c @@ -490,7 +490,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_HEX(chip.id); DRIVER_STATE_PRINT_STR(chip.fw_ver_str); DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); - DRIVER_STATE_PRINT_INT(recovery_count); + DRIVER_STATE_PRINT_INT(sched_scanning); #undef DRIVER_STATE_PRINT_INT #undef DRIVER_STATE_PRINT_LONG @@ -560,6 +560,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, if (wlvif->bss_type == BSS_TYPE_STA_BSS || wlvif->bss_type == BSS_TYPE_IBSS) { VIF_STATE_PRINT_INT(sta.hlid); + VIF_STATE_PRINT_INT(sta.ba_rx_bitmap); VIF_STATE_PRINT_INT(sta.basic_rate_idx); VIF_STATE_PRINT_INT(sta.ap_rate_idx); VIF_STATE_PRINT_INT(sta.p2p_rate_idx); @@ -576,10 +577,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]); } VIF_STATE_PRINT_INT(last_tx_hlid); - VIF_STATE_PRINT_INT(tx_queue_count[0]); - VIF_STATE_PRINT_INT(tx_queue_count[1]); - VIF_STATE_PRINT_INT(tx_queue_count[2]); - VIF_STATE_PRINT_INT(tx_queue_count[3]); VIF_STATE_PRINT_LHEX(links_map[0]); VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len); VIF_STATE_PRINT_INT(band); @@ -592,6 +589,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, VIF_STATE_PRINT_INT(beacon_int); VIF_STATE_PRINT_INT(default_key); VIF_STATE_PRINT_INT(aid); + VIF_STATE_PRINT_INT(session_counter); VIF_STATE_PRINT_INT(psm_entry_retry); VIF_STATE_PRINT_INT(power_level); VIF_STATE_PRINT_INT(rssi_thold); @@ -995,7 +993,7 @@ static ssize_t sleep_auth_write(struct file *file, return -EINVAL; } - if (value > WL1271_PSM_MAX) { + if (value < 0 || value > WL1271_PSM_MAX) { wl1271_warning("sleep_auth must be between 0 and %d", WL1271_PSM_MAX); return -ERANGE; diff --git a/trunk/drivers/net/wireless/ti/wlcore/event.c b/trunk/drivers/net/wireless/ti/wlcore/event.c index 70f289aa1bc6..48907054d493 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/event.c +++ b/trunk/drivers/net/wireless/ti/wlcore/event.c @@ -29,39 +29,34 @@ #include "scan.h" #include "wl12xx_80211.h" -void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr) +static void wl1271_event_rssi_trigger(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct event_mailbox *mbox) { - struct wl12xx_vif *wlvif; - struct ieee80211_vif *vif; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); enum nl80211_cqm_rssi_threshold_event event; - s8 metric = metric_arr[0]; + s8 metric = mbox->rssi_snr_trigger_metric[0]; wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); - /* TODO: check actual multi-role support */ - wl12xx_for_each_wlvif_sta(wl, wlvif) { - if (metric <= wlvif->rssi_thold) - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else - event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - - vif = wl12xx_wlvif_to_vif(wlvif); - if (event != wlvif->last_rssi_event) - ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL); - wlvif->last_rssi_event = event; - } + if (metric <= wlvif->rssi_thold) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + + if (event != wlvif->last_rssi_event) + ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL); + wlvif->last_rssi_event = event; } -EXPORT_SYMBOL_GPL(wlcore_event_rssi_trigger); static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); if (wlvif->bss_type != BSS_TYPE_AP_BSS) { - u8 hlid = wlvif->sta.hlid; - if (!wl->links[hlid].ba_bitmap) + if (!wlvif->sta.ba_rx_bitmap) return; - ieee80211_stop_rx_ba_session(vif, wl->links[hlid].ba_bitmap, + ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap, vif->bss_conf.bssid); } else { u8 hlid; @@ -79,7 +74,8 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) } } -void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable) +static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, + u8 enable) { struct wl12xx_vif *wlvif; @@ -91,169 +87,201 @@ void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable) wl1271_recalc_rx_streaming(wl, wlvif); } } + } -EXPORT_SYMBOL_GPL(wlcore_event_soft_gemini_sense); -void wlcore_event_sched_scan_completed(struct wl1271 *wl, - u8 status) +static void wl1271_event_mbox_dump(struct event_mailbox *mbox) { - wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)", - status); - - if (wl->sched_vif) { - ieee80211_sched_scan_stopped(wl->hw); - wl->sched_vif = NULL; - } + wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); } -EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_completed); -void wlcore_event_ba_rx_constraint(struct wl1271 *wl, - unsigned long roles_bitmap, - unsigned long allowed_bitmap) +static int wl1271_event_process(struct wl1271 *wl) { + struct event_mailbox *mbox = wl->mbox; + struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; + u32 vector; + bool disconnect_sta = false; + unsigned long sta_bitmap = 0; + int ret; + + wl1271_event_mbox_dump(mbox); - wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx allowed=0x%lx", - __func__, roles_bitmap, allowed_bitmap); + vector = le32_to_cpu(mbox->events_vector); + vector &= ~(le32_to_cpu(mbox->events_mask)); + wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); - wl12xx_for_each_wlvif(wl, wlvif) { - if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || - !test_bit(wlvif->role_id , &roles_bitmap)) - continue; + if (vector & SCAN_COMPLETE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "status: 0x%x", + mbox->scheduled_scan_status); - wlvif->ba_allowed = !!test_bit(wlvif->role_id, - &allowed_bitmap); - if (!wlvif->ba_allowed) - wl1271_stop_ba_event(wl, wlvif); + wl1271_scan_stm(wl, wl->scan_vif); } -} -EXPORT_SYMBOL_GPL(wlcore_event_ba_rx_constraint); -void wlcore_event_channel_switch(struct wl1271 *wl, - unsigned long roles_bitmap, - bool success) -{ - struct wl12xx_vif *wlvif; - struct ieee80211_vif *vif; + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " + "(status 0x%0x)", mbox->scheduled_scan_status); + + wl1271_scan_sched_scan_results(wl); + } + + if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " + "(status 0x%0x)", mbox->scheduled_scan_status); + if (wl->sched_scanning) { + ieee80211_sched_scan_stopped(wl->hw); + wl->sched_scanning = false; + } + } - wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d", - __func__, roles_bitmap, success); + if (vector & SOFT_GEMINI_SENSE_EVENT_ID) + wl12xx_event_soft_gemini_sense(wl, + mbox->soft_gemini_sense_info); - wl12xx_for_each_wlvif_sta(wl, wlvif) { - if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || - !test_bit(wlvif->role_id , &roles_bitmap)) - continue; + /* + * We are HW_MONITOR device. On beacon loss - queue + * connection loss work. Cancel it on REGAINED event. + */ + if (vector & BSS_LOSE_EVENT_ID) { + /* TODO: check for multi-role */ + int delay = wl->conf.conn.synch_fail_thold * + wl->conf.conn.bss_lose_timeout; + wl1271_info("Beacon loss detected."); - if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, - &wlvif->flags)) - continue; + /* + * if the work is already queued, it should take place. We + * don't want to delay the connection loss indication + * any more. + */ + ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work, + msecs_to_jiffies(delay)); - vif = wl12xx_wlvif_to_vif(wlvif); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_chswitch_done(vif, success); - cancel_delayed_work(&wlvif->channel_switch_work); + ieee80211_cqm_rssi_notify( + vif, + NL80211_CQM_RSSI_BEACON_LOSS_EVENT, + GFP_KERNEL); + } } -} -EXPORT_SYMBOL_GPL(wlcore_event_channel_switch); -void wlcore_event_dummy_packet(struct wl1271 *wl) -{ - wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); - wl1271_tx_dummy_packet(wl); -} -EXPORT_SYMBOL_GPL(wlcore_event_dummy_packet); + if (vector & REGAINED_BSS_EVENT_ID) { + /* TODO: check for multi-role */ + wl1271_info("Beacon regained."); + cancel_delayed_work(&wl->connection_loss_work); -static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap) -{ - u32 num_packets = wl->conf.tx.max_tx_retries; - struct wl12xx_vif *wlvif; - struct ieee80211_vif *vif; - struct ieee80211_sta *sta; - const u8 *addr; - int h; - - for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { - bool found = false; - /* find the ap vif connected to this sta */ - wl12xx_for_each_wlvif_ap(wl, wlvif) { - if (!test_bit(h, wlvif->ap.sta_hlid_map)) - continue; - found = true; - break; + /* sanity check - we can't lose and gain the beacon together */ + WARN(vector & BSS_LOSE_EVENT_ID, + "Concurrent beacon loss and gain from FW"); + } + + if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { + /* TODO: check actual multi-role support */ + wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); + wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl1271_event_rssi_trigger(wl, wlvif, mbox); } - if (!found) - continue; + } - vif = wl12xx_wlvif_to_vif(wlvif); - addr = wl->links[h].addr; + if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) { + u8 role_id = mbox->role_id; + wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " + "ba_allowed = 0x%x, role_id=%d", + mbox->rx_ba_allowed, role_id); - rcu_read_lock(); - sta = ieee80211_find_sta(vif, addr); - if (sta) { - wl1271_debug(DEBUG_EVENT, "remove sta %d", h); - ieee80211_report_low_ack(sta, num_packets); + wl12xx_for_each_wlvif(wl, wlvif) { + if (role_id != 0xff && role_id != wlvif->role_id) + continue; + + wlvif->ba_allowed = !!mbox->rx_ba_allowed; + if (!wlvif->ba_allowed) + wl1271_stop_ba_event(wl, wlvif); } - rcu_read_unlock(); } -} -void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap) -{ - wl1271_debug(DEBUG_EVENT, "MAX_TX_FAILURE_EVENT_ID"); - wlcore_disconnect_sta(wl, sta_bitmap); -} -EXPORT_SYMBOL_GPL(wlcore_event_max_tx_failure); + if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " + "status = 0x%x", + mbox->channel_switch_status); + /* + * That event uses for two cases: + * 1) channel switch complete with status=0 + * 2) channel switch failed status=1 + */ -void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap) -{ - wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); - wlcore_disconnect_sta(wl, sta_bitmap); -} -EXPORT_SYMBOL_GPL(wlcore_event_inactive_sta); + /* TODO: configure only the relevant vif */ + wl12xx_for_each_wlvif_sta(wl, wlvif) { + bool success; -void wlcore_event_roc_complete(struct wl1271 *wl) -{ - wl1271_debug(DEBUG_EVENT, "REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID"); - if (wl->roc_vif) - ieee80211_ready_on_channel(wl->hw); -} -EXPORT_SYMBOL_GPL(wlcore_event_roc_complete); + if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, + &wlvif->flags)) + continue; + + success = mbox->channel_switch_status ? false : true; + vif = wl12xx_wlvif_to_vif(wlvif); + + ieee80211_chswitch_done(vif, success); + } + } + + if ((vector & DUMMY_PACKET_EVENT_ID)) { + wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); + ret = wl1271_tx_dummy_packet(wl); + if (ret < 0) + return ret; + } -void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) -{ /* - * We are HW_MONITOR device. On beacon loss - queue - * connection loss work. Cancel it on REGAINED event. + * "TX retries exceeded" has a different meaning according to mode. + * In AP mode the offending station is disconnected. */ - struct wl12xx_vif *wlvif; - struct ieee80211_vif *vif; - int delay = wl->conf.conn.synch_fail_thold * - wl->conf.conn.bss_lose_timeout; + if (vector & MAX_TX_RETRY_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); + sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); + disconnect_sta = true; + } - wl1271_info("Beacon loss detected. roles:0x%lx", roles_bitmap); + if (vector & INACTIVE_STA_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); + sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); + disconnect_sta = true; + } - wl12xx_for_each_wlvif_sta(wl, wlvif) { - if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || - !test_bit(wlvif->role_id , &roles_bitmap)) - continue; + if (disconnect_sta) { + u32 num_packets = wl->conf.tx.max_tx_retries; + struct ieee80211_sta *sta; + const u8 *addr; + int h; + + for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { + bool found = false; + /* find the ap vif connected to this sta */ + wl12xx_for_each_wlvif_ap(wl, wlvif) { + if (!test_bit(h, wlvif->ap.sta_hlid_map)) + continue; + found = true; + break; + } + if (!found) + continue; - /* - * if the work is already queued, it should take place. - * We don't want to delay the connection loss - * indication any more. - */ - ieee80211_queue_delayed_work(wl->hw, - &wlvif->connection_loss_work, - msecs_to_jiffies(delay)); + vif = wl12xx_wlvif_to_vif(wlvif); + addr = wl->links[h].addr; - vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_cqm_rssi_notify( - vif, - NL80211_CQM_RSSI_BEACON_LOSS_EVENT, - GFP_KERNEL); + rcu_read_lock(); + sta = ieee80211_find_sta(vif, addr); + if (sta) { + wl1271_debug(DEBUG_EVENT, "remove sta %d", h); + ieee80211_report_low_ack(sta, num_packets); + } + rcu_read_unlock(); + } } + return 0; } -EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss); int wl1271_event_unmask(struct wl1271 *wl) { @@ -277,12 +305,12 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) /* first we read the mbox descriptor */ ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, - wl->mbox_size, false); + sizeof(*wl->mbox), false); if (ret < 0) return ret; /* process the descriptor */ - ret = wl->ops->process_mailbox_events(wl); + ret = wl1271_event_process(wl); if (ret < 0) return ret; diff --git a/trunk/drivers/net/wireless/ti/wlcore/event.h b/trunk/drivers/net/wireless/ti/wlcore/event.h index acc7a59d3828..8adf18d6c58f 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/event.h +++ b/trunk/drivers/net/wireless/ti/wlcore/event.h @@ -46,17 +46,33 @@ enum { RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), - + MEASUREMENT_START_EVENT_ID = BIT(8), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), + SCAN_COMPLETE_EVENT_ID = BIT(10), + WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), + RESERVED1 = BIT(13), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), + ROLE_STOP_COMPLETE_EVENT_ID = BIT(15), + RADAR_DETECTED_EVENT_ID = BIT(16), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), + BSS_LOSE_EVENT_ID = BIT(18), + REGAINED_BSS_EVENT_ID = BIT(19), + MAX_TX_RETRY_EVENT_ID = BIT(20), + DUMMY_PACKET_EVENT_ID = BIT(21), + SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23), + SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), + INACTIVE_STA_EVENT_ID = BIT(26), + PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), + PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), + PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), + BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; -/* events the driver might want to wait for */ -enum wlcore_wait_event { - WLCORE_EVENT_ROLE_STOP_COMPLETE, - WLCORE_EVENT_PEER_REMOVE_COMPLETE, - WLCORE_EVENT_DFS_CONFIG_COMPLETE -}; - enum { EVENT_ENTER_POWER_SAVE_FAIL = 0, EVENT_ENTER_POWER_SAVE_SUCCESS, @@ -64,24 +80,61 @@ enum { #define NUM_OF_RSSI_SNR_TRIGGERS 8 +struct event_mailbox { + __le32 events_vector; + __le32 events_mask; + __le32 reserved_1; + __le32 reserved_2; + + u8 number_of_scan_results; + u8 scan_tag; + u8 completed_scan_status; + u8 reserved_3; + + u8 soft_gemini_sense_info; + u8 soft_gemini_protective_info; + s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; + u8 change_auto_mode_timeout; + u8 scheduled_scan_status; + u8 reserved4; + /* tuned channel (roc) */ + u8 roc_channel; + + __le16 hlid_removed_bitmap; + + /* bitmap of aged stations (by HLID) */ + __le16 sta_aging_status; + + /* bitmap of stations (by HLID) which exceeded max tx retries */ + __le16 sta_tx_retry_exceeded; + + /* discovery completed results */ + u8 discovery_tag; + u8 number_of_preq_results; + u8 number_of_prsp_results; + u8 reserved_5; + + /* rx ba constraint */ + u8 role_id; /* 0xFF means any role. */ + u8 rx_ba_allowed; + u8 reserved_6[2]; + + /* Channel switch results */ + + u8 channel_switch_role_id; + u8 channel_switch_status; + u8 reserved_7[2]; + + u8 ps_poll_delivery_failure_role_ids; + u8 stopped_role_ids; + u8 started_role_ids; + + u8 reserved_8[9]; +} __packed; + struct wl1271; int wl1271_event_unmask(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); -void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable); -void wlcore_event_sched_scan_completed(struct wl1271 *wl, - u8 status); -void wlcore_event_ba_rx_constraint(struct wl1271 *wl, - unsigned long roles_bitmap, - unsigned long allowed_bitmap); -void wlcore_event_channel_switch(struct wl1271 *wl, - unsigned long roles_bitmap, - bool success); -void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap); -void wlcore_event_dummy_packet(struct wl1271 *wl); -void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap); -void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap); -void wlcore_event_roc_complete(struct wl1271 *wl); -void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr); #endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h b/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h index 7fd260c02a0a..2673d783ec1e 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -201,45 +201,4 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len) return buf_offset; } -static inline void -wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u32 changed) -{ - if (wl->ops->sta_rc_update) - wl->ops->sta_rc_update(wl, wlvif, sta, changed); -} - -static inline int -wlcore_hw_set_peer_cap(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, - u32 rate_set, u8 hlid) -{ - if (wl->ops->set_peer_cap) - return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation, - rate_set, hlid); - - return 0; -} - -static inline bool -wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk) -{ - if (!wl->ops->lnk_high_prio) - BUG_ON(1); - - return wl->ops->lnk_high_prio(wl, hlid, lnk); -} - -static inline bool -wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk) -{ - if (!wl->ops->lnk_low_prio) - BUG_ON(1); - - return wl->ops->lnk_low_prio(wl, hlid, lnk); -} - #endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/init.c b/trunk/drivers/net/wireless/ti/wlcore/init.c index 5c6f11e157d9..32d157f62f31 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/init.c +++ b/trunk/drivers/net/wireless/ti/wlcore/init.c @@ -41,14 +41,14 @@ int wl1271_init_templates_config(struct wl1271 *wl) /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - wl->scan_templ_id_2_4, NULL, + CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - wl->scan_templ_id_5, + CMD_TEMPL_CFG_PROBE_REQ_5, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) @@ -56,16 +56,14 @@ int wl1271_init_templates_config(struct wl1271 *wl) if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) { ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - wl->sched_scan_templ_id_2_4, - NULL, + CMD_TEMPL_APP_PROBE_REQ_2_4, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - wl->sched_scan_templ_id_5, - NULL, + CMD_TEMPL_APP_PROBE_REQ_5, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) @@ -465,7 +463,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) supported_rates = CONF_TX_OFDM_RATES; else - supported_rates = CONF_TX_ENABLED_RATES; + supported_rates = CONF_TX_AP_ENABLED_RATES; /* unconditionally enable HT rates */ supported_rates |= CONF_TX_MCS_RATES; @@ -577,6 +575,9 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) /* Configure for power according to debugfs */ if (sta_auth != WL1271_PSM_ILLEGAL) ret = wl1271_acx_sleep_auth(wl, sta_auth); + /* Configure for power always on */ + else if (wl->quirks & WLCORE_QUIRK_NO_ELP) + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); /* Configure for ELP power saving */ else ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); @@ -678,10 +679,6 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wlcore_cmd_regdomain_config_locked(wl); - if (ret < 0) - return ret; - /* Bluetooth WLAN coexistence */ ret = wl1271_init_pta(wl); if (ret < 0) diff --git a/trunk/drivers/net/wireless/ti/wlcore/io.h b/trunk/drivers/net/wireless/ti/wlcore/io.h index af7d9f9b3b4d..f48530fec14f 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/io.h +++ b/trunk/drivers/net/wireless/ti/wlcore/io.h @@ -105,13 +105,13 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr, { int ret; - ret = wlcore_raw_read(wl, addr, wl->buffer_32, - sizeof(*wl->buffer_32), false); + ret = wlcore_raw_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); if (ret < 0) return ret; if (val) - *val = le32_to_cpu(*wl->buffer_32); + *val = le32_to_cpu(wl->buffer_32); return 0; } @@ -119,9 +119,9 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr, static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr, u32 val) { - *wl->buffer_32 = cpu_to_le32(val); - return wlcore_raw_write(wl, addr, wl->buffer_32, - sizeof(*wl->buffer_32), false); + wl->buffer_32 = cpu_to_le32(val); + return wlcore_raw_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); } static inline int __must_check wlcore_read(struct wl1271 *wl, int addr, diff --git a/trunk/drivers/net/wireless/ti/wlcore/main.c b/trunk/drivers/net/wireless/ti/wlcore/main.c index 28a37576d568..919ad70cc520 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/main.c +++ b/trunk/drivers/net/wireless/ti/wlcore/main.c @@ -56,8 +56,8 @@ #define WL1271_BOOT_RETRIES 3 static char *fwlog_param; -static int bug_on_recovery = -1; -static int no_recovery = -1; +static bool bug_on_recovery; +static bool no_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, struct ieee80211_vif *vif, @@ -79,10 +79,12 @@ static int wl12xx_set_authorized(struct wl1271 *wl, if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) return 0; - ret = wl12xx_cmd_set_peer_state(wl, wlvif, wlvif->sta.hlid); + ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid); if (ret < 0) return ret; + wl12xx_croc(wl, wlvif->role_id); + wl1271_info("Association completed."); return 0; } @@ -93,8 +95,6 @@ static void wl1271_reg_notify(struct wiphy *wiphy, struct ieee80211_supported_band *band; struct ieee80211_channel *ch; int i; - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct wl1271 *wl = hw->priv; band = wiphy->bands[IEEE80211_BAND_5GHZ]; for (i = 0; i < band->n_channels; i++) { @@ -107,9 +107,6 @@ static void wl1271_reg_notify(struct wiphy *wiphy, IEEE80211_CHAN_PASSIVE_SCAN; } - - if (likely(wl->state == WLCORE_STATE_ON)) - wlcore_regdomain_config(wl); } static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, @@ -304,7 +301,6 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work) static void wlcore_adjust_conf(struct wl1271 *wl) { /* Adjust settings according to optional module parameters */ - if (fwlog_param) { if (!strcmp(fwlog_param, "continuous")) { wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; @@ -320,22 +316,16 @@ static void wlcore_adjust_conf(struct wl1271 *wl) wl1271_error("Unknown fwlog parameter %s", fwlog_param); } } - - if (bug_on_recovery != -1) - wl->conf.recovery.bug_on_recovery = (u8) bug_on_recovery; - - if (no_recovery != -1) - wl->conf.recovery.no_recovery = (u8) no_recovery; } static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid, u8 tx_pkts) { - bool fw_ps, single_link; + bool fw_ps, single_sta; fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - single_link = (wl->active_link_count == 1); + single_sta = (wl->active_sta_count == 1); /* * Wake up from high level PS if the STA is asleep with too little @@ -346,10 +336,10 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, /* * Start high-level PS if the STA is asleep with enough blocks in FW. - * Make an exception if this is the only connected link. In this - * case FW-memory congestion is less of a problem. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. */ - else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl12xx_ps_link_start(wl, wlvif, hlid, true); } @@ -357,8 +347,11 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl_fw_status_2 *status) { + struct wl1271_link *lnk; u32 cur_fw_ps_map; - u8 hlid; + u8 hlid, cnt; + + /* TODO: also use link_fast_bitmap here */ cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); if (wl->ap_fw_ps_map != cur_fw_ps_map) { @@ -370,9 +363,17 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, wl->ap_fw_ps_map = cur_fw_ps_map; } - for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) + for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { + lnk = &wl->links[hlid]; + cnt = status->counters.tx_lnk_free_pkts[hlid] - + lnk->prev_freed_pkts; + + lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid]; + lnk->allocated_pkts -= cnt; + wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, - wl->links[hlid].allocated_pkts); + lnk->allocated_pkts); + } } static int wlcore_fw_status(struct wl1271 *wl, @@ -386,7 +387,6 @@ static int wlcore_fw_status(struct wl1271 *wl, int i; size_t status_len; int ret; - struct wl1271_link *lnk; status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + sizeof(*status_2) + wl->fw_status_priv_len; @@ -412,17 +412,6 @@ static int wlcore_fw_status(struct wl1271 *wl, wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i]; } - - for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) { - lnk = &wl->links[i]; - /* prevent wrap-around in freed-packets counter */ - lnk->allocated_pkts -= - (status_2->counters.tx_lnk_free_pkts[i] - - lnk->prev_freed_pkts) & 0xff; - - lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i]; - } - /* prevent wrap-around in total blocks counter */ if (likely(wl->tx_blocks_freed <= le32_to_cpu(status_2->total_released_blks))) @@ -475,8 +464,6 @@ static int wlcore_fw_status(struct wl1271 *wl, wl->time_offset = (timespec_to_ns(&ts) >> 10) - (s64)le32_to_cpu(status_2->fw_localtime); - wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap); - return 0; } @@ -813,13 +800,11 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) /* * Make sure the chip is awake and the logger isn't active. - * Do not send a stop fwlog command if the fw is hanged or if - * dbgpins are used (due to some fw bug). + * Do not send a stop fwlog command if the fw is hanged. */ if (wl1271_ps_elp_wakeup(wl)) goto out; - if (!wl->watchdog_recovery && - wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS) + if (!wl->watchdog_recovery) wl12xx_cmd_stop_fwlog(wl); /* Read the first memory block address */ @@ -887,8 +872,7 @@ static void wlcore_print_recovery(struct wl1271 *wl) if (ret < 0) return; - wl1271_info("pc: 0x%x, hint_sts: 0x%08x count: %d", - pc, hint_sts, ++wl->recovery_count); + wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts); wlcore_set_partition(wl, &wl->ptable[PART_WORK]); } @@ -911,10 +895,10 @@ static void wl1271_recovery_work(struct work_struct *work) wlcore_print_recovery(wl); } - BUG_ON(wl->conf.recovery.bug_on_recovery && + BUG_ON(bug_on_recovery && !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); - if (wl->conf.recovery.no_recovery) { + if (no_recovery) { wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); goto out_unlock; } @@ -934,6 +918,11 @@ static void wl1271_recovery_work(struct work_struct *work) /* Prevent spurious TX during FW restart */ wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); + if (wl->sched_scanning) { + ieee80211_sched_scan_stopped(wl->hw); + wl->sched_scanning = false; + } + /* reboot the chipset */ while (!list_empty(&wl->wlvif_list)) { wlvif = list_first_entry(&wl->wlvif_list, @@ -1150,6 +1139,7 @@ int wl1271_plt_stop(struct wl1271 *wl) cancel_work_sync(&wl->recovery_work); cancel_delayed_work_sync(&wl->elp_work); cancel_delayed_work_sync(&wl->tx_watchdog_work); + cancel_delayed_work_sync(&wl->connection_loss_work); mutex_lock(&wl->mutex); wl1271_power_off(wl); @@ -1177,13 +1167,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, int q, mapping; u8 hlid; - if (!vif) { - wl1271_debug(DEBUG_TX, "DROP skb with no vif"); - ieee80211_free_txskb(hw, skb); - return; - } + if (vif) + wlvif = wl12xx_vif_to_data(vif); - wlvif = wl12xx_vif_to_data(vif); mapping = skb_get_queue_mapping(skb); q = wl1271_tx_get_queue(mapping); @@ -1197,9 +1183,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, * allow these packets through. */ if (hlid == WL12XX_INVALID_LINK_ID || - (!test_bit(hlid, wlvif->links_map)) || - (wlcore_is_queue_stopped_locked(wl, wlvif, q) && - !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q, + (wlvif && !test_bit(hlid, wlvif->links_map)) || + (wlcore_is_queue_stopped(wl, q) && + !wlcore_is_queue_stopped_by_reason(wl, q, WLCORE_QUEUE_STOP_REASON_WATERMARK))) { wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); ieee80211_free_txskb(hw, skb); @@ -1211,17 +1197,16 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); wl->tx_queue_count[q]++; - wlvif->tx_queue_count[q]++; /* * The workqueue is slow to process the tx_queue and we need stop * the queue here, otherwise the queue will get too long. */ - if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && - !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q, + if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && + !wlcore_is_queue_stopped_by_reason(wl, q, WLCORE_QUEUE_STOP_REASON_WATERMARK)) { wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); - wlcore_stop_queue_locked(wl, wlvif, q, + wlcore_stop_queue_locked(wl, q, WLCORE_QUEUE_STOP_REASON_WATERMARK); } @@ -1856,10 +1841,11 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->elp_work); cancel_delayed_work_sync(&wl->tx_watchdog_work); + cancel_delayed_work_sync(&wl->connection_loss_work); /* let's notify MAC80211 about the remaining pending TX frames */ - mutex_lock(&wl->mutex); wl12xx_tx_reset(wl); + mutex_lock(&wl->mutex); wl1271_power_off(wl); /* @@ -1882,17 +1868,14 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) wl->time_offset = 0; wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; + wl->sched_scanning = false; wl->sleep_auth = WL1271_PSM_ILLEGAL; memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); memset(wl->roc_map, 0, sizeof(wl->roc_map)); - memset(wl->session_ids, 0, sizeof(wl->session_ids)); wl->active_sta_count = 0; - wl->active_link_count = 0; /* The system link is always allocated */ - wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0; - wl->links[WL12XX_SYSTEM_HLID].prev_freed_pkts = 0; __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); /* @@ -1918,12 +1901,6 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) wl->tx_res_if = NULL; kfree(wl->target_mem_map); wl->target_mem_map = NULL; - - /* - * FW channels must be re-calibrated after recovery, - * clear the last Reg-Domain channel configuration. - */ - memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last)); } static void wlcore_op_stop(struct ieee80211_hw *hw) @@ -1939,71 +1916,6 @@ static void wlcore_op_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } -static void wlcore_channel_switch_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - struct ieee80211_vif *vif; - struct wl12xx_vif *wlvif; - int ret; - - dwork = container_of(work, struct delayed_work, work); - wlvif = container_of(dwork, struct wl12xx_vif, channel_switch_work); - wl = wlvif->wl; - - wl1271_info("channel switch failed (role_id: %d).", wlvif->role_id); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state != WLCORE_STATE_ON)) - goto out; - - /* check the channel switch is still ongoing */ - if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) - goto out; - - vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_chswitch_done(vif, false); - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl12xx_cmd_stop_channel_switch(wl, wlvif); - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - -static void wlcore_connection_loss_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - struct ieee80211_vif *vif; - struct wl12xx_vif *wlvif; - - dwork = container_of(work, struct delayed_work, work); - wlvif = container_of(dwork, struct wl12xx_vif, connection_loss_work); - wl = wlvif->wl; - - wl1271_info("Connection loss work (role_id: %d).", wlvif->role_id); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state != WLCORE_STATE_ON)) - goto out; - - /* Call mac80211 connection loss */ - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - goto out; - - vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_connection_loss(vif); -out: - mutex_unlock(&wl->mutex); -} - static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) { u8 policy = find_first_zero_bit(wl->rate_policies_map, @@ -2123,15 +2035,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) wl12xx_allocate_rate_policy(wl, &wlvif->ap.ucast_rate_idx[i]); - wlvif->basic_rate_set = CONF_TX_ENABLED_RATES; + wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES; /* * TODO: check if basic_rate shouldn't be * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); * instead (the same thing for STA above). */ - wlvif->basic_rate = CONF_TX_ENABLED_RATES; + wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES; /* TODO: this seems to be used only for STA, check it */ - wlvif->rate_set = CONF_TX_ENABLED_RATES; + wlvif->rate_set = CONF_TX_AP_ENABLED_RATES; } wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; @@ -2151,10 +2063,6 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wl1271_rx_streaming_enable_work); INIT_WORK(&wlvif->rx_streaming_disable_work, wl1271_rx_streaming_disable_work); - INIT_DELAYED_WORK(&wlvif->channel_switch_work, - wlcore_channel_switch_work); - INIT_DELAYED_WORK(&wlvif->connection_loss_work, - wlcore_connection_loss_work); INIT_LIST_HEAD(&wlvif->list); setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, @@ -2162,7 +2070,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) return 0; } -static int wl12xx_init_fw(struct wl1271 *wl) +static bool wl12xx_init_fw(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; bool booted = false; @@ -2228,7 +2136,7 @@ static int wl12xx_init_fw(struct wl1271 *wl) wl->state = WLCORE_STATE_ON; out: - return ret; + return booted; } static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) @@ -2288,81 +2196,6 @@ static void wl12xx_force_active_psm(struct wl1271 *wl) } } -struct wlcore_hw_queue_iter_data { - unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)]; - /* current vif */ - struct ieee80211_vif *vif; - /* is the current vif among those iterated */ - bool cur_running; -}; - -static void wlcore_hw_queue_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct wlcore_hw_queue_iter_data *iter_data = data; - - if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) - return; - - if (iter_data->cur_running || vif == iter_data->vif) { - iter_data->cur_running = true; - return; - } - - __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map); -} - -static int wlcore_allocate_hw_queue_base(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct wlcore_hw_queue_iter_data iter_data = {}; - int i, q_base; - - iter_data.vif = vif; - - /* mark all bits taken by active interfaces */ - ieee80211_iterate_active_interfaces_atomic(wl->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - wlcore_hw_queue_iter, &iter_data); - - /* the current vif is already running in mac80211 (resume/recovery) */ - if (iter_data.cur_running) { - wlvif->hw_queue_base = vif->hw_queue[0]; - wl1271_debug(DEBUG_MAC80211, - "using pre-allocated hw queue base %d", - wlvif->hw_queue_base); - - /* interface type might have changed type */ - goto adjust_cab_queue; - } - - q_base = find_first_zero_bit(iter_data.hw_queue_map, - WLCORE_NUM_MAC_ADDRESSES); - if (q_base >= WLCORE_NUM_MAC_ADDRESSES) - return -EBUSY; - - wlvif->hw_queue_base = q_base * NUM_TX_QUEUES; - wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d", - wlvif->hw_queue_base); - - for (i = 0; i < NUM_TX_QUEUES; i++) { - wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0; - /* register hw queues in mac80211 */ - vif->hw_queue[i] = wlvif->hw_queue_base + i; - } - -adjust_cab_queue: - /* the last places are reserved for cab queues per interface */ - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES + - wlvif->hw_queue_base / NUM_TX_QUEUES; - else - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; - - return 0; -} - static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -2371,6 +2204,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct vif_counter_data vif_count; int ret = 0; u8 role_type; + bool booted = false; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; @@ -2408,10 +2242,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - ret = wlcore_allocate_hw_queue_base(wl, wlvif); - if (ret < 0) - goto out; - if (wl12xx_need_fw_change(wl, vif_count, true)) { wl12xx_force_active_psm(wl); set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); @@ -2431,9 +2261,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, */ memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN); - ret = wl12xx_init_fw(wl); - if (ret < 0) + booted = wl12xx_init_fw(wl); + if (!booted) { + ret = -EINVAL; goto out; + } } ret = wl12xx_cmd_role_enable(wl, vif->addr, @@ -2480,7 +2312,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl1271_info("down"); if (wl->scan.state != WL1271_SCAN_STATE_IDLE && - wl->scan_wlvif == wlvif) { + wl->scan_vif == vif) { /* * Rearm the tx watchdog just before idling scan. This * prevents just-finished scans from triggering the watchdog @@ -2489,21 +2321,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan_wlvif = NULL; + wl->scan_vif = NULL; wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); } - if (wl->sched_vif == wlvif) { - ieee80211_sched_scan_stopped(wl->hw); - wl->sched_vif = NULL; - } - - if (wl->roc_vif == vif) { - wl->roc_vif = NULL; - ieee80211_remain_on_channel_expired(wl->hw); - } - if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { /* disable active roles */ ret = wl1271_ps_elp_wakeup(wl); @@ -2572,6 +2394,9 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, /* Configure for power according to debugfs */ if (sta_auth != WL1271_PSM_ILLEGAL) wl1271_acx_sleep_auth(wl, sta_auth); + /* Configure for power always on */ + else if (wl->quirks & WLCORE_QUIRK_NO_ELP) + wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); /* Configure for ELP power saving */ else wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); @@ -2583,7 +2408,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, del_timer_sync(&wlvif->rx_streaming_timer); cancel_work_sync(&wlvif->rx_streaming_enable_work); cancel_work_sync(&wlvif->rx_streaming_disable_work); - cancel_delayed_work_sync(&wlvif->connection_loss_work); mutex_lock(&wl->mutex); } @@ -2642,7 +2466,8 @@ static int wl12xx_op_change_interface(struct ieee80211_hw *hw, return ret; } -static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif) +static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool set_assoc) { int ret; bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); @@ -2662,111 +2487,18 @@ static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif) /* clear encryption type */ wlvif->encryption_type = KEY_NONE; + if (set_assoc) + set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); + if (is_ibss) ret = wl12xx_cmd_role_start_ibss(wl, wlvif); - else { - if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) { - /* - * TODO: this is an ugly workaround for wl12xx fw - * bug - we are not able to tx/rx after the first - * start_sta, so make dummy start+stop calls, - * and then call start_sta again. - * this should be fixed in the fw. - */ - wl12xx_cmd_role_start_sta(wl, wlvif); - wl12xx_cmd_role_stop_sta(wl, wlvif); - } - + else ret = wl12xx_cmd_role_start_sta(wl, wlvif); - } - - return ret; -} - -static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb, - int offset) -{ - u8 ssid_len; - const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, - skb->len - offset); - - if (!ptr) { - wl1271_error("No SSID in IEs!"); - return -ENOENT; - } - - ssid_len = ptr[1]; - if (ssid_len > IEEE80211_MAX_SSID_LEN) { - wl1271_error("SSID is too long!"); - return -EINVAL; - } - - wlvif->ssid_len = ssid_len; - memcpy(wlvif->ssid, ptr+2, ssid_len); - return 0; -} - -static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct sk_buff *skb; - int ieoffset; - - /* we currently only support setting the ssid from the ap probe req */ - if (wlvif->bss_type != BSS_TYPE_STA_BSS) - return -EINVAL; - - skb = ieee80211_ap_probereq_get(wl->hw, vif); - if (!skb) - return -EINVAL; - - ieoffset = offsetof(struct ieee80211_mgmt, - u.probe_req.variable); - wl1271_ssid_set(wlvif, skb, ieoffset); - dev_kfree_skb(skb); - - return 0; -} - -static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_bss_conf *bss_conf, - u32 sta_rate_set) -{ - int ieoffset; - int ret; - - wlvif->aid = bss_conf->aid; - wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef); - wlvif->beacon_int = bss_conf->beacon_int; - wlvif->wmm_enabled = bss_conf->qos; - - set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); - - /* - * with wl1271, we don't need to update the - * beacon_int and dtim_period, because the firmware - * updates it by itself when the first beacon is - * received after a join. - */ - ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); if (ret < 0) - return ret; + goto out; - /* - * Get a template for hardware connection maintenance - */ - dev_kfree_skb(wlvif->probereq); - wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, - wlvif, - NULL); - ieoffset = offsetof(struct ieee80211_mgmt, - u.probe_req.variable); - wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset); - - /* enable the connection monitoring feature */ - ret = wl1271_acx_conn_monit_params(wl, wlvif, true); - if (ret < 0) - return ret; + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; /* * The join command disable the keep-alive mode, shut down its process, @@ -2776,83 +2508,35 @@ static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, */ ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); if (ret < 0) - return ret; + goto out; ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); if (ret < 0) - return ret; + goto out; ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); if (ret < 0) - return ret; + goto out; ret = wl1271_acx_keep_alive_config(wl, wlvif, wlvif->sta.klv_template_id, ACX_KEEP_ALIVE_TPL_VALID); if (ret < 0) - return ret; - - /* - * The default fw psm configuration is AUTO, while mac80211 default - * setting is off (ACTIVE), so sync the fw with the correct value. - */ - ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - - if (sta_rate_set) { - wlvif->rate_set = - wl1271_tx_enabled_rates_get(wl, - sta_rate_set, - wlvif->band); - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - return ret; - } + goto out; +out: return ret; } -static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif) +static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; - bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS; - - /* make sure we are connected (sta) joined */ - if (sta && - !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - return false; - - /* make sure we are joined (ibss) */ - if (!sta && - test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) - return false; - - if (sta) { - /* use defaults when not associated */ - wlvif->aid = 0; - - /* free probe-request template */ - dev_kfree_skb(wlvif->probereq); - wlvif->probereq = NULL; - - /* disable connection monitor features */ - ret = wl1271_acx_conn_monit_params(wl, wlvif, false); - if (ret < 0) - return ret; - - /* Disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); - if (ret < 0) - return ret; - } if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - wl12xx_cmd_stop_channel_switch(wl, wlvif); + wl12xx_cmd_stop_channel_switch(wl); ieee80211_chswitch_done(vif, false); - cancel_delayed_work(&wlvif->channel_switch_work); } /* invalidate keep-alive template */ @@ -2860,11 +2544,17 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->sta.klv_template_id, ACX_KEEP_ALIVE_TPL_INVALID); + /* to stop listening to a channel, we disconnect */ + ret = wl12xx_cmd_role_stop_sta(wl, wlvif); + if (ret < 0) + goto out; + /* reset TX security counters on a clean disconnect */ wlvif->tx_security_last_seq_lsb = 0; wlvif->tx_security_seq = 0; - return 0; +out: + return ret; } static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) @@ -2873,38 +2563,195 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->rate_set = wlvif->basic_rate_set; } -static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_conf *conf, u32 changed) +static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool idle) { int ret; + bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); - if (conf->power_level != wlvif->power_level) { - ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); + if (idle == cur_idle) + return 0; + + if (idle) { + /* no need to croc if we weren't busy (e.g. during boot) */ + if (wl12xx_dev_role_started(wlvif)) { + ret = wl12xx_stop_dev(wl, wlvif); + if (ret < 0) + goto out; + } + wlvif->rate_set = + wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) - return ret; + goto out; + clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + } else { + /* The current firmware only supports sched_scan in idle */ + if (wl->sched_scanning) { + wl1271_scan_sched_scan_stop(wl, wlvif); + ieee80211_sched_scan_stopped(wl->hw); + } - wlvif->power_level = conf->power_level; + ret = wl12xx_start_dev(wl, wlvif); + if (ret < 0) + goto out; + set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); } - return 0; +out: + return ret; } -static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_conf *conf, u32 changed) { - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - struct ieee80211_conf *conf = &hw->conf; - int ret = 0; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int channel, ret; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + /* if the channel changes while joined, join again */ + if (changed & IEEE80211_CONF_CHANGE_CHANNEL && + ((wlvif->band != conf->channel->band) || + (wlvif->channel != channel) || + (wlvif->channel_type != conf->channel_type))) { + /* send all pending packets */ + ret = wlcore_tx_work_locked(wl); + if (ret < 0) + return ret; + + wlvif->band = conf->channel->band; + wlvif->channel = channel; + wlvif->channel_type = conf->channel_type; + + if (is_ap) { + wl1271_set_band_rate(wl, wlvif); + ret = wl1271_init_ap_rates(wl, wlvif); + if (ret < 0) + wl1271_error("AP rate policy change failed %d", + ret); + } else { + /* + * FIXME: the mac80211 should really provide a fixed + * rate to use here. for now, just use the smallest + * possible rate for the band as a fixed rate for + * association frames and other control messages. + */ + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + wl1271_set_band_rate(wl, wlvif); + + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + wl1271_warning("rate policy for channel " + "failed %d", ret); + + /* + * change the ROC channel. do it only if we are + * not idle. otherwise, CROC will be called + * anyway. + */ + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags) && + wl12xx_dev_role_started(wlvif) && + !(conf->flags & IEEE80211_CONF_IDLE)) { + ret = wl12xx_stop_dev(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl12xx_start_dev(wl, wlvif); + if (ret < 0) + return ret; + } + } + } + + if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { + + if ((conf->flags & IEEE80211_CONF_PS) && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && + !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { + + int ps_mode; + char *ps_mode_str; + + if (wl->conf.conn.forced_ps) { + ps_mode = STATION_POWER_SAVE_MODE; + ps_mode_str = "forced"; + } else { + ps_mode = STATION_AUTO_PS_MODE; + ps_mode_str = "auto"; + } + + wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); + + ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); + + if (ret < 0) + wl1271_warning("enter %s ps failed %d", + ps_mode_str, ret); + + } else if (!(conf->flags & IEEE80211_CONF_PS) && + test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { + + wl1271_debug(DEBUG_PSM, "auto ps disabled"); + + ret = wl1271_ps_set_mode(wl, wlvif, + STATION_ACTIVE_MODE); + if (ret < 0) + wl1271_warning("exit auto ps failed %d", ret); + } + } - wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s" + if (conf->power_level != wlvif->power_level) { + ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); + if (ret < 0) + return ret; + + wlvif->power_level = conf->power_level; + } + + return 0; +} + +static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" " changed 0x%x", + channel, conf->flags & IEEE80211_CONF_PS ? "on" : "off", conf->power_level, conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", changed); + /* + * mac80211 will go to idle nearly immediately after transmitting some + * frames, such as the deauth. To make sure those frames reach the air, + * wait here until the TX queue is fully flushed. + */ + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || + ((changed & IEEE80211_CONF_CHANGE_IDLE) && + (conf->flags & IEEE80211_CONF_IDLE))) + wl1271_tx_flush(wl); + mutex_lock(&wl->mutex); + /* we support configuring the channel and band even while off */ + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + wl->band = conf->channel->band; + wl->channel = channel; + wl->channel_type = conf->channel_type; + } + if (changed & IEEE80211_CONF_CHANGE_POWER) wl->power_level = conf->power_level; @@ -3224,7 +3071,10 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * stop the queues and flush to ensure the next packets are * in sync with FW spare block accounting */ + mutex_lock(&wl->mutex); wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); + mutex_unlock(&wl->mutex); + wl1271_tx_flush(wl); } @@ -3350,29 +3200,6 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, } EXPORT_SYMBOL_GPL(wlcore_set_key); -void wlcore_regdomain_config(struct wl1271 *wl) -{ - int ret; - - if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF)) - return; - - mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wlcore_cmd_regdomain_config_locked(wl); - if (ret < 0) { - wl12xx_queue_recovery_work(wl); - goto out; - } - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - static int wl1271_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) @@ -3412,7 +3239,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, goto out_sleep; } - ret = wlcore_scan(hw->priv, vif, ssid, len, req); + ret = wl1271_scan(hw->priv, vif, ssid, len, req); out_sleep: wl1271_ps_elp_sleep(wl); out: @@ -3425,7 +3252,6 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); @@ -3443,7 +3269,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, goto out; if (wl->scan.state != WL1271_SCAN_STATE_DONE) { - ret = wl->ops->scan_stop(wl, wlvif); + ret = wl1271_scan_stop(wl); if (ret < 0) goto out_sleep; } @@ -3456,7 +3282,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan_wlvif = NULL; + wl->scan_vif = NULL; wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); @@ -3490,11 +3316,15 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl->ops->sched_scan_start(wl, wlvif, req, ies); + ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); + if (ret < 0) + goto out_sleep; + + ret = wl1271_scan_sched_scan_start(wl, wlvif); if (ret < 0) goto out_sleep; - wl->sched_vif = wlvif; + wl->sched_scanning = true; out_sleep: wl1271_ps_elp_sleep(wl); @@ -3521,7 +3351,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, if (ret < 0) goto out; - wl->ops->sched_scan_stop(wl, wlvif); + wl1271_scan_sched_scan_stop(wl, wlvif); wl1271_ps_elp_sleep(wl); out: @@ -3586,6 +3416,30 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } +static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb, + int offset) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + u8 ssid_len; + const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, + skb->len - offset); + + if (!ptr) { + wl1271_error("No SSID in IEs!"); + return -ENOENT; + } + + ssid_len = ptr[1]; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + wl1271_error("SSID is too long!"); + return -EINVAL; + } + + wlvif->ssid_len = ssid_len; + memcpy(wlvif->ssid, ptr+2, ssid_len); + return 0; +} + static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) { int len; @@ -3766,7 +3620,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, wl1271_debug(DEBUG_MASTER, "beacon updated"); - ret = wl1271_ssid_set(wlvif, beacon, ieoffset); + ret = wl1271_ssid_set(vif, beacon, ieoffset); if (ret < 0) { dev_kfree_skb(beacon); goto out; @@ -3783,12 +3637,6 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, goto out; } - wlvif->wmm_enabled = - cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, - WLAN_OUI_TYPE_MICROSOFT_WMM, - beacon->data + ieoffset, - beacon->len - ieoffset); - /* * In case we already have a probe-resp beacon set explicitly * by usermode, don't use the beacon data. @@ -3842,7 +3690,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret = 0; - if (changed & BSS_CHANGED_BEACON_INT) { + if ((changed & BSS_CHANGED_BEACON_INT)) { wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", bss_conf->beacon_int); @@ -3855,7 +3703,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, wl1271_ap_set_probe_resp_tmpl(wl, rate, vif); } - if (changed & BSS_CHANGED_BEACON) { + if ((changed & BSS_CHANGED_BEACON)) { ret = wlcore_set_beacon_template(wl, vif, is_ap); if (ret < 0) goto out; @@ -3876,7 +3724,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret = 0; - if (changed & BSS_CHANGED_BASIC_RATES) { + if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, @@ -3907,7 +3755,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if (ret < 0) goto out; - if (changed & BSS_CHANGED_BEACON_ENABLED) { + if ((changed & BSS_CHANGED_BEACON_ENABLED)) { if (bss_conf->enable_beacon) { if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { ret = wl12xx_cmd_role_start_ap(wl, wlvif); @@ -3954,79 +3802,6 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, return; } -static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_bss_conf *bss_conf, - u32 sta_rate_set) -{ - u32 rates; - int ret; - - wl1271_debug(DEBUG_MAC80211, - "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x", - bss_conf->bssid, bss_conf->aid, - bss_conf->beacon_int, - bss_conf->basic_rates, sta_rate_set); - - wlvif->beacon_int = bss_conf->beacon_int; - rates = bss_conf->basic_rates; - wlvif->basic_rate_set = - wl1271_tx_enabled_rates_get(wl, rates, - wlvif->band); - wlvif->basic_rate = - wl1271_tx_min_rate_get(wl, - wlvif->basic_rate_set); - - if (sta_rate_set) - wlvif->rate_set = - wl1271_tx_enabled_rates_get(wl, - sta_rate_set, - wlvif->band); - - /* we only support sched_scan while not connected */ - if (wl->sched_vif == wlvif) - wl->ops->sched_scan_stop(wl, wlvif); - - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_build_null_data(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl1271_build_qos_null_data(wl, wl12xx_wlvif_to_vif(wlvif)); - if (ret < 0) - return ret; - - wlcore_set_ssid(wl, wlvif); - - set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); - - return 0; -} - -static int wlcore_clear_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - /* revert back to minimum rates for the current band */ - wl1271_set_band_rate(wl, wlvif); - wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - return ret; - - if (wlvif->bss_type == BSS_TYPE_STA_BSS && - test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) { - ret = wl12xx_cmd_role_stop_sta(wl, wlvif); - if (ret < 0) - return ret; - } - - clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); - return 0; -} /* STA/IBSS mode changes */ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, struct ieee80211_vif *vif, @@ -4034,7 +3809,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, u32 changed) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - bool do_join = false; + bool do_join = false, set_assoc = false; bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); bool ibss_joined = false; u32 sta_rate_set = 0; @@ -4055,8 +3830,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); ibss_joined = true; } else { - wlcore_unset_assoc(wl, wlvif); - wl12xx_cmd_role_stop_sta(wl, wlvif); + if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, + &wlvif->flags)) + wl1271_unjoin(wl, wlvif); } } @@ -4074,7 +3850,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, do_join = true; } - if (changed & BSS_CHANGED_CQM) { + if (changed & BSS_CHANGED_IDLE && !is_ibss) { + ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); + if (ret < 0) + wl1271_warning("idle mode change failed %d", ret); + } + + if ((changed & BSS_CHANGED_CQM)) { bool enable = false; if (bss_conf->cqm_rssi_thold) enable = true; @@ -4086,39 +3868,150 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, wlvif->rssi_thold = bss_conf->cqm_rssi_thold; } - if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT | - BSS_CHANGED_ASSOC)) { - rcu_read_lock(); - sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { - u8 *rx_mask = sta->ht_cap.mcs.rx_mask; - - /* save the supp_rates of the ap */ - sta_rate_set = sta->supp_rates[wlvif->band]; - if (sta->ht_cap.ht_supported) - sta_rate_set |= - (rx_mask[0] << HW_HT_RATES_OFFSET) | - (rx_mask[1] << HW_MIMO_RATES_OFFSET); - sta_ht_cap = sta->ht_cap; - sta_exists = true; + if (changed & BSS_CHANGED_BSSID) + if (!is_zero_ether_addr(bss_conf->bssid)) { + ret = wl12xx_cmd_build_null_data(wl, wlvif); + if (ret < 0) + goto out; + + ret = wl1271_build_qos_null_data(wl, vif); + if (ret < 0) + goto out; } + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (!sta) + goto sta_not_found; + + /* save the supp_rates of the ap */ + sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; + if (sta->ht_cap.ht_supported) + sta_rate_set |= + (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) | + (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET); + sta_ht_cap = sta->ht_cap; + sta_exists = true; + +sta_not_found: rcu_read_unlock(); } - if (changed & BSS_CHANGED_BSSID) { - if (!is_zero_ether_addr(bss_conf->bssid)) { - ret = wlcore_set_bssid(wl, wlvif, bss_conf, - sta_rate_set); + if ((changed & BSS_CHANGED_ASSOC)) { + if (bss_conf->assoc) { + u32 rates; + int ieoffset; + wlvif->aid = bss_conf->aid; + wlvif->channel_type = + cfg80211_get_chandef_type(&bss_conf->chandef); + wlvif->beacon_int = bss_conf->beacon_int; + do_join = true; + set_assoc = true; + + /* + * use basic rates from AP, and determine lowest rate + * to use with control frames. + */ + rates = bss_conf->basic_rates; + wlvif->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wlvif->band); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + if (sta_rate_set) + wlvif->rate_set = + wl1271_tx_enabled_rates_get(wl, + sta_rate_set, + wlvif->band); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; - /* Need to update the BSSID (for filtering etc) */ - do_join = true; + /* + * with wl1271, we don't need to update the + * beacon_int and dtim_period, because the firmware + * updates it by itself when the first beacon is + * received after a join. + */ + ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); + if (ret < 0) + goto out; + + /* + * Get a template for hardware connection maintenance + */ + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, + wlvif, + NULL); + ieoffset = offsetof(struct ieee80211_mgmt, + u.probe_req.variable); + wl1271_ssid_set(vif, wlvif->probereq, ieoffset); + + /* enable the connection monitoring feature */ + ret = wl1271_acx_conn_monit_params(wl, wlvif, true); + if (ret < 0) + goto out; } else { - ret = wlcore_clear_bssid(wl, wlvif); + /* use defaults when not associated */ + bool was_assoc = + !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags); + bool was_ifup = + !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT, + &wlvif->flags); + wlvif->aid = 0; + + /* free probe-request template */ + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = NULL; + + /* revert back to minimum rates for the current band */ + wl1271_set_band_rate(wl, wlvif); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; + + /* disable connection monitor features */ + ret = wl1271_acx_conn_monit_params(wl, wlvif, false); + + /* Disable the keep-alive feature */ + ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); + if (ret < 0) + goto out; + + /* restore the bssid filter and go to dummy bssid */ + if (was_assoc) { + /* + * we might have to disable roc, if there was + * no IF_OPER_UP notification. + */ + if (!was_ifup) { + ret = wl12xx_croc(wl, wlvif->role_id); + if (ret < 0) + goto out; + } + /* + * (we also need to disable roc in case of + * roaming on the same channel. until we will + * have a better flow...) + */ + if (test_bit(wlvif->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, + wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + wl1271_unjoin(wl, wlvif); + if (!bss_conf->idle) + wl12xx_start_dev(wl, wlvif); + } } } @@ -4148,87 +4041,71 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, goto out; if (do_join) { - ret = wlcore_join(wl, wlvif); + ret = wl1271_join(wl, wlvif, set_assoc); if (ret < 0) { wl1271_warning("cmd join failed %d", ret); goto out; } - } - if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - ret = wlcore_set_assoc(wl, wlvif, bss_conf, - sta_rate_set); + /* ROC until connected (after EAPOL exchange) */ + if (!is_ibss) { + ret = wl12xx_roc(wl, wlvif, wlvif->role_id); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) wl12xx_set_authorized(wl, wlvif); - } else { - wlcore_unset_assoc(wl, wlvif); } - } - - if (changed & BSS_CHANGED_PS) { - if ((bss_conf->ps) && - test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && - !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { - int ps_mode; - char *ps_mode_str; - - if (wl->conf.conn.forced_ps) { - ps_mode = STATION_POWER_SAVE_MODE; - ps_mode_str = "forced"; - } else { - ps_mode = STATION_AUTO_PS_MODE; - ps_mode_str = "auto"; - } - - wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); - - ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); - if (ret < 0) - wl1271_warning("enter %s ps failed %d", - ps_mode_str, ret); - } else if (!bss_conf->ps && - test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { - wl1271_debug(DEBUG_PSM, "auto ps disabled"); - - ret = wl1271_ps_set_mode(wl, wlvif, - STATION_ACTIVE_MODE); + /* + * stop device role if started (we might already be in + * STA/IBSS role). + */ + if (wl12xx_dev_role_started(wlvif)) { + ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) - wl1271_warning("exit auto ps failed %d", ret); + goto out; } } /* Handle new association with HT. Do this after join. */ - if (sta_exists && - (changed & BSS_CHANGED_HT)) { - bool enabled = - bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT; - - ret = wlcore_hw_set_peer_cap(wl, - &sta_ht_cap, - enabled, - wlvif->rate_set, - wlvif->sta.hlid); - if (ret < 0) { - wl1271_warning("Set ht cap failed %d", ret); - goto out; - + if (sta_exists) { + if ((changed & BSS_CHANGED_HT) && + (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + true, + wlvif->sta.hlid); + if (ret < 0) { + wl1271_warning("Set ht cap true failed %d", + ret); + goto out; + } } - - if (enabled) { - ret = wl1271_acx_set_ht_information(wl, wlvif, - bss_conf->ht_operation_mode); + /* handle new association without HT and disassociation */ + else if (changed & BSS_CHANGED_ASSOC) { + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + false, + wlvif->sta.hlid); if (ret < 0) { - wl1271_warning("Set ht information failed %d", + wl1271_warning("Set ht cap false failed %d", ret); goto out; } } } + /* Handle HT information change. Done after join. */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { + ret = wl1271_acx_set_ht_information(wl, wlvif, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out; + } + } + /* Handle arp filtering. Done after join. */ if ((changed & BSS_CHANGED_ARP_FILTER) || (!is_ibss && (changed & BSS_CHANGED_QOS))) { @@ -4277,15 +4154,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret; - wl1271_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x", - wlvif->role_id, (int)changed); + wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", + (int)changed); /* * make sure to cancel pending disconnections if our association * state changed */ if (!is_ap && (changed & BSS_CHANGED_ASSOC)) - cancel_delayed_work_sync(&wlvif->connection_loss_work); + cancel_delayed_work_sync(&wl->connection_loss_work); if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) @@ -4314,76 +4191,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int wlcore_op_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) -{ - wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)", - ieee80211_frequency_to_channel(ctx->def.chan->center_freq), - cfg80211_get_chandef_type(&ctx->def)); - return 0; -} - -static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) -{ - wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)", - ieee80211_frequency_to_channel(ctx->def.chan->center_freq), - cfg80211_get_chandef_type(&ctx->def)); -} - -static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx, - u32 changed) -{ - wl1271_debug(DEBUG_MAC80211, - "mac80211 change chanctx %d (type %d) changed 0x%x", - ieee80211_frequency_to_channel(ctx->def.chan->center_freq), - cfg80211_get_chandef_type(&ctx->def), changed); -} - -static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int channel = ieee80211_frequency_to_channel( - ctx->def.chan->center_freq); - - wl1271_debug(DEBUG_MAC80211, - "mac80211 assign chanctx (role %d) %d (type %d)", - wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def)); - - mutex_lock(&wl->mutex); - - wlvif->band = ctx->def.chan->band; - wlvif->channel = channel; - wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def); - - /* update default rates according to the band */ - wl1271_set_band_rate(wl, wlvif); - - mutex_unlock(&wl->mutex); - - return 0; -} - -static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - - wl1271_debug(DEBUG_MAC80211, - "mac80211 unassign chanctx (role %d) %d (type %d)", - wlvif->role_id, - ieee80211_frequency_to_channel(ctx->def.chan->center_freq), - cfg80211_get_chandef_type(&ctx->def)); - - wl1271_tx_flush(wl); -} - static int wl1271_op_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) @@ -4511,6 +4318,8 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) return; clear_bit(hlid, wlvif->ap.sta_hlid_map); + memset(wl->links[hlid].addr, 0, ETH_ALEN); + wl->links[hlid].ba_bitmap = 0; __clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); wl12xx_free_link(wl, wlvif, &hlid); @@ -4570,45 +4379,6 @@ static int wl12xx_sta_remove(struct wl1271 *wl, return ret; } -static void wlcore_roc_if_possible(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - if (find_first_bit(wl->roc_map, - WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) - return; - - if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) - return; - - wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel); -} - -static void wlcore_update_inconn_sta(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct wl1271_station *wl_sta, - bool in_connection) -{ - if (in_connection) { - if (WARN_ON(wl_sta->in_connection)) - return; - wl_sta->in_connection = true; - if (!wlvif->inconn_count++) - wlcore_roc_if_possible(wl, wlvif); - } else { - if (!wl_sta->in_connection) - return; - - wl_sta->in_connection = false; - wlvif->inconn_count--; - if (WARN_ON(wlvif->inconn_count < 0)) - return; - - if (!wlvif->inconn_count) - if (test_bit(wlvif->role_id, wl->roc_map)) - wl12xx_croc(wl, wlvif->role_id); - } -} - static int wl12xx_update_sta_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_sta *sta, @@ -4627,13 +4397,8 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, /* Add station (AP mode) */ if (is_ap && old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE) { - ret = wl12xx_sta_add(wl, wlvif, sta); - if (ret) - return ret; - - wlcore_update_inconn_sta(wl, wlvif, wl_sta, true); - } + new_state == IEEE80211_STA_NONE) + return wl12xx_sta_add(wl, wlvif, sta); /* Remove station (AP mode) */ if (is_ap && @@ -4641,59 +4406,35 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, new_state == IEEE80211_STA_NOTEXIST) { /* must not fail */ wl12xx_sta_remove(wl, wlvif, sta); - - wlcore_update_inconn_sta(wl, wlvif, wl_sta, false); + return 0; } /* Authorize station (AP mode) */ if (is_ap && new_state == IEEE80211_STA_AUTHORIZED) { - ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid); + ret = wl12xx_cmd_set_peer_state(wl, hlid); if (ret < 0) return ret; ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid); - if (ret) - return ret; - - wlcore_update_inconn_sta(wl, wlvif, wl_sta, false); + return ret; } /* Authorize station */ if (is_sta && new_state == IEEE80211_STA_AUTHORIZED) { set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); - ret = wl12xx_set_authorized(wl, wlvif); - if (ret) - return ret; + return wl12xx_set_authorized(wl, wlvif); } if (is_sta && old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); - clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags); - } - - /* clear ROCs on failure or authorization */ - if (is_sta && - (new_state == IEEE80211_STA_AUTHORIZED || - new_state == IEEE80211_STA_NOTEXIST)) { - if (test_bit(wlvif->role_id, wl->roc_map)) - wl12xx_croc(wl, wlvif->role_id); + return 0; } - if (is_sta && - old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE) { - if (find_first_bit(wl->roc_map, - WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) { - WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID); - wl12xx_roc(wl, wlvif, wlvif->role_id, - wlvif->band, wlvif->channel); - } - } return 0; } @@ -4758,18 +4499,18 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, if (wlvif->bss_type == BSS_TYPE_STA_BSS) { hlid = wlvif->sta.hlid; + ba_bitmap = &wlvif->sta.ba_rx_bitmap; } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { struct wl1271_station *wl_sta; wl_sta = (struct wl1271_station *)sta->drv_priv; hlid = wl_sta->hlid; + ba_bitmap = &wl->links[hlid].ba_bitmap; } else { ret = -EINVAL; goto out; } - ba_bitmap = &wl->links[hlid].ba_bitmap; - ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -4923,23 +4664,12 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, /* TODO: change mac80211 to pass vif as param */ wl12xx_for_each_wlvif_sta(wl, wlvif) { - unsigned long delay_usec; + ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch); - ret = wl->ops->channel_switch(wl, wlvif, ch_switch); - if (ret) - goto out_sleep; - - set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); - - /* indicate failure 5 seconds after channel switch time */ - delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) * - ch_switch->count; - ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work, - usecs_to_jiffies(delay_usec) + - msecs_to_jiffies(5000)); + if (!ret) + set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); } -out_sleep: wl1271_ps_elp_sleep(wl); out: @@ -4953,144 +4683,6 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) wl1271_tx_flush(wl); } -static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel *chan, - int duration) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl1271 *wl = hw->priv; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(chan->center_freq); - - wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)", - channel, wlvif->role_id); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state != WLCORE_STATE_ON)) - goto out; - - /* return EBUSY if we can't ROC right now */ - if (WARN_ON(wl->roc_vif || - find_first_bit(wl->roc_map, - WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) { - ret = -EBUSY; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_start_dev(wl, wlvif, chan->band, channel); - if (ret < 0) - goto out_sleep; - - wl->roc_vif = vif; - ieee80211_queue_delayed_work(hw, &wl->roc_complete_work, - msecs_to_jiffies(duration)); -out_sleep: - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); - return ret; -} - -static int __wlcore_roc_completed(struct wl1271 *wl) -{ - struct wl12xx_vif *wlvif; - int ret; - - /* already completed */ - if (unlikely(!wl->roc_vif)) - return 0; - - wlvif = wl12xx_vif_to_data(wl->roc_vif); - - if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) - return -EBUSY; - - ret = wl12xx_stop_dev(wl, wlvif); - if (ret < 0) - return ret; - - wl->roc_vif = NULL; - - return 0; -} - -static int wlcore_roc_completed(struct wl1271 *wl) -{ - int ret; - - wl1271_debug(DEBUG_MAC80211, "roc complete"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state != WLCORE_STATE_ON)) { - ret = -EBUSY; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = __wlcore_roc_completed(wl); - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wlcore_roc_complete_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - int ret; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, roc_complete_work); - - ret = wlcore_roc_completed(wl); - if (!ret) - ieee80211_remain_on_channel_expired(wl->hw); -} - -static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw) -{ - struct wl1271 *wl = hw->priv; - - wl1271_debug(DEBUG_MAC80211, "mac80211 croc"); - - /* TODO: per-vif */ - wl1271_tx_flush(wl); - - /* - * we can't just flush_work here, because it might deadlock - * (as we might get called from the same workqueue) - */ - cancel_delayed_work_sync(&wl->roc_complete_work); - wlcore_roc_completed(wl); - - return 0; -} - -static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - u32 changed) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl1271 *wl = hw->priv; - - wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); -} - static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -5154,20 +4746,20 @@ static struct ieee80211_rate wl1271_rates[] = { /* can't be const, mac80211 writes to this */ static struct ieee80211_channel wl1271_channels[] = { - { .hw_value = 1, .center_freq = 2412, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 2, .center_freq = 2417, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 3, .center_freq = 2422, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 4, .center_freq = 2427, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 5, .center_freq = 2432, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 6, .center_freq = 2437, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 7, .center_freq = 2442, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 8, .center_freq = 2447, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 9, .center_freq = 2452, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 10, .center_freq = 2457, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR }, + { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, + { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, + { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, + { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, + { .hw_value = 14, .center_freq = 2484, .max_power = 25 }, }; /* can't be const, mac80211 writes to this */ @@ -5208,40 +4800,40 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { /* 5 GHz band channels for WL1273 */ static struct ieee80211_channel wl1271_channels_5ghz[] = { - { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 36, .center_freq = 5180, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 38, .center_freq = 5190, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 40, .center_freq = 5200, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 42, .center_freq = 5210, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 44, .center_freq = 5220, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 46, .center_freq = 5230, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 48, .center_freq = 5240, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 52, .center_freq = 5260, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 56, .center_freq = 5280, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 60, .center_freq = 5300, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 64, .center_freq = 5320, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 100, .center_freq = 5500, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 104, .center_freq = 5520, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 108, .center_freq = 5540, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 112, .center_freq = 5560, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 116, .center_freq = 5580, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 120, .center_freq = 5600, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 124, .center_freq = 5620, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 128, .center_freq = 5640, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 132, .center_freq = 5660, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 136, .center_freq = 5680, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 140, .center_freq = 5700, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 149, .center_freq = 5745, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 153, .center_freq = 5765, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 157, .center_freq = 5785, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 161, .center_freq = 5805, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 165, .center_freq = 5825, .max_power = WLCORE_MAX_TXPWR }, + { .hw_value = 7, .center_freq = 5035, .max_power = 25 }, + { .hw_value = 8, .center_freq = 5040, .max_power = 25 }, + { .hw_value = 9, .center_freq = 5045, .max_power = 25 }, + { .hw_value = 11, .center_freq = 5055, .max_power = 25 }, + { .hw_value = 12, .center_freq = 5060, .max_power = 25 }, + { .hw_value = 16, .center_freq = 5080, .max_power = 25 }, + { .hw_value = 34, .center_freq = 5170, .max_power = 25 }, + { .hw_value = 36, .center_freq = 5180, .max_power = 25 }, + { .hw_value = 38, .center_freq = 5190, .max_power = 25 }, + { .hw_value = 40, .center_freq = 5200, .max_power = 25 }, + { .hw_value = 42, .center_freq = 5210, .max_power = 25 }, + { .hw_value = 44, .center_freq = 5220, .max_power = 25 }, + { .hw_value = 46, .center_freq = 5230, .max_power = 25 }, + { .hw_value = 48, .center_freq = 5240, .max_power = 25 }, + { .hw_value = 52, .center_freq = 5260, .max_power = 25 }, + { .hw_value = 56, .center_freq = 5280, .max_power = 25 }, + { .hw_value = 60, .center_freq = 5300, .max_power = 25 }, + { .hw_value = 64, .center_freq = 5320, .max_power = 25 }, + { .hw_value = 100, .center_freq = 5500, .max_power = 25 }, + { .hw_value = 104, .center_freq = 5520, .max_power = 25 }, + { .hw_value = 108, .center_freq = 5540, .max_power = 25 }, + { .hw_value = 112, .center_freq = 5560, .max_power = 25 }, + { .hw_value = 116, .center_freq = 5580, .max_power = 25 }, + { .hw_value = 120, .center_freq = 5600, .max_power = 25 }, + { .hw_value = 124, .center_freq = 5620, .max_power = 25 }, + { .hw_value = 128, .center_freq = 5640, .max_power = 25 }, + { .hw_value = 132, .center_freq = 5660, .max_power = 25 }, + { .hw_value = 136, .center_freq = 5680, .max_power = 25 }, + { .hw_value = 140, .center_freq = 5700, .max_power = 25 }, + { .hw_value = 149, .center_freq = 5745, .max_power = 25 }, + { .hw_value = 153, .center_freq = 5765, .max_power = 25 }, + { .hw_value = 157, .center_freq = 5785, .max_power = 25 }, + { .hw_value = 161, .center_freq = 5805, .max_power = 25 }, + { .hw_value = 165, .center_freq = 5825, .max_power = 25 }, }; static struct ieee80211_supported_band wl1271_band_5ghz = { @@ -5282,14 +4874,6 @@ static const struct ieee80211_ops wl1271_ops = { .set_bitrate_mask = wl12xx_set_bitrate_mask, .channel_switch = wl12xx_op_channel_switch, .flush = wlcore_op_flush, - .remain_on_channel = wlcore_op_remain_on_channel, - .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel, - .add_chanctx = wlcore_op_add_chanctx, - .remove_chanctx = wlcore_op_remove_chanctx, - .change_chanctx = wlcore_op_change_chanctx, - .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, - .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, - .sta_rc_update = wlcore_op_sta_rc_update, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -5459,6 +5043,34 @@ static struct bin_attribute fwlog_attr = { .read = wl1271_sysfs_read_fwlog, }; +static void wl1271_connection_loss_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, connection_loss_work); + + wl1271_info("Connection loss work."); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + /* Call mac80211 connection loss */ + wl12xx_for_each_wlvif_sta(wl, wlvif) { + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; + vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_connection_loss(vif); + } +out: + mutex_unlock(&wl->mutex); +} + static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) { int i; @@ -5504,7 +5116,7 @@ static int wl12xx_get_hw_info(struct wl1271 *wl) ret = wl12xx_set_power_on(wl); if (ret < 0) - return ret; + goto out; ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id); if (ret < 0) @@ -5594,9 +5206,10 @@ static const struct ieee80211_iface_limit wlcore_iface_limits[] = { }, }; -static struct ieee80211_iface_combination +static const struct ieee80211_iface_combination wlcore_iface_combinations[] = { { + .num_different_channels = 1, .max_interfaces = 3, .limits = wlcore_iface_limits, .n_limits = ARRAY_SIZE(wlcore_iface_limits), @@ -5605,7 +5218,6 @@ wlcore_iface_combinations[] = { static int wl1271_init_ieee80211(struct wl1271 *wl) { - int i; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, @@ -5636,8 +5248,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_AP_LINK_PS | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | - IEEE80211_HW_SCAN_WHILE_IDLE | - IEEE80211_HW_QUEUE_CONTROL; + IEEE80211_HW_SCAN_WHILE_IDLE; wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -5659,8 +5270,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); - wl->hw->wiphy->max_remain_on_channel_duration = 5000; - wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; @@ -5668,22 +5277,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + ARRAY_SIZE(wl1271_channels_5ghz) > WL1271_MAX_CHANNELS); - /* - * clear channel flags from the previous usage - * and restore max_power & max_antenna_gain values. - */ - for (i = 0; i < ARRAY_SIZE(wl1271_channels); i++) { - wl1271_band_2ghz.channels[i].flags = 0; - wl1271_band_2ghz.channels[i].max_power = WLCORE_MAX_TXPWR; - wl1271_band_2ghz.channels[i].max_antenna_gain = 0; - } - - for (i = 0; i < ARRAY_SIZE(wl1271_channels_5ghz); i++) { - wl1271_band_5ghz.channels[i].flags = 0; - wl1271_band_5ghz.channels[i].max_power = WLCORE_MAX_TXPWR; - wl1271_band_5ghz.channels[i].max_antenna_gain = 0; - } - /* * We keep local copies of the band structs because we need to * modify them on a per-device basis. @@ -5704,14 +5297,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl->bands[IEEE80211_BAND_5GHZ]; - /* - * allow 4 queues per mac address we support + - * 1 cab queue per mac + one global offchannel Tx queue - */ - wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1; - - /* the last queue is the offchannel queue */ - wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1; + wl->hw->queues = 4; wl->hw->max_rates = 1; wl->hw->wiphy->reg_notifier = wl1271_reg_notify; @@ -5724,7 +5310,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; /* allowed interface combinations */ - wlcore_iface_combinations[0].num_different_channels = wl->num_channels; wl->hw->wiphy->iface_combinations = wlcore_iface_combinations; wl->hw->wiphy->n_iface_combinations = ARRAY_SIZE(wlcore_iface_combinations); @@ -5741,8 +5326,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) #define WL1271_DEFAULT_CHANNEL 0 -struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, - u32 mbox_size) +struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size) { struct ieee80211_hw *hw; struct wl1271 *wl; @@ -5784,8 +5368,9 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->recovery_work, wl1271_recovery_work); INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); - INIT_DELAYED_WORK(&wl->roc_complete_work, wlcore_roc_complete_work); INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); + INIT_DELAYED_WORK(&wl->connection_loss_work, + wl1271_connection_loss_work); wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); if (!wl->freezable_wq) { @@ -5801,15 +5386,14 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, wl->flags = 0; wl->sg_enabled = true; wl->sleep_auth = WL1271_PSM_ILLEGAL; - wl->recovery_count = 0; wl->hw_pg_ver = -1; wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; wl->platform_quirks = 0; + wl->sched_scanning = false; wl->system_hlid = WL12XX_SYSTEM_HLID; wl->active_sta_count = 0; - wl->active_link_count = 0; wl->fwlog_size = 0; init_waitqueue_head(&wl->fwlog_waitq); @@ -5849,24 +5433,14 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, goto err_dummy_packet; } - wl->mbox_size = mbox_size; - wl->mbox = kmalloc(wl->mbox_size, GFP_KERNEL | GFP_DMA); + wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA); if (!wl->mbox) { ret = -ENOMEM; goto err_fwlog; } - wl->buffer_32 = kmalloc(sizeof(*wl->buffer_32), GFP_KERNEL); - if (!wl->buffer_32) { - ret = -ENOMEM; - goto err_mbox; - } - return hw; -err_mbox: - kfree(wl->mbox); - err_fwlog: free_page((unsigned long)wl->fwlog); @@ -5905,8 +5479,6 @@ int wlcore_free_hw(struct wl1271 *wl) device_remove_file(wl->dev, &dev_attr_hw_pg_ver); device_remove_file(wl->dev, &dev_attr_bt_coex_state); - kfree(wl->buffer_32); - kfree(wl->mbox); free_page((unsigned long)wl->fwlog); dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size)); @@ -5963,8 +5535,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) { struct wl1271 *wl = context; struct platform_device *pdev = wl->pdev; - struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data; - struct wl12xx_platform_data *pdata = pdev_data->pdata; + struct wl12xx_platform_data *pdata = pdev->dev.platform_data; unsigned long irqflags; int ret; @@ -5993,7 +5564,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) wl->irq = platform_get_irq(pdev, 0); wl->platform_quirks = pdata->platform_quirks; - wl->if_ops = pdev_data->if_ops; + wl->set_power = pdata->set_power; + wl->if_ops = pdata->ops; if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) irqflags = IRQF_TRIGGER_RISING; @@ -6139,10 +5711,10 @@ module_param_named(fwlog, fwlog_param, charp, 0); MODULE_PARM_DESC(fwlog, "FW logger options: continuous, ondemand, dbgpins or disable"); -module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR); +module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); -module_param(no_recovery, int, S_IRUSR | S_IWUSR); +module_param(no_recovery, bool, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/wireless/ti/wlcore/ps.c b/trunk/drivers/net/wireless/ti/wlcore/ps.c index 9b7b6e2e4fbc..4d1414a673fb 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/ps.c +++ b/trunk/drivers/net/wireless/ti/wlcore/ps.c @@ -151,6 +151,9 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) wl12xx_queue_recovery_work(wl); ret = -ETIMEDOUT; goto err; + } else if (ret < 0) { + wl1271_error("ELP wakeup completion error."); + goto err; } } @@ -239,12 +242,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) struct ieee80211_tx_info *info; unsigned long flags; int filtered[NUM_TX_QUEUES]; - struct wl1271_link *lnk = &wl->links[hlid]; /* filter all frames currently in the low level queues for this hlid */ for (i = 0; i < NUM_TX_QUEUES; i++) { filtered[i] = 0; - while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { + while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { filtered[i]++; if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) @@ -258,11 +260,8 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) } spin_lock_irqsave(&wl->wl_lock, flags); - for (i = 0; i < NUM_TX_QUEUES; i++) { + for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_queue_count[i] -= filtered[i]; - if (lnk->wlvif) - lnk->wlvif->tx_queue_count[i] -= filtered[i]; - } spin_unlock_irqrestore(&wl->wl_lock, flags); wl1271_handle_tx_low_watermark(wl); diff --git a/trunk/drivers/net/wireless/ti/wlcore/rx.c b/trunk/drivers/net/wireless/ti/wlcore/rx.c index 6791a1a6afba..9ee0ec6fd1db 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/rx.c +++ b/trunk/drivers/net/wireless/ti/wlcore/rx.c @@ -92,16 +92,11 @@ static void wl1271_rx_status(struct wl1271 *wl, status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; - if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) { + if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { status->flag |= RX_FLAG_MMIC_ERROR; - wl1271_warning("Michael MIC error. Desc: 0x%x", - desc_err_code); + wl1271_warning("Michael MIC error"); } } - - if (beacon) - wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel, - status->band); } static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, @@ -113,7 +108,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, u8 *buf; u8 beacon = 0; u8 is_data = 0; - u8 reserved = 0, offset_to_data = 0; + u8 reserved = 0; u16 seq_num; u32 pkt_data_len; @@ -133,8 +128,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, if (rx_align == WLCORE_RX_BUF_UNALIGNED) reserved = RX_BUF_ALIGN; - else if (rx_align == WLCORE_RX_BUF_PADDED) - offset_to_data = RX_BUF_ALIGN; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; @@ -146,15 +139,19 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, return 0; } + switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* discard corrupted packets */ - if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) { - hdr = (void *)(data + sizeof(*desc) + offset_to_data); - wl1271_warning("corrupted packet in RX: status: 0x%x len: %d", - desc->status & WL1271_RX_DESC_STATUS_MASK, - pkt_data_len); - wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc), - min(pkt_data_len, - ieee80211_hdrlen(hdr->frame_control))); + case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: + case WL1271_RX_DESC_DECRYPT_FAIL: + wl1271_warning("corrupted packet in RX with status: 0x%x", + desc->status & WL1271_RX_DESC_STATUS_MASK); + return -EINVAL; + case WL1271_RX_DESC_SUCCESS: + case WL1271_RX_DESC_MIC_FAIL: + break; + default: + wl1271_error("invalid RX descriptor status: 0x%x", + desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; } diff --git a/trunk/drivers/net/wireless/ti/wlcore/rx.h b/trunk/drivers/net/wireless/ti/wlcore/rx.h index 3363f60fb7da..71eba1899915 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/rx.h +++ b/trunk/drivers/net/wireless/ti/wlcore/rx.h @@ -84,11 +84,12 @@ * Bits 3-5 - process_id tag (AP mode FW) * Bits 6-7 - reserved */ -#define WL1271_RX_DESC_STATUS_MASK 0x07 +#define WL1271_RX_DESC_STATUS_MASK 0x03 #define WL1271_RX_DESC_SUCCESS 0x00 #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 #define WL1271_RX_DESC_MIC_FAIL 0x02 +#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 #define RX_MEM_BLOCK_MASK 0xFF #define RX_BUF_SIZE_MASK 0xFFF00 diff --git a/trunk/drivers/net/wireless/ti/wlcore/scan.c b/trunk/drivers/net/wireless/ti/wlcore/scan.c index f407101e525b..d00501493dfe 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/scan.c +++ b/trunk/drivers/net/wireless/ti/wlcore/scan.c @@ -35,6 +35,7 @@ void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; @@ -51,7 +52,8 @@ void wl1271_scan_complete_work(struct work_struct *work) if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; - wlvif = wl->scan_wlvif; + vif = wl->scan_vif; + wlvif = wl12xx_vif_to_data(vif); /* * Rearm the tx watchdog just before idling scan. This @@ -62,7 +64,7 @@ void wl1271_scan_complete_work(struct work_struct *work) wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; - wl->scan_wlvif = NULL; + wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) @@ -80,8 +82,6 @@ void wl1271_scan_complete_work(struct work_struct *work) wl12xx_queue_recovery_work(wl); } - wlcore_cmd_regdomain_config_locked(wl); - ieee80211_scan_completed(wl->hw, false); out: @@ -89,99 +89,371 @@ void wl1271_scan_complete_work(struct work_struct *work) } -static void wlcore_started_vifs_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) + +static int wl1271_get_scan_channels(struct wl1271 *wl, + struct cfg80211_scan_request *req, + struct basic_scan_channel_params *channels, + enum ieee80211_band band, bool passive) +{ + struct conf_scan_settings *c = &wl->conf.scan; + int i, j; + u32 flags; + + for (i = 0, j = 0; + i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; + i++) { + flags = req->channels[i]->flags; + + if (!test_bit(i, wl->scan.scanned_ch) && + !(flags & IEEE80211_CHAN_DISABLED) && + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { + wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", + req->channels[i]->band, + req->channels[i]->center_freq); + wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", + req->channels[i]->hw_value, + req->channels[i]->flags); + wl1271_debug(DEBUG_SCAN, + "max_antenna_gain %d, max_power %d", + req->channels[i]->max_antenna_gain, + req->channels[i]->max_power); + wl1271_debug(DEBUG_SCAN, "beacon_found %d", + req->channels[i]->beacon_found); + + if (!passive) { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_active); + } else { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_passive); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_passive); + } + channels[j].early_termination = 0; + channels[j].tx_power_att = req->channels[i]->max_power; + channels[j].channel = req->channels[i]->hw_value; + + memset(&channels[j].bssid_lsb, 0xff, 4); + memset(&channels[j].bssid_msb, 0xff, 2); + + /* Mark the channels we already used */ + set_bit(i, wl->scan.scanned_ch); + + j++; + } + } + + return j; +} + +#define WL1271_NOTHING_TO_SCAN 1 + +static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, + enum ieee80211_band band, + bool passive, u32 basic_rate) { - int *count = (int *)data; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct wl1271_cmd_scan *cmd; + struct wl1271_cmd_trigger_scan_to *trigger; + int ret; + u16 scan_options = 0; + + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!cmd || !trigger) { + ret = -ENOMEM; + goto out; + } + + if (wl->conf.scan.split_scan_timeout) + scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; + + if (passive) + scan_options |= WL1271_SCAN_OPT_PASSIVE; + + cmd->params.role_id = wlvif->role_id; + + if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { + ret = -EINVAL; + goto out; + } + + cmd->params.scan_options = cpu_to_le16(scan_options); + + cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, + cmd->channels, + band, passive); + if (cmd->params.n_ch == 0) { + ret = WL1271_NOTHING_TO_SCAN; + goto out; + } + + cmd->params.tx_rate = cpu_to_le32(basic_rate); + cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; + cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; + cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + + if (band == IEEE80211_BAND_2GHZ) + cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; + else + cmd->params.band = WL1271_SCAN_BAND_5_GHZ; + + if (wl->scan.ssid_len && wl->scan.ssid) { + cmd->params.ssid_len = wl->scan.ssid_len; + memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); + } + + memcpy(cmd->addr, vif->addr, ETH_ALEN); + + ret = wl12xx_cmd_build_probe_req(wl, wlvif, + cmd->params.role_id, band, + wl->scan.ssid, wl->scan.ssid_len, + wl->scan.req->ie, + wl->scan.req->ie_len, false); + if (ret < 0) { + wl1271_error("PROBE request template failed"); + goto out; + } + + trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); + ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger), 0); + if (ret < 0) { + wl1271_error("trigger scan to failed for hw scan"); + goto out; + } + + wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); - if (!vif->bss_conf.idle) - (*count)++; + ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("SCAN failed"); + goto out; + } + +out: + kfree(cmd); + kfree(trigger); + return ret; } -static int wlcore_count_started_vifs(struct wl1271 *wl) +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) { - int count = 0; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret = 0; + enum ieee80211_band band; + u32 rate, mask; + + switch (wl->scan.state) { + case WL1271_SCAN_STATE_IDLE: + break; + + case WL1271_SCAN_STATE_2GHZ_ACTIVE: + band = IEEE80211_BAND_2GHZ; + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, false, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_2GHZ_PASSIVE: + band = IEEE80211_BAND_2GHZ; + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, true, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + if (wl->enable_11a) + wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; + else + wl->scan.state = WL1271_SCAN_STATE_DONE; + wl1271_scan_stm(wl, vif); + } + + break; - ieee80211_iterate_active_interfaces_atomic(wl->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - wlcore_started_vifs_iter, &count); - return count; + case WL1271_SCAN_STATE_5GHZ_ACTIVE: + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, false, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_5GHZ_PASSIVE: + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, true, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_DONE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_DONE: + wl->scan.failed = false; + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + break; + + default: + wl1271_error("invalid scan state"); + break; + } + + if (ret < 0) { + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + } +} + +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req) +{ + /* + * cfg80211 should guarantee that we don't get more channels + * than what we have registered. + */ + BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); + + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) + return -EBUSY; + + wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; + + if (ssid_len && ssid) { + wl->scan.ssid_len = ssid_len; + memcpy(wl->scan.ssid, ssid, ssid_len); + } else { + wl->scan.ssid_len = 0; + } + + wl->scan_vif = vif; + wl->scan.req = req; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + + /* we assume failure so that timeout scenarios are handled correctly */ + wl->scan.failed = true; + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); + + wl1271_scan_stm(wl, vif); + + return 0; +} + +int wl1271_scan_stop(struct wl1271 *wl) +{ + struct wl1271_cmd_header *cmd = NULL; + int ret = 0; + + if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) + return -EINVAL; + + wl1271_debug(DEBUG_CMD, "cmd scan stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd stop_scan failed"); + goto out; + } +out: + kfree(cmd); + return ret; } static int -wlcore_scan_get_channels(struct wl1271 *wl, - struct ieee80211_channel *req_channels[], - u32 n_channels, - u32 n_ssids, - struct conn_scan_ch_params *channels, - u32 band, bool radar, bool passive, - int start, int max_channels, - u8 *n_pactive_ch, - int scan_type) +wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct conn_scan_ch_params *channels, + u32 band, bool radar, bool passive, + int start, int max_channels, + u8 *n_pactive_ch) { + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, j; u32 flags; - bool force_passive = !n_ssids; - u32 min_dwell_time_active, max_dwell_time_active; + bool force_passive = !req->n_ssids; + u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe; u32 dwell_time_passive, dwell_time_dfs; - /* configure dwell times according to scan type */ - if (scan_type == SCAN_TYPE_SEARCH) { - struct conf_scan_settings *c = &wl->conf.scan; - bool active_vif_exists = !!wlcore_count_started_vifs(wl); - - min_dwell_time_active = active_vif_exists ? - c->min_dwell_time_active : - c->min_dwell_time_active_long; - max_dwell_time_active = active_vif_exists ? - c->max_dwell_time_active : - c->max_dwell_time_active_long; - dwell_time_passive = c->dwell_time_passive; - dwell_time_dfs = c->dwell_time_dfs; - } else { - struct conf_sched_scan_settings *c = &wl->conf.sched_scan; - u32 delta_per_probe; + if (band == IEEE80211_BAND_5GHZ) + delta_per_probe = c->dwell_time_delta_per_probe_5; + else + delta_per_probe = c->dwell_time_delta_per_probe; - if (band == IEEE80211_BAND_5GHZ) - delta_per_probe = c->dwell_time_delta_per_probe_5; - else - delta_per_probe = c->dwell_time_delta_per_probe; + min_dwell_time_active = c->base_dwell_time + + req->n_ssids * c->num_probe_reqs * delta_per_probe; - min_dwell_time_active = c->base_dwell_time + - n_ssids * c->num_probe_reqs * delta_per_probe; + max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta; - max_dwell_time_active = min_dwell_time_active + - c->max_dwell_time_delta; - dwell_time_passive = c->dwell_time_passive; - dwell_time_dfs = c->dwell_time_dfs; - } min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); - dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000); - dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000); + dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000); + dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000); for (i = 0, j = start; - i < n_channels && j < max_channels; + i < req->n_channels && j < max_channels; i++) { - flags = req_channels[i]->flags; + flags = req->channels[i]->flags; if (force_passive) flags |= IEEE80211_CHAN_PASSIVE_SCAN; - if ((req_channels[i]->band == band) && + if ((req->channels[i]->band == band) && !(flags & IEEE80211_CHAN_DISABLED) && (!!(flags & IEEE80211_CHAN_RADAR) == radar) && /* if radar is set, we ignore the passive flag */ (radar || !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", - req_channels[i]->band, - req_channels[i]->center_freq); + req->channels[i]->band, + req->channels[i]->center_freq); wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", - req_channels[i]->hw_value, - req_channels[i]->flags); + req->channels[i]->hw_value, + req->channels[i]->flags); wl1271_debug(DEBUG_SCAN, "max_power %d", - req_channels[i]->max_power); + req->channels[i]->max_power); wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d", min_dwell_time_active, max_dwell_time_active); @@ -201,11 +473,10 @@ wlcore_scan_get_channels(struct wl1271 *wl, channels[j].max_duration = cpu_to_le16(max_dwell_time_active); - channels[j].tx_power_att = req_channels[i]->max_power; - channels[j].channel = req_channels[i]->hw_value; + channels[j].tx_power_att = req->channels[i]->max_power; + channels[j].channel = req->channels[i]->hw_value; - if (n_pactive_ch && - (band == IEEE80211_BAND_2GHZ) && + if ((band == IEEE80211_BAND_2GHZ) && (channels[j].channel >= 12) && (channels[j].channel <= 14) && (flags & IEEE80211_CHAN_PASSIVE_SCAN) && @@ -229,80 +500,51 @@ wlcore_scan_get_channels(struct wl1271 *wl, return j - start; } -bool -wlcore_set_scan_chan_params(struct wl1271 *wl, - struct wlcore_scan_channels *cfg, - struct ieee80211_channel *channels[], - u32 n_channels, - u32 n_ssids, - int scan_type) +static bool +wl1271_scan_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct wl1271_cmd_sched_scan_config *cfg) { u8 n_pactive_ch = 0; cfg->passive[0] = - wlcore_scan_get_channels(wl, - channels, - n_channels, - n_ssids, - cfg->channels_2, - IEEE80211_BAND_2GHZ, - false, true, 0, - MAX_CHANNELS_2GHZ, - &n_pactive_ch, - scan_type); + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, + IEEE80211_BAND_2GHZ, + false, true, 0, + MAX_CHANNELS_2GHZ, + &n_pactive_ch); cfg->active[0] = - wlcore_scan_get_channels(wl, - channels, - n_channels, - n_ssids, - cfg->channels_2, - IEEE80211_BAND_2GHZ, - false, false, - cfg->passive[0], - MAX_CHANNELS_2GHZ, - &n_pactive_ch, - scan_type); + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, + IEEE80211_BAND_2GHZ, + false, false, + cfg->passive[0], + MAX_CHANNELS_2GHZ, + &n_pactive_ch); cfg->passive[1] = - wlcore_scan_get_channels(wl, - channels, - n_channels, - n_ssids, - cfg->channels_5, - IEEE80211_BAND_5GHZ, - false, true, 0, - wl->max_channels_5, - &n_pactive_ch, - scan_type); + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, + IEEE80211_BAND_5GHZ, + false, true, 0, + MAX_CHANNELS_5GHZ, + &n_pactive_ch); cfg->dfs = - wlcore_scan_get_channels(wl, - channels, - n_channels, - n_ssids, - cfg->channels_5, - IEEE80211_BAND_5GHZ, - true, true, - cfg->passive[1], - wl->max_channels_5, - &n_pactive_ch, - scan_type); + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, + IEEE80211_BAND_5GHZ, + true, true, + cfg->passive[1], + MAX_CHANNELS_5GHZ, + &n_pactive_ch); cfg->active[1] = - wlcore_scan_get_channels(wl, - channels, - n_channels, - n_ssids, - cfg->channels_5, - IEEE80211_BAND_5GHZ, - false, false, - cfg->passive[1] + cfg->dfs, - wl->max_channels_5, - &n_pactive_ch, - scan_type); - + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, + IEEE80211_BAND_5GHZ, + false, false, + cfg->passive[1] + cfg->dfs, + MAX_CHANNELS_5GHZ, + &n_pactive_ch); /* 802.11j channels are not supported yet */ cfg->passive[2] = 0; cfg->active[2] = 0; - cfg->passive_active = n_pactive_ch; + cfg->n_pactive_ch = n_pactive_ch; wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", cfg->active[0], cfg->passive[0]); @@ -314,48 +556,10 @@ wlcore_set_scan_chan_params(struct wl1271 *wl, cfg->passive[1] || cfg->active[1] || cfg->dfs || cfg->passive[2] || cfg->active[2]; } -EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params); - -int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif, - const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - - /* - * cfg80211 should guarantee that we don't get more channels - * than what we have registered. - */ - BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); - - if (wl->scan.state != WL1271_SCAN_STATE_IDLE) - return -EBUSY; - - wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; - - if (ssid_len && ssid) { - wl->scan.ssid_len = ssid_len; - memcpy(wl->scan.ssid, ssid, ssid_len); - } else { - wl->scan.ssid_len = 0; - } - - wl->scan_wlvif = wlvif; - wl->scan.req = req; - memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - - /* we assume failure so that timeout scenarios are handled correctly */ - wl->scan.failed = true; - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); - wl->ops->scan_start(wl, wlvif, req); - - return 0; -} /* Returns the scan type to be used or a negative value on error */ -int -wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, +static int +wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req) { @@ -458,12 +662,160 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, return ret; return type; } -EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list); -void wlcore_scan_sched_scan_results(struct wl1271 *wl) +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies) +{ + struct wl1271_cmd_sched_scan_config *cfg = NULL; + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; + int i, ret; + bool force_passive = !req->n_ssids; + + wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->role_id = wlvif->role_id; + cfg->rssi_threshold = c->rssi_threshold; + cfg->snr_threshold = c->snr_threshold; + cfg->n_probe_reqs = c->num_probe_reqs; + /* cycles set to 0 it means infinite (until manually stopped) */ + cfg->cycles = 0; + /* report APs when at least 1 is found */ + cfg->report_after = 1; + /* don't stop scanning automatically when something is found */ + cfg->terminate = 0; + cfg->tag = WL1271_SCAN_DEFAULT_TAG; + /* don't filter on BSS type */ + cfg->bss_type = SCAN_BSS_TYPE_ANY; + /* currently NL80211 supports only a single interval */ + for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) + cfg->intervals[i] = cpu_to_le32(req->interval); + + cfg->ssid_len = 0; + ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req); + if (ret < 0) + goto out; + + cfg->filter_type = ret; + + wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); + + if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { + wl1271_error("scan channel list is empty"); + ret = -EINVAL; + goto out; + } + + if (!force_passive && cfg->active[0]) { + u8 band = IEEE80211_BAND_2GHZ; + ret = wl12xx_cmd_build_probe_req(wl, wlvif, + wlvif->role_id, band, + req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[band], + ies->len[band], true); + if (ret < 0) { + wl1271_error("2.4GHz PROBE request template failed"); + goto out; + } + } + + if (!force_passive && cfg->active[1]) { + u8 band = IEEE80211_BAND_5GHZ; + ret = wl12xx_cmd_build_probe_req(wl, wlvif, + wlvif->role_id, band, + req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[band], + ies->len[band], true); + if (ret < 0) { + wl1271_error("5GHz PROBE request template failed"); + goto out; + } + } + + wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, + sizeof(*cfg), 0); + if (ret < 0) { + wl1271_error("SCAN configuration failed"); + goto out; + } +out: + kfree(cfg); + return ret; +} + +int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl1271_cmd_sched_scan_start *start; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); + + if (wlvif->bss_type != BSS_TYPE_STA_BSS) + return -EOPNOTSUPP; + + if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) && + test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) + return -EBUSY; + + start = kzalloc(sizeof(*start), GFP_KERNEL); + if (!start) + return -ENOMEM; + + start->role_id = wlvif->role_id; + start->tag = WL1271_SCAN_DEFAULT_TAG; + + ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, + sizeof(*start), 0); + if (ret < 0) { + wl1271_error("failed to send scan start command"); + goto out_free; + } + +out_free: + kfree(start); + return ret; +} + +void wl1271_scan_sched_scan_results(struct wl1271 *wl) { wl1271_debug(DEBUG_SCAN, "got periodic scan results"); ieee80211_sched_scan_results(wl->hw); } -EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results); + +void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl1271_cmd_sched_scan_stop *stop; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); + + /* FIXME: what to do if alloc'ing to stop fails? */ + stop = kzalloc(sizeof(*stop), GFP_KERNEL); + if (!stop) { + wl1271_error("failed to alloc memory to send sched scan stop"); + return; + } + + stop->role_id = wlvif->role_id; + stop->tag = WL1271_SCAN_DEFAULT_TAG; + + ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, + sizeof(*stop), 0); + if (ret < 0) { + wl1271_error("failed to send sched scan stop command"); + goto out_free; + } + +out_free: + kfree(stop); +} diff --git a/trunk/drivers/net/wireless/ti/wlcore/scan.h b/trunk/drivers/net/wireless/ti/wlcore/scan.h index a6ab24b5c0f9..29f3c8d6b046 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/scan.h +++ b/trunk/drivers/net/wireless/ti/wlcore/scan.h @@ -26,20 +26,22 @@ #include "wlcore.h" -int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif, +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req); +int wl1271_scan_stop(struct wl1271 *wl); int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band); -void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif); +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif); void wl1271_scan_complete_work(struct work_struct *work); int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies); int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); -void wlcore_scan_sched_scan_results(struct wl1271 *wl); +void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); +void wl1271_scan_sched_scan_results(struct wl1271 *wl); #define WL1271_SCAN_MAX_CHANNELS 24 #define WL1271_SCAN_DEFAULT_TAG 1 @@ -64,6 +66,56 @@ enum { WL1271_SCAN_STATE_DONE }; +struct basic_scan_params { + /* Scan option flags (WL1271_SCAN_OPT_*) */ + __le16 scan_options; + u8 role_id; + /* Number of scan channels in the list (maximum 30) */ + u8 n_ch; + /* This field indicates the number of probe requests to send + per channel for an active scan */ + u8 n_probe_reqs; + u8 tid_trigger; + u8 ssid_len; + u8 use_ssid_list; + + /* Rate bit field for sending the probes */ + __le32 tx_rate; + + u8 ssid[IEEE80211_MAX_SSID_LEN]; + /* Band to scan */ + u8 band; + + u8 scan_tag; + u8 padding2[2]; +} __packed; + +struct basic_scan_channel_params { + /* Duration in TU to wait for frames on a channel for active scan */ + __le32 min_duration; + __le32 max_duration; + __le32 bssid_lsb; + __le16 bssid_msb; + u8 early_termination; + u8 tx_power_att; + u8 channel; + /* FW internal use only! */ + u8 dfs_candidate; + u8 activity_detected; + u8 pad; +} __packed; + +struct wl1271_cmd_scan { + struct wl1271_cmd_header header; + + struct basic_scan_params params; + struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; + + /* src mac address */ + u8 addr[ETH_ALEN]; + u8 padding[2]; +} __packed; + struct wl1271_cmd_trigger_scan_to { struct wl1271_cmd_header header; @@ -71,17 +123,9 @@ struct wl1271_cmd_trigger_scan_to { } __packed; #define MAX_CHANNELS_2GHZ 14 +#define MAX_CHANNELS_5GHZ 23 #define MAX_CHANNELS_4GHZ 4 -/* - * This max value here is used only for the struct definition of - * wlcore_scan_channels. This struct is used by both 12xx - * and 18xx (which have different max 5ghz channels value). - * In order to make sure this is large enough, just use the - * max possible 5ghz channels. - */ -#define MAX_CHANNELS_5GHZ 42 - #define SCAN_MAX_CYCLE_INTERVALS 16 #define SCAN_MAX_BANDS 3 @@ -116,6 +160,43 @@ struct conn_scan_ch_params { u8 padding[3]; } __packed; +struct wl1271_cmd_sched_scan_config { + struct wl1271_cmd_header header; + + __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; + + s8 rssi_threshold; /* for filtering (in dBm) */ + s8 snr_threshold; /* for filtering (in dB) */ + + u8 cycles; /* maximum number of scan cycles */ + u8 report_after; /* report when this number of results are received */ + u8 terminate; /* stop scanning after reporting */ + + u8 tag; + u8 bss_type; /* for filtering */ + u8 filter_type; + + u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + u8 n_probe_reqs; /* Number of probes requests per channel */ + + u8 passive[SCAN_MAX_BANDS]; + u8 active[SCAN_MAX_BANDS]; + + u8 dfs; + + u8 n_pactive_ch; /* number of pactive (passive until fw detects energy) + channels in BG band */ + u8 role_id; + u8 padding[1]; + + struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; + struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; + struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; +} __packed; + + #define SCHED_SCAN_MAX_SSIDS 16 enum { @@ -139,34 +220,21 @@ struct wl1271_cmd_sched_scan_ssid_list { u8 padding[2]; } __packed; -struct wlcore_scan_channels { - u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */ - u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */ - u8 dfs; /* number of dfs channels in 5ghz */ - u8 passive_active; /* number of passive before active channels 2.4ghz */ +struct wl1271_cmd_sched_scan_start { + struct wl1271_cmd_header header; - struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; - struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; - struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; -}; + u8 tag; + u8 role_id; + u8 padding[2]; +} __packed; -enum { - SCAN_TYPE_SEARCH = 0, - SCAN_TYPE_PERIODIC = 1, - SCAN_TYPE_TRACKING = 2, -}; +struct wl1271_cmd_sched_scan_stop { + struct wl1271_cmd_header header; + + u8 tag; + u8 role_id; + u8 padding[2]; +} __packed; -bool -wlcore_set_scan_chan_params(struct wl1271 *wl, - struct wlcore_scan_channels *cfg, - struct ieee80211_channel *channels[], - u32 n_channels, - u32 n_ssids, - int scan_type); - -int -wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req); #endif /* __WL1271_SCAN_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/sdio.c b/trunk/drivers/net/wireless/ti/wlcore/sdio.c index 29ef2492951f..646f703ae739 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/sdio.c +++ b/trunk/drivers/net/wireless/ti/wlcore/sdio.c @@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = { static int wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { - struct wlcore_platdev_data *pdev_data; + struct wl12xx_platform_data *wlan_data; struct wl12xx_sdio_glue *glue; struct resource res[1]; mmc_pm_flag_t mmcflags; @@ -228,16 +228,10 @@ static int wl1271_probe(struct sdio_func *func, if (func->num != 0x02) return -ENODEV; - pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); - if (!pdev_data) - goto out; - - pdev_data->if_ops = &sdio_ops; - glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&func->dev, "can't allocate glue\n"); - goto out_free_pdev_data; + goto out; } glue->dev = &func->dev; @@ -248,9 +242,9 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - pdev_data->pdata = wl12xx_get_platform_data(); - if (IS_ERR(pdev_data->pdata)) { - ret = PTR_ERR(pdev_data->pdata); + wlan_data = wl12xx_get_platform_data(); + if (IS_ERR(wlan_data)) { + ret = PTR_ERR(wlan_data); dev_err(glue->dev, "missing wlan platform data: %d\n", ret); goto out_free_glue; } @@ -260,7 +254,9 @@ static int wl1271_probe(struct sdio_func *func, dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); if (mmcflags & MMC_PM_KEEP_POWER) - pdev_data->pdata->pwr_in_suspend = true; + wlan_data->pwr_in_suspend = true; + + wlan_data->ops = &sdio_ops; sdio_set_drvdata(func, glue); @@ -278,7 +274,7 @@ static int wl1271_probe(struct sdio_func *func, else chip_family = "wl12xx"; - glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO); + glue->core = platform_device_alloc(chip_family, -1); if (!glue->core) { dev_err(glue->dev, "can't allocate platform_device"); ret = -ENOMEM; @@ -289,7 +285,7 @@ static int wl1271_probe(struct sdio_func *func, memset(res, 0x00, sizeof(res)); - res[0].start = pdev_data->pdata->irq; + res[0].start = wlan_data->irq; res[0].flags = IORESOURCE_IRQ; res[0].name = "irq"; @@ -299,8 +295,8 @@ static int wl1271_probe(struct sdio_func *func, goto out_dev_put; } - ret = platform_device_add_data(glue->core, pdev_data, - sizeof(*pdev_data)); + ret = platform_device_add_data(glue->core, wlan_data, + sizeof(*wlan_data)); if (ret) { dev_err(glue->dev, "can't add platform data\n"); goto out_dev_put; @@ -319,9 +315,6 @@ static int wl1271_probe(struct sdio_func *func, out_free_glue: kfree(glue); -out_free_pdev_data: - kfree(pdev_data); - out: return ret; } @@ -333,7 +326,8 @@ static void wl1271_remove(struct sdio_func *func) /* Undo decrement done above in wl1271_probe */ pm_runtime_get_noresume(&func->dev); - platform_device_unregister(glue->core); + platform_device_del(glue->core); + platform_device_put(glue->core); kfree(glue); } diff --git a/trunk/drivers/net/wireless/ti/wlcore/spi.c b/trunk/drivers/net/wireless/ti/wlcore/spi.c index e26447832683..f06f4770ce02 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/spi.c +++ b/trunk/drivers/net/wireless/ti/wlcore/spi.c @@ -270,7 +270,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); - struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)]; + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; u32 *cmd; @@ -327,27 +327,22 @@ static struct wl1271_if_operations spi_ops = { static int wl1271_probe(struct spi_device *spi) { struct wl12xx_spi_glue *glue; - struct wlcore_platdev_data *pdev_data; + struct wl12xx_platform_data *pdata; struct resource res[1]; int ret = -ENOMEM; - pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); - if (!pdev_data) - goto out; - - pdev_data->pdata = spi->dev.platform_data; - if (!pdev_data->pdata) { + pdata = spi->dev.platform_data; + if (!pdata) { dev_err(&spi->dev, "no platform data\n"); - ret = -ENODEV; - goto out_free_pdev_data; + return -ENODEV; } - pdev_data->if_ops = &spi_ops; + pdata->ops = &spi_ops; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&spi->dev, "can't allocate glue\n"); - goto out_free_pdev_data; + goto out; } glue->dev = &spi->dev; @@ -364,7 +359,7 @@ static int wl1271_probe(struct spi_device *spi) goto out_free_glue; } - glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO); + glue->core = platform_device_alloc("wl12xx", -1); if (!glue->core) { dev_err(glue->dev, "can't allocate platform_device\n"); ret = -ENOMEM; @@ -385,8 +380,7 @@ static int wl1271_probe(struct spi_device *spi) goto out_dev_put; } - ret = platform_device_add_data(glue->core, pdev_data, - sizeof(*pdev_data)); + ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata)); if (ret) { dev_err(glue->dev, "can't add platform data\n"); goto out_dev_put; @@ -405,10 +399,6 @@ static int wl1271_probe(struct spi_device *spi) out_free_glue: kfree(glue); - -out_free_pdev_data: - kfree(pdev_data); - out: return ret; } @@ -417,7 +407,8 @@ static int wl1271_remove(struct spi_device *spi) { struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); - platform_device_unregister(glue->core); + platform_device_del(glue->core); + platform_device_put(glue->core); kfree(glue); return 0; diff --git a/trunk/drivers/net/wireless/ti/wlcore/tx.c b/trunk/drivers/net/wireless/ti/wlcore/tx.c index ece392c54d9c..a90d3cd09408 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/tx.c +++ b/trunk/drivers/net/wireless/ti/wlcore/tx.c @@ -104,7 +104,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) { - bool fw_ps, single_link; + bool fw_ps, single_sta; u8 tx_pkts; if (WARN_ON(!test_bit(hlid, wlvif->links_map))) @@ -112,15 +112,15 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; - single_link = (wl->active_link_count == 1); + single_sta = (wl->active_sta_count == 1); /* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. - * Make an exception if this is the only connected link. In this - * case FW-memory congestion is less of a problem. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. */ - if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl12xx_ps_link_start(wl, wlvif, hlid, true); } @@ -155,18 +155,21 @@ static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct sk_buff *skb, struct ieee80211_sta *sta) { - struct ieee80211_tx_info *control; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) + return wl->system_hlid; if (wlvif->bss_type == BSS_TYPE_AP_BSS) return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta); - control = IEEE80211_SKB_CB(skb); - if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { - wl1271_debug(DEBUG_TX, "tx offchannel"); + if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || + test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && + !ieee80211_is_auth(hdr->frame_control) && + !ieee80211_is_assoc_req(hdr->frame_control)) + return wlvif->sta.hlid; + else return wlvif->dev_hlid; - } - - return wlvif->sta.hlid; } unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, @@ -221,7 +224,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); wl->tx_allocated_pkts[ac]++; - if (test_bit(hlid, wl->links_map)) + if (!wl12xx_is_dummy_packet(wl, skb) && wlvif && + wlvif->bss_type == BSS_TYPE_AP_BSS && + test_bit(hlid, wlvif->ap.sta_hlid_map)) wl->links[hlid].allocated_pkts++; ret = 0; @@ -288,14 +293,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; } else if (wlvif) { - u8 session_id = wl->session_ids[hlid]; - - if ((wl->quirks & WLCORE_QUIRK_AP_ZERO_SESSION_ID) && - (wlvif->bss_type == BSS_TYPE_AP_BSS)) - session_id = 0; - /* configure the tx attributes */ - tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER; + tx_attr = wlvif->session_counter << + TX_HW_ATTR_OFST_SESSION_COUNTER; } desc->hlid = hlid; @@ -452,22 +452,20 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, void wl1271_handle_tx_low_watermark(struct wl1271 *wl) { int i; - struct wl12xx_vif *wlvif; - wl12xx_for_each_wlvif(wl, wlvif) { - for (i = 0; i < NUM_TX_QUEUES; i++) { - if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i, - WLCORE_QUEUE_STOP_REASON_WATERMARK) && - wlvif->tx_queue_count[i] <= - WL1271_TX_QUEUE_LOW_WATERMARK) - /* firmware buffer has space, restart queues */ - wlcore_wake_queue(wl, wlvif, i, - WLCORE_QUEUE_STOP_REASON_WATERMARK); + for (i = 0; i < NUM_TX_QUEUES; i++) { + if (wlcore_is_queue_stopped_by_reason(wl, i, + WLCORE_QUEUE_STOP_REASON_WATERMARK) && + wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { + /* firmware buffer has space, restart queues */ + wlcore_wake_queue(wl, i, + WLCORE_QUEUE_STOP_REASON_WATERMARK); } } } -static int wlcore_select_ac(struct wl1271 *wl) +static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, + struct sk_buff_head *queues) { int i, q = -1, ac; u32 min_pkts = 0xffffffff; @@ -481,60 +479,45 @@ static int wlcore_select_ac(struct wl1271 *wl) */ for (i = 0; i < NUM_TX_QUEUES; i++) { ac = wl1271_tx_get_queue(i); - if (wl->tx_queue_count[ac] && - wl->tx_allocated_pkts[ac] < min_pkts) { + if (!skb_queue_empty(&queues[ac]) && + (wl->tx_allocated_pkts[ac] < min_pkts)) { q = ac; min_pkts = wl->tx_allocated_pkts[q]; } } - return q; + if (q == -1) + return NULL; + + return &queues[q]; } -static struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl, - struct wl1271_link *lnk, u8 q) +static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, + struct wl1271_link *lnk) { struct sk_buff *skb; unsigned long flags; + struct sk_buff_head *queue; - skb = skb_dequeue(&lnk->tx_queue[q]); + queue = wl1271_select_queue(wl, lnk->tx_queue); + if (!queue) + return NULL; + + skb = skb_dequeue(queue); if (skb) { + int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); spin_lock_irqsave(&wl->wl_lock, flags); WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); wl->tx_queue_count[q]--; - if (lnk->wlvif) { - WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0); - lnk->wlvif->tx_queue_count[q]--; - } spin_unlock_irqrestore(&wl->wl_lock, flags); } return skb; } -static struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl, - u8 hlid, u8 ac, - u8 *low_prio_hlid) -{ - struct wl1271_link *lnk = &wl->links[hlid]; - - if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) { - if (*low_prio_hlid == WL12XX_INVALID_LINK_ID && - !skb_queue_empty(&lnk->tx_queue[ac]) && - wlcore_hw_lnk_low_prio(wl, hlid, lnk)) - /* we found the first non-empty low priority queue */ - *low_prio_hlid = hlid; - - return NULL; - } - - return wlcore_lnk_dequeue(wl, lnk, ac); -} - -static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u8 ac, u8 *hlid, - u8 *low_prio_hlid) +static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 *hlid) { struct sk_buff *skb = NULL; int i, h, start_hlid; @@ -550,8 +533,7 @@ static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl, if (!test_bit(h, wlvif->links_map)) continue; - skb = wlcore_lnk_dequeue_high_prio(wl, h, ac, - low_prio_hlid); + skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); if (!skb) continue; @@ -571,74 +553,42 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) unsigned long flags; struct wl12xx_vif *wlvif = wl->last_wlvif; struct sk_buff *skb = NULL; - int ac; - u8 low_prio_hlid = WL12XX_INVALID_LINK_ID; - - ac = wlcore_select_ac(wl); - if (ac < 0) - goto out; /* continue from last wlvif (round robin) */ if (wlvif) { wl12xx_for_each_wlvif_continue(wl, wlvif) { - if (!wlvif->tx_queue_count[ac]) - continue; - - skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid, - &low_prio_hlid); - if (!skb) - continue; - - wl->last_wlvif = wlvif; - break; + skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); + if (skb) { + wl->last_wlvif = wlvif; + break; + } } } /* dequeue from the system HLID before the restarting wlvif list */ if (!skb) { - skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid, - ac, &low_prio_hlid); - if (skb) { - *hlid = wl->system_hlid; - wl->last_wlvif = NULL; - } + skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); + *hlid = wl->system_hlid; } - /* Do a new pass over the wlvif list. But no need to continue - * after last_wlvif. The previous pass should have found it. */ + /* do a new pass over the wlvif list */ if (!skb) { wl12xx_for_each_wlvif(wl, wlvif) { - if (!wlvif->tx_queue_count[ac]) - goto next; - - skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid, - &low_prio_hlid); + skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); if (skb) { wl->last_wlvif = wlvif; break; } -next: + /* + * No need to continue after last_wlvif. The previous + * pass should have found it. + */ if (wlvif == wl->last_wlvif) break; } } - /* no high priority skbs found - but maybe a low priority one? */ - if (!skb && low_prio_hlid != WL12XX_INVALID_LINK_ID) { - struct wl1271_link *lnk = &wl->links[low_prio_hlid]; - skb = wlcore_lnk_dequeue(wl, lnk, ac); - - WARN_ON(!skb); /* we checked this before */ - *hlid = low_prio_hlid; - - /* ensure proper round robin in the vif/link levels */ - wl->last_wlvif = lnk->wlvif; - if (lnk->wlvif) - lnk->wlvif->last_tx_hlid = low_prio_hlid; - - } - if (!skb && test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { int q; @@ -652,7 +602,6 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) spin_unlock_irqrestore(&wl->wl_lock, flags); } -out: return skb; } @@ -674,8 +623,6 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, spin_lock_irqsave(&wl->wl_lock, flags); wl->tx_queue_count[q]++; - if (wlvif) - wlvif->tx_queue_count[q]++; spin_unlock_irqrestore(&wl->wl_lock, flags); } @@ -752,7 +699,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) bool has_data = false; wlvif = NULL; - if (!wl12xx_is_dummy_packet(wl, skb)) + if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) wlvif = wl12xx_vif_to_data(info->control.vif); else hlid = wl->system_hlid; @@ -1025,11 +972,10 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) unsigned long flags; struct ieee80211_tx_info *info; int total[NUM_TX_QUEUES]; - struct wl1271_link *lnk = &wl->links[hlid]; for (i = 0; i < NUM_TX_QUEUES; i++) { total[i] = 0; - while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { + while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); if (!wl12xx_is_dummy_packet(wl, skb)) { @@ -1044,11 +990,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) } spin_lock_irqsave(&wl->wl_lock, flags); - for (i = 0; i < NUM_TX_QUEUES; i++) { + for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_queue_count[i] -= total[i]; - if (lnk->wlvif) - lnk->wlvif->tx_queue_count[i] -= total[i]; - } spin_unlock_irqrestore(&wl->wl_lock, flags); wl1271_handle_tx_low_watermark(wl); @@ -1061,18 +1004,16 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) /* TX failure */ for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { - if (wlvif->bss_type == BSS_TYPE_AP_BSS) { - /* this calls wl12xx_free_link */ + if (wlvif->bss_type == BSS_TYPE_AP_BSS) wl1271_free_sta(wl, wlvif, i); - } else { - u8 hlid = i; - wl12xx_free_link(wl, wlvif, &hlid); - } + else + wlvif->sta.ba_rx_bitmap = 0; + + wl->links[i].allocated_pkts = 0; + wl->links[i].prev_freed_pkts = 0; } wlvif->last_tx_hlid = 0; - for (i = 0; i < NUM_TX_QUEUES; i++) - wlvif->tx_queue_count[i] = 0; } /* caller must hold wl->mutex and TX must be stopped */ void wl12xx_tx_reset(struct wl1271 *wl) @@ -1082,7 +1023,7 @@ void wl12xx_tx_reset(struct wl1271 *wl) struct ieee80211_tx_info *info; /* only reset the queues if something bad happened */ - if (wl1271_tx_total_queue_count(wl) != 0) { + if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { for (i = 0; i < WL12XX_MAX_LINKS; i++) wl1271_tx_reset_link_queues(wl, i); @@ -1194,48 +1135,45 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) return BIT(__ffs(rate_set)); } -EXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get); -void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 queue, enum wlcore_queue_stop_reason reason) +void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue, + enum wlcore_queue_stop_reason reason) { - int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); - bool stopped = !!wl->queue_stop_reasons[hwq]; + bool stopped = !!wl->queue_stop_reasons[queue]; /* queue should not be stopped for this reason */ - WARN_ON_ONCE(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq])); + WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue])); if (stopped) return; - ieee80211_stop_queue(wl->hw, hwq); + ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue)); } -void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, +void wlcore_stop_queue(struct wl1271 *wl, u8 queue, enum wlcore_queue_stop_reason reason) { unsigned long flags; spin_lock_irqsave(&wl->wl_lock, flags); - wlcore_stop_queue_locked(wl, wlvif, queue, reason); + wlcore_stop_queue_locked(wl, queue, reason); spin_unlock_irqrestore(&wl->wl_lock, flags); } -void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, +void wlcore_wake_queue(struct wl1271 *wl, u8 queue, enum wlcore_queue_stop_reason reason) { unsigned long flags; - int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); spin_lock_irqsave(&wl->wl_lock, flags); /* queue should not be clear for this reason */ - WARN_ON_ONCE(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq])); + WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue])); - if (wl->queue_stop_reasons[hwq]) + if (wl->queue_stop_reasons[queue]) goto out; - ieee80211_wake_queue(wl->hw, hwq); + ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue)); out: spin_unlock_irqrestore(&wl->wl_lock, flags); @@ -1245,74 +1183,48 @@ void wlcore_stop_queues(struct wl1271 *wl, enum wlcore_queue_stop_reason reason) { int i; - unsigned long flags; - - spin_lock_irqsave(&wl->wl_lock, flags); - - /* mark all possible queues as stopped */ - for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) - WARN_ON_ONCE(test_and_set_bit(reason, - &wl->queue_stop_reasons[i])); - /* use the global version to make sure all vifs in mac80211 we don't - * know are stopped. - */ - ieee80211_stop_queues(wl->hw); - - spin_unlock_irqrestore(&wl->wl_lock, flags); + for (i = 0; i < NUM_TX_QUEUES; i++) + wlcore_stop_queue(wl, i, reason); } +EXPORT_SYMBOL_GPL(wlcore_stop_queues); void wlcore_wake_queues(struct wl1271 *wl, enum wlcore_queue_stop_reason reason) { int i; - unsigned long flags; - - spin_lock_irqsave(&wl->wl_lock, flags); - /* mark all possible queues as awake */ - for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) - WARN_ON_ONCE(!test_and_clear_bit(reason, - &wl->queue_stop_reasons[i])); - - /* use the global version to make sure all vifs in mac80211 we don't - * know are woken up. - */ - ieee80211_wake_queues(wl->hw); - - spin_unlock_irqrestore(&wl->wl_lock, flags); + for (i = 0; i < NUM_TX_QUEUES; i++) + wlcore_wake_queue(wl, i, reason); } +EXPORT_SYMBOL_GPL(wlcore_wake_queues); -bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, - struct wl12xx_vif *wlvif, u8 queue, - enum wlcore_queue_stop_reason reason) +void wlcore_reset_stopped_queues(struct wl1271 *wl) { + int i; unsigned long flags; - bool stopped; spin_lock_irqsave(&wl->wl_lock, flags); - stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue, - reason); - spin_unlock_irqrestore(&wl->wl_lock, flags); - return stopped; -} + for (i = 0; i < NUM_TX_QUEUES; i++) { + if (!wl->queue_stop_reasons[i]) + continue; -bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, - struct wl12xx_vif *wlvif, u8 queue, - enum wlcore_queue_stop_reason reason) -{ - int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); + wl->queue_stop_reasons[i] = 0; + ieee80211_wake_queue(wl->hw, + wl1271_tx_get_mac80211_queue(i)); + } - WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); - return test_bit(reason, &wl->queue_stop_reasons[hwq]); + spin_unlock_irqrestore(&wl->wl_lock, flags); } -bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 queue) +bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue, + enum wlcore_queue_stop_reason reason) { - int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); + return test_bit(reason, &wl->queue_stop_reasons[queue]); +} - WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); - return !!wl->queue_stop_reasons[hwq]; +bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue) +{ + return !!wl->queue_stop_reasons[queue]; } diff --git a/trunk/drivers/net/wireless/ti/wlcore/tx.h b/trunk/drivers/net/wireless/ti/wlcore/tx.h index 55aa4acf9105..349520d8b724 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/tx.h +++ b/trunk/drivers/net/wireless/ti/wlcore/tx.h @@ -207,22 +207,19 @@ static inline int wl1271_tx_get_queue(int queue) } } -static inline -int wlcore_tx_get_mac80211_queue(struct wl12xx_vif *wlvif, int queue) +static inline int wl1271_tx_get_mac80211_queue(int queue) { - int mac_queue = wlvif->hw_queue_base; - switch (queue) { case CONF_TX_AC_VO: - return mac_queue + 0; + return 0; case CONF_TX_AC_VI: - return mac_queue + 1; + return 1; case CONF_TX_AC_BE: - return mac_queue + 2; + return 2; case CONF_TX_AC_BK: - return mac_queue + 3; + return 3; default: - return mac_queue + 2; + return 2; } } @@ -255,26 +252,20 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, unsigned int packet_length); void wl1271_free_tx_id(struct wl1271 *wl, int id); -void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 queue, enum wlcore_queue_stop_reason reason); -void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, +void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue, + enum wlcore_queue_stop_reason reason); +void wlcore_stop_queue(struct wl1271 *wl, u8 queue, enum wlcore_queue_stop_reason reason); -void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, +void wlcore_wake_queue(struct wl1271 *wl, u8 queue, enum wlcore_queue_stop_reason reason); void wlcore_stop_queues(struct wl1271 *wl, enum wlcore_queue_stop_reason reason); void wlcore_wake_queues(struct wl1271 *wl, enum wlcore_queue_stop_reason reason); -bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, - struct wl12xx_vif *wlvif, u8 queue, +void wlcore_reset_stopped_queues(struct wl1271 *wl); +bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue, enum wlcore_queue_stop_reason reason); -bool -wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u8 queue, - enum wlcore_queue_stop_reason reason); -bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 queue); +bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue); /* from main.c */ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); diff --git a/trunk/drivers/net/wireless/ti/wilink_platform_data.c b/trunk/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c similarity index 100% rename from trunk/drivers/net/wireless/ti/wilink_platform_data.c rename to trunk/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c diff --git a/trunk/drivers/net/wireless/ti/wlcore/wlcore.h b/trunk/drivers/net/wireless/ti/wlcore/wlcore.h index af9fecaefc30..c3884937c007 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/trunk/drivers/net/wireless/ti/wlcore/wlcore.h @@ -37,9 +37,6 @@ */ #define WLCORE_NUM_MAC_ADDRESSES 3 -/* wl12xx/wl18xx maximum transmission power (in dBm) */ -#define WLCORE_MAX_TXPWR 25 - /* forward declaration */ struct wl1271_tx_hw_descr; enum wl_rx_buf_align; @@ -54,9 +51,6 @@ struct wlcore_ops { int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, void *buf, size_t len); int (*ack_event)(struct wl1271 *wl); - int (*wait_for_event)(struct wl1271 *wl, enum wlcore_wait_event event, - bool *timeout); - int (*process_mailbox_events)(struct wl1271 *wl); u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); void (*set_tx_desc_blocks)(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, @@ -88,32 +82,12 @@ struct wlcore_ops { int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir); int (*handle_static_data)(struct wl1271 *wl, struct wl1271_static_data *static_data); - int (*scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_scan_request *req); - int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); - int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); - void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem); int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key_conf); - int (*channel_switch)(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch); u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); - void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u32 changed); - int (*set_peer_cap)(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, - u32 rate_set, u8 hlid); - bool (*lnk_high_prio)(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk); - bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, - struct wl1271_link *lnk); }; enum wlcore_partitions { @@ -183,6 +157,7 @@ struct wl1271 { struct wl1271_if_operations *if_ops; + void (*set_power)(bool enable); int irq; spinlock_t wl_lock; @@ -227,8 +202,6 @@ struct wl1271 { unsigned long klv_templates_map[ BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)]; - u8 session_ids[WL12XX_MAX_LINKS]; - struct list_head wlvif_list; u8 sta_count; @@ -254,8 +227,7 @@ struct wl1271 { /* Frames scheduled for transmission, not handled yet */ int tx_queue_count[NUM_TX_QUEUES]; - unsigned long queue_stop_reasons[ - NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES]; + unsigned long queue_stop_reasons[NUM_TX_QUEUES]; /* Frames received, not handled yet by mac80211 */ struct sk_buff_head deferred_rx_queue; @@ -297,30 +269,24 @@ struct wl1271 { struct work_struct recovery_work; bool watchdog_recovery; - /* Reg domain last configuration */ - u32 reg_ch_conf_last[2]; - /* Reg domain pending configuration */ - u32 reg_ch_conf_pending[2]; - /* Pointer that holds DMA-friendly block for the mailbox */ - void *mbox; + struct event_mailbox *mbox; /* The mbox event mask */ u32 event_mask; /* Mailbox pointers */ - u32 mbox_size; u32 mbox_ptr[2]; /* Are we currently scanning */ - struct wl12xx_vif *scan_wlvif; + struct ieee80211_vif *scan_vif; struct wl1271_scan scan; struct delayed_work scan_complete_work; - struct ieee80211_vif *roc_vif; - struct delayed_work roc_complete_work; + /* Connection loss work */ + struct delayed_work connection_loss_work; - struct wl12xx_vif *sched_vif; + bool sched_scanning; /* The current band */ enum ieee80211_band band; @@ -333,7 +299,7 @@ struct wl1271 { struct wl1271_stats stats; - __le32 *buffer_32; + __le32 buffer_32; u32 buffer_cmd; u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; @@ -348,8 +314,6 @@ struct wl1271 { bool enable_11a; - int recovery_count; - /* Most recently reported noise in dBm */ s8 noise; @@ -369,12 +333,6 @@ struct wl1271 { */ struct wl1271_link links[WL12XX_MAX_LINKS]; - /* number of currently active links */ - int active_link_count; - - /* Fast/slow links bitmap according to FW */ - u32 fw_fast_lnk_map; - /* AP-mode - a bitmap of links currently in PS mode according to FW */ u32 ap_fw_ps_map; @@ -409,12 +367,6 @@ struct wl1271 { const char *sr_fw_name; const char *mr_fw_name; - u8 scan_templ_id_2_4; - u8 scan_templ_id_5; - u8 sched_scan_templ_id_2_4; - u8 sched_scan_templ_id_5; - u8 max_channels_5; - /* per-chip-family private structure */ void *priv; @@ -456,28 +408,20 @@ struct wl1271 { /* the number of allocated MAC addresses in this chip */ int num_mac_addr; - /* minimum FW version required for the driver to work in single-role */ - unsigned int min_sr_fw_ver[NUM_FW_VER]; - - /* minimum FW version required for the driver to work in multi-role */ - unsigned int min_mr_fw_ver[NUM_FW_VER]; + /* the minimum FW version required for the driver to work */ + unsigned int min_fw_ver[NUM_FW_VER]; struct completion nvs_loading_complete; - - /* number of concurrent channels the HW supports */ - u32 num_channels; }; int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); int wlcore_remove(struct platform_device *pdev); -struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, - u32 mbox_size); +struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size); int wlcore_free_hw(struct wl1271 *wl); int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key_conf); -void wlcore_regdomain_config(struct wl1271 *wl); static inline void wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, @@ -486,27 +430,16 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap)); } -/* Tell wlcore not to care about this element when checking the version */ -#define WLCORE_FW_VER_IGNORE -1 - static inline void wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, - unsigned int iftype_sr, unsigned int major_sr, - unsigned int subtype_sr, unsigned int minor_sr, - unsigned int iftype_mr, unsigned int major_mr, - unsigned int subtype_mr, unsigned int minor_mr) + unsigned int iftype, unsigned int major, + unsigned int subtype, unsigned int minor) { - wl->min_sr_fw_ver[FW_VER_CHIP] = chip; - wl->min_sr_fw_ver[FW_VER_IF_TYPE] = iftype_sr; - wl->min_sr_fw_ver[FW_VER_MAJOR] = major_sr; - wl->min_sr_fw_ver[FW_VER_SUBTYPE] = subtype_sr; - wl->min_sr_fw_ver[FW_VER_MINOR] = minor_sr; - - wl->min_mr_fw_ver[FW_VER_CHIP] = chip; - wl->min_mr_fw_ver[FW_VER_IF_TYPE] = iftype_mr; - wl->min_mr_fw_ver[FW_VER_MAJOR] = major_mr; - wl->min_mr_fw_ver[FW_VER_SUBTYPE] = subtype_mr; - wl->min_mr_fw_ver[FW_VER_MINOR] = minor_mr; + wl->min_fw_ver[FW_VER_CHIP] = chip; + wl->min_fw_ver[FW_VER_IF_TYPE] = iftype; + wl->min_fw_ver[FW_VER_MAJOR] = major; + wl->min_fw_ver[FW_VER_SUBTYPE] = subtype; + wl->min_fw_ver[FW_VER_MINOR] = minor; } /* Firmware image load chunk size */ @@ -517,9 +450,6 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, /* Each RX/TX transaction requires an end-of-transaction transfer */ #define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0) -/* the first start_role(sta) sometimes doesn't work on wl12xx */ -#define WLCORE_QUIRK_START_STA_FAILS BIT(1) - /* wl127x and SPI don't support SDIO block size alignment */ #define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2) @@ -532,6 +462,9 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, /* Older firmwares use an old NVS format */ #define WLCORE_QUIRK_LEGACY_NVS BIT(5) +/* Some firmwares may not support ELP */ +#define WLCORE_QUIRK_NO_ELP BIT(6) + /* pad only the last frame in the aggregate buffer */ #define WLCORE_QUIRK_TX_PAD_LAST_FRAME BIT(7) @@ -544,11 +477,11 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, /* separate probe response templates for one-shot and sched scans */ #define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10) -/* Firmware requires reg domain configuration for active calibration */ -#define WLCORE_QUIRK_REGDOMAIN_CONF BIT(11) - -/* The FW only support a zero session id for AP */ -#define WLCORE_QUIRK_AP_ZERO_SESSION_ID BIT(12) +/* TODO: move to the lower drivers when all usages are abstracted */ +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) +#define CHIP_ID_1283_PG10 (0x05030101) +#define CHIP_ID_1283_PG20 (0x05030111) /* TODO: move all these common registers and values elsewhere */ #define HW_ACCESS_ELP_CTRL_REG 0x1FFFC diff --git a/trunk/drivers/net/wireless/ti/wlcore/wlcore_i.h b/trunk/drivers/net/wireless/ti/wlcore/wlcore_i.h index c845b0ef7f4b..6678d4b18611 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/trunk/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -109,6 +109,17 @@ enum { NUM_FW_VER }; +#define FW_VER_CHIP_WL127X 6 +#define FW_VER_CHIP_WL128X 7 + +#define FW_VER_IF_TYPE_STA 1 +#define FW_VER_IF_TYPE_AP 2 + +#define FW_VER_MINOR_1_SPARE_STA_MIN 58 +#define FW_VER_MINOR_1_SPARE_AP_MIN 47 + +#define FW_VER_MINOR_FWLOG_STA_MIN 70 + struct wl1271_chip { u32 id; char fw_ver_str[ETHTOOL_BUSINFO_LEN]; @@ -130,10 +141,7 @@ struct wl_fw_packet_counters { /* Cumulative counter of released Voice memory blocks */ u8 tx_voice_released_blks; - /* Tx rate of the last transmitted packet */ - u8 tx_last_rate; - - u8 padding[2]; + u8 padding[3]; } __packed; /* FW status registers */ @@ -206,11 +214,6 @@ struct wl1271_if_operations { void (*set_block_size) (struct device *child, unsigned int blksz); }; -struct wlcore_platdev_data { - struct wl12xx_platform_data *pdata; - struct wl1271_if_operations *if_ops; -}; - #define MAX_NUM_KEYS 14 #define MAX_KEY_SIZE 32 @@ -257,8 +260,6 @@ enum wl12xx_vif_flags { WLVIF_FLAG_IN_USE, }; -struct wl12xx_vif; - struct wl1271_link { /* AP-mode - TX queue per AC in link */ struct sk_buff_head tx_queue[NUM_TX_QUEUES]; @@ -271,9 +272,6 @@ struct wl1271_link { /* bitmap of TIDs where RX BA sessions are active for this link */ u8 ba_bitmap; - - /* The wlvif this link belongs to. Might be null for global links */ - struct wl12xx_vif *wlvif; }; #define WL1271_MAX_RX_FILTERS 5 @@ -317,7 +315,6 @@ struct wl12xx_rx_filter { struct wl1271_station { u8 hlid; - bool in_connection; }; struct wl12xx_vif { @@ -335,6 +332,7 @@ struct wl12xx_vif { union { struct { u8 hlid; + u8 ba_rx_bitmap; u8 basic_rate_idx; u8 ap_rate_idx; @@ -343,8 +341,6 @@ struct wl12xx_vif { u8 klv_template_id; bool qos; - /* channel type we started the STA role with */ - enum nl80211_channel_type role_chan_type; } sta; struct { u8 global_hlid; @@ -366,9 +362,6 @@ struct wl12xx_vif { /* the hlid of the last transmitted skb */ int last_tx_hlid; - /* counters of packets per AC, across all links in the vif */ - int tx_queue_count[NUM_TX_QUEUES]; - unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; @@ -403,6 +396,9 @@ struct wl12xx_vif { /* Our association ID */ u16 aid; + /* Session counter for the chipset */ + int session_counter; + /* retry counter for PSM entries */ u8 psm_entry_retry; @@ -420,28 +416,11 @@ struct wl12xx_vif { bool ba_support; bool ba_allowed; - bool wmm_enabled; - /* Rx Streaming */ struct work_struct rx_streaming_enable_work; struct work_struct rx_streaming_disable_work; struct timer_list rx_streaming_timer; - struct delayed_work channel_switch_work; - struct delayed_work connection_loss_work; - - /* number of in connection stations */ - int inconn_count; - - /* - * This vif's queues are mapped to mac80211 HW queues as: - * VO - hw_queue_base - * VI - hw_queue_base + 1 - * BE - hw_queue_base + 2 - * BK - hw_queue_base + 3 - */ - int hw_queue_base; - /* * This struct must be last! * data that has to be saved acrossed reconfigs (e.g. recovery) @@ -464,7 +443,6 @@ struct wl12xx_vif { static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) { - WARN_ON(!vif); return (struct wl12xx_vif *)vif->drv_priv; } diff --git a/trunk/drivers/nfc/Kconfig b/trunk/drivers/nfc/Kconfig index e57034971ccc..80c728b28828 100644 --- a/trunk/drivers/nfc/Kconfig +++ b/trunk/drivers/nfc/Kconfig @@ -27,6 +27,5 @@ config NFC_WILINK into the kernel or say M to compile it as module. source "drivers/nfc/pn544/Kconfig" -source "drivers/nfc/microread/Kconfig" endmenu diff --git a/trunk/drivers/nfc/Makefile b/trunk/drivers/nfc/Makefile index a189ada0926a..574bbc04d97a 100644 --- a/trunk/drivers/nfc/Makefile +++ b/trunk/drivers/nfc/Makefile @@ -3,7 +3,6 @@ # obj-$(CONFIG_NFC_PN544) += pn544/ -obj-$(CONFIG_NFC_MICROREAD) += microread/ obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o diff --git a/trunk/drivers/nfc/microread/Kconfig b/trunk/drivers/nfc/microread/Kconfig deleted file mode 100644 index 572305be6e37..000000000000 --- a/trunk/drivers/nfc/microread/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config NFC_MICROREAD - tristate "Inside Secure microread NFC driver" - depends on NFC_HCI - select CRC_CCITT - default n - ---help--- - This module contains the main code for Inside Secure microread - NFC chipsets. It implements the chipset HCI logic and hooks into - the NFC kernel APIs. Physical layers will register against it. - - To compile this driver as a module, choose m here. The module will - be called microread. - Say N if unsure. - -config NFC_MICROREAD_I2C - tristate "NFC Microread i2c support" - depends on NFC_MICROREAD && I2C && NFC_SHDLC - ---help--- - This module adds support for the i2c interface of adapters using - Inside microread chipsets. Select this if your platform is using - the i2c bus. - - If you choose to build a module, it'll be called microread_i2c. - Say N if unsure. - -config NFC_MICROREAD_MEI - tristate "NFC Microread MEI support" - depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC - ---help--- - This module adds support for the mei interface of adapters using - Inside microread chipsets. Select this if your microread chipset - is handled by Intel's Management Engine Interface on your platform. - - If you choose to build a module, it'll be called microread_mei. - Say N if unsure. diff --git a/trunk/drivers/nfc/microread/Makefile b/trunk/drivers/nfc/microread/Makefile deleted file mode 100644 index 755c24cba253..000000000000 --- a/trunk/drivers/nfc/microread/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for Microread HCI based NFC driver -# - -microread_i2c-objs = i2c.o -microread_mei-objs = mei.o - -obj-$(CONFIG_NFC_MICROREAD) += microread.o -obj-$(CONFIG_NFC_MICROREAD_I2C) += microread_i2c.o -obj-$(CONFIG_NFC_MICROREAD_MEI) += microread_mei.o diff --git a/trunk/drivers/nfc/microread/i2c.c b/trunk/drivers/nfc/microread/i2c.c deleted file mode 100644 index 101089495bf8..000000000000 --- a/trunk/drivers/nfc/microread/i2c.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * HCI based Driver for Inside Secure microread NFC Chip - i2c layer - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, 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., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "microread.h" - -#define MICROREAD_I2C_DRIVER_NAME "microread" - -#define MICROREAD_I2C_FRAME_HEADROOM 1 -#define MICROREAD_I2C_FRAME_TAILROOM 1 - -/* framing in HCI mode */ -#define MICROREAD_I2C_LLC_LEN 1 -#define MICROREAD_I2C_LLC_CRC 1 -#define MICROREAD_I2C_LLC_LEN_CRC (MICROREAD_I2C_LLC_LEN + \ - MICROREAD_I2C_LLC_CRC) -#define MICROREAD_I2C_LLC_MIN_SIZE (1 + MICROREAD_I2C_LLC_LEN_CRC) -#define MICROREAD_I2C_LLC_MAX_PAYLOAD 29 -#define MICROREAD_I2C_LLC_MAX_SIZE (MICROREAD_I2C_LLC_LEN_CRC + 1 + \ - MICROREAD_I2C_LLC_MAX_PAYLOAD) - -struct microread_i2c_phy { - struct i2c_client *i2c_dev; - struct nfc_hci_dev *hdev; - - int irq; - - int hard_fault; /* - * < 0 if hardware error occured (e.g. i2c err) - * and prevents normal operation. - */ -}; - -#define I2C_DUMP_SKB(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \ - 16, 1, (skb)->data, (skb)->len, 0); \ -} while (0) - -static void microread_i2c_add_len_crc(struct sk_buff *skb) -{ - int i; - u8 crc = 0; - int len; - - len = skb->len; - *skb_push(skb, 1) = len; - - for (i = 0; i < skb->len; i++) - crc = crc ^ skb->data[i]; - - *skb_put(skb, 1) = crc; -} - -static void microread_i2c_remove_len_crc(struct sk_buff *skb) -{ - skb_pull(skb, MICROREAD_I2C_FRAME_HEADROOM); - skb_trim(skb, MICROREAD_I2C_FRAME_TAILROOM); -} - -static int check_crc(struct sk_buff *skb) -{ - int i; - u8 crc = 0; - - for (i = 0; i < skb->len - 1; i++) - crc = crc ^ skb->data[i]; - - if (crc != skb->data[skb->len-1]) { - pr_err(MICROREAD_I2C_DRIVER_NAME - ": CRC error 0x%x != 0x%x\n", - crc, skb->data[skb->len-1]); - - pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); - - return -EPERM; - } - - return 0; -} - -static int microread_i2c_enable(void *phy_id) -{ - return 0; -} - -static void microread_i2c_disable(void *phy_id) -{ - return; -} - -static int microread_i2c_write(void *phy_id, struct sk_buff *skb) -{ - int r; - struct microread_i2c_phy *phy = phy_id; - struct i2c_client *client = phy->i2c_dev; - - if (phy->hard_fault != 0) - return phy->hard_fault; - - usleep_range(3000, 6000); - - microread_i2c_add_len_crc(skb); - - I2C_DUMP_SKB("i2c frame written", skb); - - r = i2c_master_send(client, skb->data, skb->len); - - if (r == -EREMOTEIO) { /* Retry, chip was in standby */ - usleep_range(6000, 10000); - r = i2c_master_send(client, skb->data, skb->len); - } - - if (r >= 0) { - if (r != skb->len) - r = -EREMOTEIO; - else - r = 0; - } - - microread_i2c_remove_len_crc(skb); - - return r; -} - - -static int microread_i2c_read(struct microread_i2c_phy *phy, - struct sk_buff **skb) -{ - int r; - u8 len; - u8 tmp[MICROREAD_I2C_LLC_MAX_SIZE - 1]; - struct i2c_client *client = phy->i2c_dev; - - pr_debug("%s\n", __func__); - - r = i2c_master_recv(client, &len, 1); - if (r != 1) { - dev_err(&client->dev, "cannot read len byte\n"); - return -EREMOTEIO; - } - - if ((len < MICROREAD_I2C_LLC_MIN_SIZE) || - (len > MICROREAD_I2C_LLC_MAX_SIZE)) { - dev_err(&client->dev, "invalid len byte\n"); - pr_err("invalid len byte\n"); - r = -EBADMSG; - goto flush; - } - - *skb = alloc_skb(1 + len, GFP_KERNEL); - if (*skb == NULL) { - r = -ENOMEM; - goto flush; - } - - *skb_put(*skb, 1) = len; - - r = i2c_master_recv(client, skb_put(*skb, len), len); - if (r != len) { - kfree_skb(*skb); - return -EREMOTEIO; - } - - I2C_DUMP_SKB("cc frame read", *skb); - - r = check_crc(*skb); - if (r != 0) { - kfree_skb(*skb); - r = -EBADMSG; - goto flush; - } - - skb_pull(*skb, 1); - skb_trim(*skb, (*skb)->len - MICROREAD_I2C_FRAME_TAILROOM); - - usleep_range(3000, 6000); - - return 0; - -flush: - if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) - r = -EREMOTEIO; - - usleep_range(3000, 6000); - - return r; -} - -static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id) -{ - struct microread_i2c_phy *phy = phy_id; - struct i2c_client *client; - struct sk_buff *skb = NULL; - int r; - - if (!phy || irq != phy->i2c_dev->irq) { - WARN_ON_ONCE(1); - return IRQ_NONE; - } - - client = phy->i2c_dev; - dev_dbg(&client->dev, "IRQ\n"); - - if (phy->hard_fault != 0) - return IRQ_HANDLED; - - r = microread_i2c_read(phy, &skb); - if (r == -EREMOTEIO) { - phy->hard_fault = r; - - nfc_hci_recv_frame(phy->hdev, NULL); - - return IRQ_HANDLED; - } else if ((r == -ENOMEM) || (r == -EBADMSG)) { - return IRQ_HANDLED; - } - - nfc_hci_recv_frame(phy->hdev, skb); - - return IRQ_HANDLED; -} - -static struct nfc_phy_ops i2c_phy_ops = { - .write = microread_i2c_write, - .enable = microread_i2c_enable, - .disable = microread_i2c_disable, -}; - -static int microread_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct microread_i2c_phy *phy; - struct microread_nfc_platform_data *pdata = - dev_get_platdata(&client->dev); - int r; - - dev_dbg(&client->dev, "client %p", client); - - if (!pdata) { - dev_err(&client->dev, "client %p: missing platform data", - client); - return -EINVAL; - } - - phy = devm_kzalloc(&client->dev, sizeof(struct microread_i2c_phy), - GFP_KERNEL); - if (!phy) { - dev_err(&client->dev, "Can't allocate microread phy"); - return -ENOMEM; - } - - i2c_set_clientdata(client, phy); - phy->i2c_dev = client; - - r = request_threaded_irq(client->irq, NULL, microread_i2c_irq_thread_fn, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - MICROREAD_I2C_DRIVER_NAME, phy); - if (r) { - dev_err(&client->dev, "Unable to register IRQ handler"); - return r; - } - - r = microread_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, - MICROREAD_I2C_FRAME_HEADROOM, - MICROREAD_I2C_FRAME_TAILROOM, - MICROREAD_I2C_LLC_MAX_PAYLOAD, &phy->hdev); - if (r < 0) - goto err_irq; - - dev_info(&client->dev, "Probed"); - - return 0; - -err_irq: - free_irq(client->irq, phy); - - return r; -} - -static int microread_i2c_remove(struct i2c_client *client) -{ - struct microread_i2c_phy *phy = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "%s\n", __func__); - - microread_remove(phy->hdev); - - free_irq(client->irq, phy); - - return 0; -} - -static struct i2c_device_id microread_i2c_id[] = { - { MICROREAD_I2C_DRIVER_NAME, 0}, - { } -}; -MODULE_DEVICE_TABLE(i2c, microread_i2c_id); - -static struct i2c_driver microread_i2c_driver = { - .driver = { - .name = MICROREAD_I2C_DRIVER_NAME, - }, - .probe = microread_i2c_probe, - .remove = microread_i2c_remove, - .id_table = microread_i2c_id, -}; - -module_i2c_driver(microread_i2c_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/nfc/microread/mei.c b/trunk/drivers/nfc/microread/mei.c deleted file mode 100644 index eef38cfd812e..000000000000 --- a/trunk/drivers/nfc/microread/mei.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * HCI based Driver for Inside Secure microread NFC Chip - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, 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., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "microread.h" - -#define MICROREAD_DRIVER_NAME "microread" - -#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \ - 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c) - -struct mei_nfc_hdr { - u8 cmd; - u8 status; - u16 req_id; - u32 reserved; - u16 data_size; -} __attribute__((packed)); - -#define MEI_NFC_HEADER_SIZE 10 -#define MEI_NFC_MAX_HCI_PAYLOAD 300 -#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) - -struct microread_mei_phy { - struct mei_device *mei_device; - struct nfc_hci_dev *hdev; - - int powered; - - int hard_fault; /* - * < 0 if hardware error occured (e.g. i2c err) - * and prevents normal operation. - */ -}; - -#define MEI_DUMP_SKB_IN(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \ - 16, 1, (skb)->data, (skb)->len, 0); \ -} while (0) - -#define MEI_DUMP_SKB_OUT(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \ - 16, 1, (skb)->data, (skb)->len, 0); \ -} while (0) - -static int microread_mei_enable(void *phy_id) -{ - struct microread_mei_phy *phy = phy_id; - - pr_info(DRIVER_DESC ": %s\n", __func__); - - phy->powered = 1; - - return 0; -} - -static void microread_mei_disable(void *phy_id) -{ - struct microread_mei_phy *phy = phy_id; - - pr_info(DRIVER_DESC ": %s\n", __func__); - - phy->powered = 0; -} - -/* - * Writing a frame must not return the number of written bytes. - * It must return either zero for success, or <0 for error. - * In addition, it must not alter the skb - */ -static int microread_mei_write(void *phy_id, struct sk_buff *skb) -{ - struct microread_mei_phy *phy = phy_id; - int r; - - MEI_DUMP_SKB_OUT("mei frame sent", skb); - - r = mei_send(phy->device, skb->data, skb->len); - if (r > 0) - r = 0; - - return r; -} - -static void microread_event_cb(struct mei_device *device, u32 events, - void *context) -{ - struct microread_mei_phy *phy = context; - - if (phy->hard_fault != 0) - return; - - if (events & BIT(MEI_EVENT_RX)) { - struct sk_buff *skb; - int reply_size; - - skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); - if (!skb) - return; - - reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ); - if (reply_size < MEI_NFC_HEADER_SIZE) { - kfree(skb); - return; - } - - skb_put(skb, reply_size); - skb_pull(skb, MEI_NFC_HEADER_SIZE); - - MEI_DUMP_SKB_IN("mei frame read", skb); - - nfc_hci_recv_frame(phy->hdev, skb); - } -} - -static struct nfc_phy_ops mei_phy_ops = { - .write = microread_mei_write, - .enable = microread_mei_enable, - .disable = microread_mei_disable, -}; - -static int microread_mei_probe(struct mei_device *device, - const struct mei_id *id) -{ - struct microread_mei_phy *phy; - int r; - - pr_info("Probing NFC microread\n"); - - phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL); - if (!phy) { - pr_err("Cannot allocate memory for microread mei phy.\n"); - return -ENOMEM; - } - - phy->device = device; - mei_set_clientdata(device, phy); - - r = mei_register_event_cb(device, microread_event_cb, phy); - if (r) { - pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); - goto err_out; - } - - r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME, - MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, - &phy->hdev); - if (r < 0) - goto err_out; - - return 0; - -err_out: - kfree(phy); - - return r; -} - -static int microread_mei_remove(struct mei_device *device) -{ - struct microread_mei_phy *phy = mei_get_clientdata(device); - - pr_info("Removing microread\n"); - - microread_remove(phy->hdev); - - if (phy->powered) - microread_mei_disable(phy); - - kfree(phy); - - return 0; -} - -static struct mei_id microread_mei_tbl[] = { - { MICROREAD_DRIVER_NAME, MICROREAD_UUID }, - - /* required last entry */ - { } -}; - -MODULE_DEVICE_TABLE(mei, microread_mei_tbl); - -static struct mei_driver microread_driver = { - .id_table = microread_mei_tbl, - .name = MICROREAD_DRIVER_NAME, - - .probe = microread_mei_probe, - .remove = microread_mei_remove, -}; - -static int microread_mei_init(void) -{ - int r; - - pr_debug(DRIVER_DESC ": %s\n", __func__); - - r = mei_driver_register(µread_driver); - if (r) { - pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n"); - return r; - } - - return 0; -} - -static void microread_mei_exit(void) -{ - mei_driver_unregister(µread_driver); -} - -module_init(microread_mei_init); -module_exit(microread_mei_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/nfc/microread/microread.c b/trunk/drivers/nfc/microread/microread.c deleted file mode 100644 index 3420d833db17..000000000000 --- a/trunk/drivers/nfc/microread/microread.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * HCI based Driver for Inside Secure microread NFC Chip - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, 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., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "microread.h" - -/* Proprietary gates, events, commands and registers */ -/* Admin */ -#define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE -#define MICROREAD_GATE_ID_MGT 0x01 -#define MICROREAD_GATE_ID_OS 0x02 -#define MICROREAD_GATE_ID_TESTRF 0x03 -#define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE -#define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE -#define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE - -/* Reader */ -#define MICROREAD_GATE_ID_MREAD_GEN 0x10 -#define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE -#define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12 -#define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE -#define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14 -#define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15 -#define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16 -#define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17 -#define MICROREAD_GATE_ID_MREAD_BPRIME 0x18 -#define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19 - -/* Card */ -#define MICROREAD_GATE_ID_MCARD_GEN 0x20 -#define MICROREAD_GATE_ID_MCARD_ISO_B 0x21 -#define MICROREAD_GATE_ID_MCARD_BPRIME 0x22 -#define MICROREAD_GATE_ID_MCARD_ISO_A 0x23 -#define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24 -#define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25 -#define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26 -#define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27 -#define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28 -#define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F - -/* P2P */ -#define MICROREAD_GATE_ID_P2P_GEN 0x30 -#define MICROREAD_GATE_ID_P2P_TARGET 0x31 -#define MICROREAD_PAR_P2P_TARGET_MODE 0x01 -#define MICROREAD_PAR_P2P_TARGET_GT 0x04 -#define MICROREAD_GATE_ID_P2P_INITIATOR 0x32 -#define MICROREAD_PAR_P2P_INITIATOR_GI 0x01 -#define MICROREAD_PAR_P2P_INITIATOR_GT 0x03 - -/* Those pipes are created/opened by default in the chip */ -#define MICROREAD_PIPE_ID_LMS 0x00 -#define MICROREAD_PIPE_ID_ADMIN 0x01 -#define MICROREAD_PIPE_ID_MGT 0x02 -#define MICROREAD_PIPE_ID_OS 0x03 -#define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04 -#define MICROREAD_PIPE_ID_HDS_IDT 0x05 -#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08 -#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09 -#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A -#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B -#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C -#define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D -#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E -#define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F -#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10 -#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11 -#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12 -#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13 -#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14 -#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15 -#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16 -#define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17 -#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18 -#define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B -#define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C -#define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D -#define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E -#define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F -#define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20 - -/* Events */ -#define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED -#define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D -#define MICROREAD_EMCF_A_ATQA 0 -#define MICROREAD_EMCF_A_SAK 2 -#define MICROREAD_EMCF_A_LEN 3 -#define MICROREAD_EMCF_A_UID 4 -#define MICROREAD_EMCF_A3_ATQA 0 -#define MICROREAD_EMCF_A3_SAK 2 -#define MICROREAD_EMCF_A3_LEN 3 -#define MICROREAD_EMCF_A3_UID 4 -#define MICROREAD_EMCF_B_UID 0 -#define MICROREAD_EMCF_T1_ATQA 0 -#define MICROREAD_EMCF_T1_UID 4 -#define MICROREAD_EMCF_T3_UID 0 -#define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED -#define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E -#define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION -#define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F -#define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED -#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20 -#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21 -#define MICROREAD_EVT_MCARD_FIELD_ON 0x11 -#define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13 -#define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12 -#define MICROREAD_EVT_MCARD_FIELD_OFF 0x14 - -/* Commands */ -#define MICROREAD_CMD_MREAD_EXCHANGE 0x10 -#define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F - -/* Hosts IDs */ -#define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID -#define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID -#define MICROREAD_ELT_ID_SE1 0x03 -#define MICROREAD_ELT_ID_SE2 0x04 -#define MICROREAD_ELT_ID_SE3 0x05 - -static struct nfc_hci_gate microread_gates[] = { - {MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN}, - {MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK}, - {MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT}, - {MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS}, - {MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B}, - {MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A}, - {MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3}, - {MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT}, - {MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS}, - {MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1}, - {MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3}, - {MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET}, - {MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR} -}; - -/* Largest headroom needed for outgoing custom commands */ -#define MICROREAD_CMDS_HEADROOM 2 -#define MICROREAD_CMD_TAILROOM 2 - -struct microread_info { - struct nfc_phy_ops *phy_ops; - void *phy_id; - - struct nfc_hci_dev *hdev; - - int async_cb_type; - data_exchange_cb_t async_cb; - void *async_cb_context; -}; - -static int microread_open(struct nfc_hci_dev *hdev) -{ - struct microread_info *info = nfc_hci_get_clientdata(hdev); - - return info->phy_ops->enable(info->phy_id); -} - -static void microread_close(struct nfc_hci_dev *hdev) -{ - struct microread_info *info = nfc_hci_get_clientdata(hdev); - - info->phy_ops->disable(info->phy_id); -} - -static int microread_hci_ready(struct nfc_hci_dev *hdev) -{ - int r; - u8 param[4]; - - param[0] = 0x03; - r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, - MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL); - if (r) - return r; - - r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3, - MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL); - if (r) - return r; - - param[0] = 0x00; - param[1] = 0x03; - param[2] = 0x00; - r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B, - MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL); - if (r) - return r; - - r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1, - MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL); - if (r) - return r; - - param[0] = 0xFF; - param[1] = 0xFF; - param[2] = 0x00; - param[3] = 0x00; - r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3, - MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL); - - return r; -} - -static int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) -{ - struct microread_info *info = nfc_hci_get_clientdata(hdev); - - return info->phy_ops->write(info->phy_id, skb); -} - -static int microread_start_poll(struct nfc_hci_dev *hdev, - u32 im_protocols, u32 tm_protocols) -{ - int r; - - u8 param[2]; - u8 mode; - - param[0] = 0x00; - param[1] = 0x00; - - if (im_protocols & NFC_PROTO_ISO14443_MASK) - param[0] |= (1 << 2); - - if (im_protocols & NFC_PROTO_ISO14443_B_MASK) - param[0] |= 1; - - if (im_protocols & NFC_PROTO_MIFARE_MASK) - param[1] |= 1; - - if (im_protocols & NFC_PROTO_JEWEL_MASK) - param[0] |= (1 << 1); - - if (im_protocols & NFC_PROTO_FELICA_MASK) - param[0] |= (1 << 5); - - if (im_protocols & NFC_PROTO_NFC_DEP_MASK) - param[1] |= (1 << 1); - - if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { - hdev->gb = nfc_get_local_general_bytes(hdev->ndev, - &hdev->gb_len); - if (hdev->gb == NULL || hdev->gb_len == 0) { - im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; - tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; - } - } - - r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, - MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0); - if (r) - return r; - - mode = 0xff; - r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, - MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); - if (r) - return r; - - if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { - r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR, - MICROREAD_PAR_P2P_INITIATOR_GI, - hdev->gb, hdev->gb_len); - if (r) - return r; - } - - if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { - r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, - MICROREAD_PAR_P2P_TARGET_GT, - hdev->gb, hdev->gb_len); - if (r) - return r; - - mode = 0x02; - r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, - MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); - if (r) - return r; - } - - return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A, - MICROREAD_EVT_MREAD_DISCOVERY_START_SOME, - param, 2); -} - -static int microread_dep_link_up(struct nfc_hci_dev *hdev, - struct nfc_target *target, u8 comm_mode, - u8 *gb, size_t gb_len) -{ - struct sk_buff *rgb_skb = NULL; - int r; - - r = nfc_hci_get_param(hdev, target->hci_reader_gate, - MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb); - if (r < 0) - return r; - - if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) { - r = -EPROTO; - goto exit; - } - - r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data, - rgb_skb->len); - if (r == 0) - r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode, - NFC_RF_INITIATOR); -exit: - kfree_skb(rgb_skb); - - return r; -} - -static int microread_dep_link_down(struct nfc_hci_dev *hdev) -{ - return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR, - MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0); -} - -static int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, - struct nfc_target *target) -{ - switch (gate) { - case MICROREAD_GATE_ID_P2P_INITIATOR: - target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; - break; - default: - return -EPROTO; - } - - return 0; -} - -static int microread_complete_target_discovered(struct nfc_hci_dev *hdev, - u8 gate, - struct nfc_target *target) -{ - return 0; -} - -#define MICROREAD_CB_TYPE_READER_ALL 1 - -static void microread_im_transceive_cb(void *context, struct sk_buff *skb, - int err) -{ - struct microread_info *info = context; - - switch (info->async_cb_type) { - case MICROREAD_CB_TYPE_READER_ALL: - if (err == 0) { - if (skb->len == 0) { - err = -EPROTO; - kfree_skb(skb); - info->async_cb(info->async_cb_context, NULL, - -EPROTO); - return; - } - - if (skb->data[skb->len - 1] != 0) { - err = nfc_hci_result_to_errno( - skb->data[skb->len - 1]); - kfree_skb(skb); - info->async_cb(info->async_cb_context, NULL, - err); - return; - } - - skb_trim(skb, skb->len - 1); /* RF Error ind. */ - } - info->async_cb(info->async_cb_context, skb, err); - break; - default: - if (err == 0) - kfree_skb(skb); - break; - } -} - -/* - * Returns: - * <= 0: driver handled the data exchange - * 1: driver doesn't especially handle, please do standard processing - */ -static int microread_im_transceive(struct nfc_hci_dev *hdev, - struct nfc_target *target, - struct sk_buff *skb, data_exchange_cb_t cb, - void *cb_context) -{ - struct microread_info *info = nfc_hci_get_clientdata(hdev); - u8 control_bits; - u16 crc; - - pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate); - - if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) { - *skb_push(skb, 1) = 0; - - return nfc_hci_send_event(hdev, target->hci_reader_gate, - MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF, - skb->data, skb->len); - } - - switch (target->hci_reader_gate) { - case MICROREAD_GATE_ID_MREAD_ISO_A: - control_bits = 0xCB; - break; - case MICROREAD_GATE_ID_MREAD_ISO_A_3: - control_bits = 0xCB; - break; - case MICROREAD_GATE_ID_MREAD_ISO_B: - control_bits = 0xCB; - break; - case MICROREAD_GATE_ID_MREAD_NFC_T1: - control_bits = 0x1B; - - crc = crc_ccitt(0xffff, skb->data, skb->len); - crc = ~crc; - *skb_put(skb, 1) = crc & 0xff; - *skb_put(skb, 1) = crc >> 8; - break; - case MICROREAD_GATE_ID_MREAD_NFC_T3: - control_bits = 0xDB; - break; - default: - pr_info("Abort im_transceive to invalid gate 0x%x\n", - target->hci_reader_gate); - return 1; - } - - *skb_push(skb, 1) = control_bits; - - info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL; - info->async_cb = cb; - info->async_cb_context = cb_context; - - return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, - MICROREAD_CMD_MREAD_EXCHANGE, - skb->data, skb->len, - microread_im_transceive_cb, info); -} - -static int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) -{ - int r; - - r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET, - MICROREAD_EVT_MCARD_EXCHANGE, - skb->data, skb->len); - - kfree_skb(skb); - - return r; -} - -static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate, - struct sk_buff *skb) -{ - struct nfc_target *targets; - int r = 0; - - pr_info("target discovered to gate 0x%x\n", gate); - - targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL); - if (targets == NULL) { - r = -ENOMEM; - goto exit; - } - - targets->hci_reader_gate = gate; - - switch (gate) { - case MICROREAD_GATE_ID_MREAD_ISO_A: - targets->supported_protocols = - nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]); - targets->sens_res = - be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]); - targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK]; - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID], - skb->data[MICROREAD_EMCF_A_LEN]); - targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN]; - break; - case MICROREAD_GATE_ID_MREAD_ISO_A_3: - targets->supported_protocols = - nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]); - targets->sens_res = - be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]); - targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK]; - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID], - skb->data[MICROREAD_EMCF_A3_LEN]); - targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN]; - break; - case MICROREAD_GATE_ID_MREAD_ISO_B: - targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4); - targets->nfcid1_len = 4; - break; - case MICROREAD_GATE_ID_MREAD_NFC_T1: - targets->supported_protocols = NFC_PROTO_JEWEL_MASK; - targets->sens_res = - le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]); - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4); - targets->nfcid1_len = 4; - break; - case MICROREAD_GATE_ID_MREAD_NFC_T3: - targets->supported_protocols = NFC_PROTO_FELICA_MASK; - memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8); - targets->nfcid1_len = 8; - break; - default: - pr_info("discard target discovered to gate 0x%x\n", gate); - goto exit_free; - } - - r = nfc_targets_found(hdev->ndev, targets, 1); - -exit_free: - kfree(targets); - -exit: - kfree_skb(skb); - - if (r) - pr_err("Failed to handle discovered target err=%d", r); -} - -static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate, - u8 event, struct sk_buff *skb) -{ - int r; - u8 mode; - - pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate); - - switch (event) { - case MICROREAD_EVT_MREAD_CARD_FOUND: - microread_target_discovered(hdev, gate, skb); - return 0; - - case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF: - if (skb->len < 1) { - kfree_skb(skb); - return -EPROTO; - } - - if (skb->data[skb->len - 1]) { - kfree_skb(skb); - return -EIO; - } - - skb_trim(skb, skb->len - 1); - - r = nfc_tm_data_received(hdev->ndev, skb); - break; - - case MICROREAD_EVT_MCARD_FIELD_ON: - case MICROREAD_EVT_MCARD_FIELD_OFF: - kfree_skb(skb); - return 0; - - case MICROREAD_EVT_P2P_TARGET_ACTIVATED: - r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, - NFC_COMM_PASSIVE, skb->data, - skb->len); - - kfree_skb(skb); - break; - - case MICROREAD_EVT_MCARD_EXCHANGE: - if (skb->len < 1) { - kfree_skb(skb); - return -EPROTO; - } - - if (skb->data[skb->len-1]) { - kfree_skb(skb); - return -EIO; - } - - skb_trim(skb, skb->len - 1); - - r = nfc_tm_data_received(hdev->ndev, skb); - break; - - case MICROREAD_EVT_P2P_TARGET_DEACTIVATED: - kfree_skb(skb); - - mode = 0xff; - r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET, - MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1); - if (r) - break; - - r = nfc_hci_send_event(hdev, gate, - MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, - 0); - break; - - default: - return 1; - } - - return r; -} - -static struct nfc_hci_ops microread_hci_ops = { - .open = microread_open, - .close = microread_close, - .hci_ready = microread_hci_ready, - .xmit = microread_xmit, - .start_poll = microread_start_poll, - .dep_link_up = microread_dep_link_up, - .dep_link_down = microread_dep_link_down, - .target_from_gate = microread_target_from_gate, - .complete_target_discovered = microread_complete_target_discovered, - .im_transceive = microread_im_transceive, - .tm_send = microread_tm_send, - .check_presence = NULL, - .event_received = microread_event_received, -}; - -int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, - int phy_headroom, int phy_tailroom, int phy_payload, - struct nfc_hci_dev **hdev) -{ - struct microread_info *info; - unsigned long quirks = 0; - u32 protocols, se; - struct nfc_hci_init_data init_data; - int r; - - info = kzalloc(sizeof(struct microread_info), GFP_KERNEL); - if (!info) { - pr_err("Cannot allocate memory for microread_info.\n"); - r = -ENOMEM; - goto err_info_alloc; - } - - info->phy_ops = phy_ops; - info->phy_id = phy_id; - - init_data.gate_count = ARRAY_SIZE(microread_gates); - memcpy(init_data.gates, microread_gates, sizeof(microread_gates)); - - strcpy(init_data.session_id, "MICROREA"); - - set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks); - - protocols = NFC_PROTO_JEWEL_MASK | - NFC_PROTO_MIFARE_MASK | - NFC_PROTO_FELICA_MASK | - NFC_PROTO_ISO14443_MASK | - NFC_PROTO_ISO14443_B_MASK | - NFC_PROTO_NFC_DEP_MASK; - - se = NFC_SE_UICC | NFC_SE_EMBEDDED; - - info->hdev = nfc_hci_allocate_device(µread_hci_ops, &init_data, - quirks, protocols, se, llc_name, - phy_headroom + - MICROREAD_CMDS_HEADROOM, - phy_tailroom + - MICROREAD_CMD_TAILROOM, - phy_payload); - if (!info->hdev) { - pr_err("Cannot allocate nfc hdev.\n"); - r = -ENOMEM; - goto err_alloc_hdev; - } - - nfc_hci_set_clientdata(info->hdev, info); - - r = nfc_hci_register_device(info->hdev); - if (r) - goto err_regdev; - - *hdev = info->hdev; - - return 0; - -err_regdev: - nfc_hci_free_device(info->hdev); - -err_alloc_hdev: - kfree(info); - -err_info_alloc: - return r; -} -EXPORT_SYMBOL(microread_probe); - -void microread_remove(struct nfc_hci_dev *hdev) -{ - struct microread_info *info = nfc_hci_get_clientdata(hdev); - - nfc_hci_unregister_device(hdev); - nfc_hci_free_device(hdev); - kfree(info); -} -EXPORT_SYMBOL(microread_remove); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/nfc/microread/microread.h b/trunk/drivers/nfc/microread/microread.h deleted file mode 100644 index 64b447a1c5bf..000000000000 --- a/trunk/drivers/nfc/microread/microread.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2011 - 2012 Intel Corporation. All rights reserved. - * - * 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. - */ - -#ifndef __LOCAL_MICROREAD_H_ -#define __LOCAL_MICROREAD_H_ - -#include - -#define DRIVER_DESC "NFC driver for microread" - -int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, - int phy_headroom, int phy_tailroom, int phy_payload, - struct nfc_hci_dev **hdev); - -void microread_remove(struct nfc_hci_dev *hdev); - -#endif /* __LOCAL_MICROREAD_H_ */ diff --git a/trunk/drivers/nfc/pn533.c b/trunk/drivers/nfc/pn533.c index f0f6763d67ae..f696318cfb51 100644 --- a/trunk/drivers/nfc/pn533.c +++ b/trunk/drivers/nfc/pn533.c @@ -219,7 +219,7 @@ struct pn533_poll_modulations { u8 len; }; -static const struct pn533_poll_modulations poll_mod[] = { +const struct pn533_poll_modulations poll_mod[] = { [PN533_POLL_MOD_106KBPS_A] = { .data = { .maxtg = 1, @@ -485,7 +485,7 @@ static u8 pn533_get_cmd_code(void *frame) return PN533_FRAME_CMD(f); } -static struct pn533_frame_ops pn533_std_frame_ops = { +struct pn533_frame_ops pn533_std_frame_ops = { .tx_frame_init = pn533_tx_frame_init, .tx_frame_finish = pn533_tx_frame_finish, .tx_update_payload_len = pn533_tx_update_payload_len, @@ -532,6 +532,7 @@ static void pn533_recv_response(struct urb *urb) urb->status); dev->wq_in_error = urb->status; goto sched_wq; + break; case -ESHUTDOWN: default: nfc_dev_err(&dev->interface->dev, @@ -588,6 +589,7 @@ static void pn533_recv_ack(struct urb *urb) urb->status); dev->wq_in_error = urb->status; goto sched_wq; + break; case -ESHUTDOWN: default: nfc_dev_err(&dev->interface->dev, @@ -1378,7 +1380,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) return NULL; /* DEP support only */ - *skb_put(skb, 1) = PN533_INIT_TARGET_DEP; + *skb_put(skb, 1) |= PN533_INIT_TARGET_DEP; /* MIFARE params */ memcpy(skb_put(skb, 6), mifare_params, 6); diff --git a/trunk/drivers/ssb/driver_gpio.c b/trunk/drivers/ssb/driver_gpio.c index accabe39b320..97ac0a38e3d0 100644 --- a/trunk/drivers/ssb/driver_gpio.c +++ b/trunk/drivers/ssb/driver_gpio.c @@ -74,16 +74,6 @@ static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio) ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); } -static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) -{ - struct ssb_bus *bus = ssb_gpio_get_bus(chip); - - if (bus->bustype == SSB_BUSTYPE_SSB) - return ssb_mips_irq(bus->chipco.dev) + 2; - else - return -EINVAL; -} - static int ssb_gpio_chipco_init(struct ssb_bus *bus) { struct gpio_chip *chip = &bus->gpio; @@ -96,7 +86,6 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus) chip->set = ssb_gpio_chipco_set_value; chip->direction_input = ssb_gpio_chipco_direction_input; chip->direction_output = ssb_gpio_chipco_direction_output; - chip->to_irq = ssb_gpio_chipco_to_irq; chip->ngpio = 16; /* There is just one SoC in one device and its GPIO addresses should be * deterministic to address them more easily. The other buses could get @@ -145,16 +134,6 @@ static int ssb_gpio_extif_direction_output(struct gpio_chip *chip, return 0; } -static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) -{ - struct ssb_bus *bus = ssb_gpio_get_bus(chip); - - if (bus->bustype == SSB_BUSTYPE_SSB) - return ssb_mips_irq(bus->extif.dev) + 2; - else - return -EINVAL; -} - static int ssb_gpio_extif_init(struct ssb_bus *bus) { struct gpio_chip *chip = &bus->gpio; @@ -165,7 +144,6 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) chip->set = ssb_gpio_extif_set_value; chip->direction_input = ssb_gpio_extif_direction_input; chip->direction_output = ssb_gpio_extif_direction_output; - chip->to_irq = ssb_gpio_extif_to_irq; chip->ngpio = 5; /* There is just one SoC in one device and its GPIO addresses should be * deterministic to address them more easily. The other buses could get diff --git a/trunk/drivers/ssb/driver_mipscore.c b/trunk/drivers/ssb/driver_mipscore.c index 33b37dac40bd..2a7684c90243 100644 --- a/trunk/drivers/ssb/driver_mipscore.c +++ b/trunk/drivers/ssb/driver_mipscore.c @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -18,25 +17,6 @@ #include "ssb_private.h" -static const char *part_probes[] = { "bcm47xxpart", NULL }; - -static struct physmap_flash_data ssb_pflash_data = { - .part_probe_types = part_probes, -}; - -static struct resource ssb_pflash_resource = { - .name = "ssb_pflash", - .flags = IORESOURCE_MEM, -}; - -struct platform_device ssb_pflash_dev = { - .name = "physmap-flash", - .dev = { - .platform_data = &ssb_pflash_data, - }, - .resource = &ssb_pflash_resource, - .num_resources = 1, -}; static inline u32 mips_read32(struct ssb_mipscore *mcore, u16 offset) @@ -209,15 +189,14 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore) static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) { struct ssb_bus *bus = mcore->dev->bus; - struct ssb_pflash *pflash = &mcore->pflash; /* When there is no chipcommon on the bus there is 4MB flash */ if (!ssb_chipco_available(&bus->chipco)) { - pflash->present = true; - pflash->buswidth = 2; - pflash->window = SSB_FLASH1; - pflash->window_size = SSB_FLASH1_SZ; - goto ssb_pflash; + mcore->pflash.present = true; + mcore->pflash.buswidth = 2; + mcore->pflash.window = SSB_FLASH1; + mcore->pflash.window_size = SSB_FLASH1_SZ; + return; } /* There is ChipCommon, so use it to read info about flash */ @@ -229,23 +208,16 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) break; case SSB_CHIPCO_FLASHT_PARA: pr_debug("Found parallel flash\n"); - pflash->present = true; - pflash->window = SSB_FLASH2; - pflash->window_size = SSB_FLASH2_SZ; + mcore->pflash.present = true; + mcore->pflash.window = SSB_FLASH2; + mcore->pflash.window_size = SSB_FLASH2_SZ; if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) & SSB_CHIPCO_CFG_DS16) == 0) - pflash->buswidth = 1; + mcore->pflash.buswidth = 1; else - pflash->buswidth = 2; + mcore->pflash.buswidth = 2; break; } - -ssb_pflash: - if (pflash->present) { - ssb_pflash_data.width = pflash->buswidth; - ssb_pflash_resource.start = pflash->window; - ssb_pflash_resource.end = pflash->window + pflash->window_size; - } } u32 ssb_cpu_clock(struct ssb_mipscore *mcore) diff --git a/trunk/drivers/ssb/main.c b/trunk/drivers/ssb/main.c index db7705743a8f..c82c5c95fe85 100644 --- a/trunk/drivers/ssb/main.c +++ b/trunk/drivers/ssb/main.c @@ -540,14 +540,6 @@ static int ssb_devices_register(struct ssb_bus *bus) dev_idx++; } -#ifdef CONFIG_SSB_DRIVER_MIPS - if (bus->mipscore.pflash.present) { - err = platform_device_register(&ssb_pflash_dev); - if (err) - pr_err("Error registering parallel flash\n"); - } -#endif - return 0; error: /* Unwind the already registered devices. */ diff --git a/trunk/drivers/ssb/ssb_private.h b/trunk/drivers/ssb/ssb_private.h index 53198dcec90e..77d942630750 100644 --- a/trunk/drivers/ssb/ssb_private.h +++ b/trunk/drivers/ssb/ssb_private.h @@ -228,10 +228,6 @@ static inline int ssb_sflash_init(struct ssb_chipcommon *cc) } #endif /* CONFIG_SSB_SFLASH */ -#ifdef CONFIG_SSB_DRIVER_MIPS -extern struct platform_device ssb_pflash_dev; -#endif - #ifdef CONFIG_SSB_DRIVER_EXTIF extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); diff --git a/trunk/include/linux/bcma/bcma_driver_chipcommon.h b/trunk/include/linux/bcma/bcma_driver_chipcommon.h index 6a299f416288..9a0e3fa3ca95 100644 --- a/trunk/include/linux/bcma/bcma_driver_chipcommon.h +++ b/trunk/include/linux/bcma/bcma_driver_chipcommon.h @@ -27,7 +27,7 @@ #define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */ #define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */ #define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ -#define BCMA_CC_FLASHT_NAND 0x00000300 /* NAND flash */ +#define BCMA_CC_FLASHT_NFLASH 0x00000200 /* NAND flash */ #define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */ #define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */ #define BCMA_PLLTYPE_NONE 0x00000000 diff --git a/trunk/include/linux/bcma/bcma_driver_mips.h b/trunk/include/linux/bcma/bcma_driver_mips.h index fb61f3fb4ddb..0d1ea297851a 100644 --- a/trunk/include/linux/bcma/bcma_driver_mips.h +++ b/trunk/include/linux/bcma/bcma_driver_mips.h @@ -42,18 +42,13 @@ struct bcma_drv_mips { #ifdef CONFIG_BCMA_DRIVER_MIPS extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); - -extern unsigned int bcma_core_irq(struct bcma_device *core); #else static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { } - -static inline unsigned int bcma_core_irq(struct bcma_device *core) -{ - return 0; -} #endif extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore); +extern unsigned int bcma_core_irq(struct bcma_device *core); + #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */ diff --git a/trunk/include/linux/platform_data/microread.h b/trunk/include/linux/platform_data/microread.h deleted file mode 100644 index cfda59b226ee..000000000000 --- a/trunk/include/linux/platform_data/microread.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Driver include for the PN544 NFC chip. - * - * Copyright (C) 2011 Tieto Poland - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _MICROREAD_H -#define _MICROREAD_H - -#include - -#define MICROREAD_DRIVER_NAME "microread" - -/* board config platform data for microread */ -struct microread_nfc_platform_data { - unsigned int rst_gpio; - unsigned int irq_gpio; - unsigned int ioh_gpio; -}; - -#endif /* _MICROREAD_H */ diff --git a/trunk/include/linux/ssb/ssb_driver_mips.h b/trunk/include/linux/ssb/ssb_driver_mips.h index afe79d40a99e..07a9c7a2e088 100644 --- a/trunk/include/linux/ssb/ssb_driver_mips.h +++ b/trunk/include/linux/ssb/ssb_driver_mips.h @@ -45,11 +45,6 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) { } -static inline unsigned int ssb_mips_irq(struct ssb_device *dev) -{ - return 0; -} - #endif /* CONFIG_SSB_DRIVER_MIPS */ #endif /* LINUX_SSB_MIPSCORE_H_ */ diff --git a/trunk/include/linux/wl12xx.h b/trunk/include/linux/wl12xx.h index a54fe82e704b..0d6373195d32 100644 --- a/trunk/include/linux/wl12xx.h +++ b/trunk/include/linux/wl12xx.h @@ -24,8 +24,6 @@ #ifndef _LINUX_WL12XX_H #define _LINUX_WL12XX_H -#include - /* Reference clock values */ enum { WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ @@ -57,17 +55,17 @@ struct wl12xx_platform_data { int board_tcxo_clock; unsigned long platform_quirks; bool pwr_in_suspend; + + struct wl1271_if_operations *ops; }; /* Platform does not support level trigger interrupts */ #define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) -#ifdef CONFIG_WILINK_PLATFORM_DATA +#ifdef CONFIG_WL12XX_PLATFORM_DATA int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); -struct wl12xx_platform_data *wl12xx_get_platform_data(void); - #else static inline @@ -76,12 +74,8 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data) return -ENOSYS; } -static inline -struct wl12xx_platform_data *wl12xx_get_platform_data(void) -{ - return ERR_PTR(-ENODATA); -} - #endif +struct wl12xx_platform_data *wl12xx_get_platform_data(void); + #endif diff --git a/trunk/include/net/bluetooth/a2mp.h b/trunk/include/net/bluetooth/a2mp.h index 487b54c1308f..42f21766c538 100644 --- a/trunk/include/net/bluetooth/a2mp.h +++ b/trunk/include/net/bluetooth/a2mp.h @@ -23,7 +23,6 @@ enum amp_mgr_state { READ_LOC_AMP_INFO, READ_LOC_AMP_ASSOC, READ_LOC_AMP_ASSOC_FINAL, - WRITE_REMOTE_AMP_ASSOC, }; struct amp_mgr { @@ -34,7 +33,7 @@ struct amp_mgr { struct kref kref; __u8 ident; __u8 handle; - unsigned long state; + enum amp_mgr_state state; unsigned long flags; struct list_head amp_ctrls; @@ -145,6 +144,5 @@ void a2mp_discover_amp(struct l2cap_chan *chan); void a2mp_send_getinfo_rsp(struct hci_dev *hdev); void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status); -void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status); #endif /* __A2MP_H */ diff --git a/trunk/include/net/bluetooth/bluetooth.h b/trunk/include/net/bluetooth/bluetooth.h index 9531beee09b5..2554b3f5222a 100644 --- a/trunk/include/net/bluetooth/bluetooth.h +++ b/trunk/include/net/bluetooth/bluetooth.h @@ -166,29 +166,6 @@ typedef struct { #define BDADDR_LE_PUBLIC 0x01 #define BDADDR_LE_RANDOM 0x02 -static inline bool bdaddr_type_is_valid(__u8 type) -{ - switch (type) { - case BDADDR_BREDR: - case BDADDR_LE_PUBLIC: - case BDADDR_LE_RANDOM: - return true; - } - - return false; -} - -static inline bool bdaddr_type_is_le(__u8 type) -{ - switch (type) { - case BDADDR_LE_PUBLIC: - case BDADDR_LE_RANDOM: - return true; - } - - return false; -} - #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} }) #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} }) diff --git a/trunk/include/net/bluetooth/hci.h b/trunk/include/net/bluetooth/hci.h index 7f12c25f1fca..45eee08157bb 100644 --- a/trunk/include/net/bluetooth/hci.h +++ b/trunk/include/net/bluetooth/hci.h @@ -943,12 +943,6 @@ struct hci_rp_le_read_buffer_size { __u8 le_max_pkt; } __packed; -#define HCI_OP_LE_READ_LOCAL_FEATURES 0x2003 -struct hci_rp_le_read_local_features { - __u8 status; - __u8 features[8]; -} __packed; - #define HCI_OP_LE_READ_ADV_TX_POWER 0x2007 struct hci_rp_le_read_adv_tx_power { __u8 status; @@ -1001,12 +995,6 @@ struct hci_cp_le_create_conn { #define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e -#define HCI_OP_LE_READ_WHITE_LIST_SIZE 0x200f -struct hci_rp_le_read_white_list_size { - __u8 status; - __u8 size; -} __packed; - #define HCI_OP_LE_CONN_UPDATE 0x2013 struct hci_cp_le_conn_update { __le16 handle; @@ -1045,12 +1033,6 @@ struct hci_rp_le_ltk_neg_reply { __le16 handle; } __packed; -#define HCI_OP_LE_READ_SUPPORTED_STATES 0x201c -struct hci_rp_le_read_supported_states { - __u8 status; - __u8 le_states[8]; -} __packed; - /* ---- HCI Events ---- */ #define HCI_EV_INQUIRY_COMPLETE 0x01 diff --git a/trunk/include/net/bluetooth/hci_core.h b/trunk/include/net/bluetooth/hci_core.h index 90cf75afcb02..014a2eaa5389 100644 --- a/trunk/include/net/bluetooth/hci_core.h +++ b/trunk/include/net/bluetooth/hci_core.h @@ -86,7 +86,6 @@ struct bdaddr_list { struct bt_uuid { struct list_head list; u8 uuid[16]; - u8 size; u8 svc_hint; }; @@ -153,9 +152,6 @@ struct hci_dev { __u8 minor_class; __u8 features[8]; __u8 host_features[8]; - __u8 le_features[8]; - __u8 le_white_list_size; - __u8 le_states[8]; __u8 commands[64]; __u8 hci_ver; __u16 hci_rev; @@ -220,7 +216,6 @@ struct hci_dev { unsigned long le_last_tx; struct workqueue_struct *workqueue; - struct workqueue_struct *req_workqueue; struct work_struct power_on; struct delayed_work power_off; diff --git a/trunk/include/net/bluetooth/l2cap.h b/trunk/include/net/bluetooth/l2cap.h index cdd33021f831..7588ef44ebaf 100644 --- a/trunk/include/net/bluetooth/l2cap.h +++ b/trunk/include/net/bluetooth/l2cap.h @@ -496,6 +496,7 @@ struct l2cap_chan { __u16 frames_sent; __u16 unacked_frames; __u8 retry_count; + __u16 srej_queue_next; __u16 sdu_len; struct sk_buff *sdu; struct sk_buff *sdu_last_frag; diff --git a/trunk/net/bluetooth/a2mp.c b/trunk/net/bluetooth/a2mp.c index eb0f4b16ff09..2f67d5ecc907 100644 --- a/trunk/net/bluetooth/a2mp.c +++ b/trunk/net/bluetooth/a2mp.c @@ -290,7 +290,7 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, goto done; } - set_bit(READ_LOC_AMP_INFO, &mgr->state); + mgr->state = READ_LOC_AMP_INFO; hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); done: @@ -499,16 +499,8 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, if (hdev) hci_dev_put(hdev); - /* Reply error now and success after HCI Write Remote AMP Assoc - command complete with success status - */ - if (rsp.status != A2MP_STATUS_SUCCESS) { - a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, - sizeof(rsp), &rsp); - } else { - set_bit(WRITE_REMOTE_AMP_ASSOC, &mgr->state); - mgr->ident = hdr->ident; - } + a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp), + &rsp); skb_pull(skb, le16_to_cpu(hdr->len)); return 0; @@ -848,7 +840,7 @@ struct amp_mgr *amp_mgr_lookup_by_state(u8 state) mutex_lock(&_mgr_list_lock); list_for_each_entry(mgr, &_mgr_list, list) { - if (test_and_clear_bit(state, &mgr->state)) { + if (mgr->state == state) { amp_mgr_get(mgr); mutex_unlock(&_mgr_list_lock); return mgr; @@ -957,32 +949,6 @@ void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status) kfree(req); } -void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status) -{ - struct amp_mgr *mgr; - struct a2mp_physlink_rsp rsp; - struct hci_conn *hs_hcon; - - mgr = amp_mgr_lookup_by_state(WRITE_REMOTE_AMP_ASSOC); - if (!mgr) - return; - - hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT); - if (!hs_hcon) { - rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; - } else { - rsp.remote_id = hs_hcon->remote_id; - rsp.status = A2MP_STATUS_SUCCESS; - } - - BT_DBG("%s mgr %p hs_hcon %p status %u", hdev->name, mgr, hs_hcon, - status); - - rsp.local_id = hdev->id; - a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, mgr->ident, sizeof(rsp), &rsp); - amp_mgr_put(mgr); -} - void a2mp_discover_amp(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; diff --git a/trunk/net/bluetooth/amp.c b/trunk/net/bluetooth/amp.c index d459ed43c779..1b0d92c0643a 100644 --- a/trunk/net/bluetooth/amp.c +++ b/trunk/net/bluetooth/amp.c @@ -236,7 +236,7 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) cp.max_len = cpu_to_le16(hdev->amp_assoc_size); - set_bit(READ_LOC_AMP_ASSOC, &mgr->state); + mgr->state = READ_LOC_AMP_ASSOC; hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); } @@ -250,7 +250,7 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev, cp.len_so_far = cpu_to_le16(0); cp.max_len = cpu_to_le16(hdev->amp_assoc_size); - set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state); + mgr->state = READ_LOC_AMP_ASSOC_FINAL; /* Read Local AMP Assoc final link information data */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); @@ -317,9 +317,7 @@ void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle) if (!hcon) return; - /* Send A2MP create phylink rsp when all fragments are written */ - if (amp_write_rem_assoc_frag(hdev, hcon)) - a2mp_send_create_phy_link_rsp(hdev, 0); + amp_write_rem_assoc_frag(hdev, hcon); } void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) @@ -405,20 +403,26 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) void amp_create_logical_link(struct l2cap_chan *chan) { - struct hci_conn *hs_hcon = chan->hs_hcon; struct hci_cp_create_accept_logical_link cp; + struct hci_conn *hcon; struct hci_dev *hdev; - BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon, chan->conn->dst); + BT_DBG("chan %p", chan); - if (!hs_hcon) + if (!chan->hs_hcon) return; hdev = hci_dev_hold(chan->hs_hcon->hdev); if (!hdev) return; - cp.phy_handle = hs_hcon->handle; + BT_DBG("chan %p dst %pMR", chan, chan->conn->dst); + + hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst); + if (!hcon) + goto done; + + cp.phy_handle = hcon->handle; cp.tx_flow_spec.id = chan->local_id; cp.tx_flow_spec.stype = chan->local_stype; @@ -434,13 +438,14 @@ void amp_create_logical_link(struct l2cap_chan *chan) cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); - if (hs_hcon->out) + if (hcon->out) hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), &cp); else hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), &cp); +done: hci_dev_put(hdev); } diff --git a/trunk/net/bluetooth/bnep/core.c b/trunk/net/bluetooth/bnep/core.c index e430b1abcd2f..a5b639702637 100644 --- a/trunk/net/bluetooth/bnep/core.c +++ b/trunk/net/bluetooth/bnep/core.c @@ -33,6 +33,7 @@ #include #include +#include #include "bnep.h" diff --git a/trunk/net/bluetooth/hci_core.c b/trunk/net/bluetooth/hci_core.c index 22e77a786545..0f78e34220c9 100644 --- a/trunk/net/bluetooth/hci_core.c +++ b/trunk/net/bluetooth/hci_core.c @@ -1146,8 +1146,7 @@ static void hci_power_on(struct work_struct *work) return; if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - queue_delayed_work(hdev->req_workqueue, &hdev->power_off, - HCI_AUTO_OFF_TIMEOUT); + schedule_delayed_work(&hdev->power_off, HCI_AUTO_OFF_TIMEOUT); if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) mgmt_index_added(hdev); @@ -1183,10 +1182,14 @@ static void hci_discov_off(struct work_struct *work) int hci_uuids_clear(struct hci_dev *hdev) { - struct bt_uuid *uuid, *tmp; + struct list_head *p, *n; + + list_for_each_safe(p, n, &hdev->uuids) { + struct bt_uuid *uuid; - list_for_each_entry_safe(uuid, tmp, &hdev->uuids, list) { - list_del(&uuid->list); + uuid = list_entry(p, struct bt_uuid, list); + + list_del(p); kfree(uuid); } @@ -1618,8 +1621,8 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, if (err < 0) return err; - queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, - msecs_to_jiffies(timeout)); + schedule_delayed_work(&hdev->le_scan_disable, + msecs_to_jiffies(timeout)); return 0; } @@ -1796,15 +1799,6 @@ int hci_register_dev(struct hci_dev *hdev) goto err; } - hdev->req_workqueue = alloc_workqueue(hdev->name, - WQ_HIGHPRI | WQ_UNBOUND | - WQ_MEM_RECLAIM, 1); - if (!hdev->req_workqueue) { - destroy_workqueue(hdev->workqueue); - error = -ENOMEM; - goto err; - } - error = hci_add_sysfs(hdev); if (error < 0) goto err_wqueue; @@ -1827,13 +1821,12 @@ int hci_register_dev(struct hci_dev *hdev) hci_notify(hdev, HCI_DEV_REG); hci_dev_hold(hdev); - queue_work(hdev->req_workqueue, &hdev->power_on); + schedule_work(&hdev->power_on); return id; err_wqueue: destroy_workqueue(hdev->workqueue); - destroy_workqueue(hdev->req_workqueue); err: ida_simple_remove(&hci_index_ida, hdev->id); write_lock(&hci_dev_list_lock); @@ -1887,7 +1880,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_del_sysfs(hdev); destroy_workqueue(hdev->workqueue); - destroy_workqueue(hdev->req_workqueue); hci_dev_lock(hdev); hci_blacklist_clear(hdev); diff --git a/trunk/net/bluetooth/hci_event.c b/trunk/net/bluetooth/hci_event.c index 477726a63512..81b44481d0d9 100644 --- a/trunk/net/bluetooth/hci_event.c +++ b/trunk/net/bluetooth/hci_event.c @@ -609,17 +609,8 @@ static void le_setup(struct hci_dev *hdev) /* Read LE Buffer Size */ hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); - /* Read LE Local Supported Features */ - hci_send_cmd(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL); - /* Read LE Advertising Channel TX Power */ hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); - - /* Read LE White List Size */ - hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); - - /* Read LE Supported States */ - hci_send_cmd(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); } static void hci_setup(struct hci_dev *hdev) @@ -1099,19 +1090,6 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); } -static void hci_cc_le_read_local_features(struct hci_dev *hdev, - struct sk_buff *skb) -{ - struct hci_rp_le_read_local_features *rp = (void *) skb->data; - - BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - - if (!rp->status) - memcpy(hdev->le_features, rp->features, 8); - - hci_req_complete(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, rp->status); -} - static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, struct sk_buff *skb) { @@ -1312,19 +1290,6 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, } } -static void hci_cc_le_read_white_list_size(struct hci_dev *hdev, - struct sk_buff *skb) -{ - struct hci_rp_le_read_white_list_size *rp = (void *) skb->data; - - BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size); - - if (!rp->status) - hdev->le_white_list_size = rp->size; - - hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status); -} - static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_le_ltk_reply *rp = (void *) skb->data; @@ -1349,19 +1314,6 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); } -static void hci_cc_le_read_supported_states(struct hci_dev *hdev, - struct sk_buff *skb) -{ - struct hci_rp_le_read_supported_states *rp = (void *) skb->data; - - BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - - if (!rp->status) - memcpy(hdev->le_states, rp->le_states, 8); - - hci_req_complete(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, rp->status); -} - static void hci_cc_write_le_host_supported(struct hci_dev *hdev, struct sk_buff *skb) { @@ -2676,10 +2628,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_le_read_buffer_size(hdev, skb); break; - case HCI_OP_LE_READ_LOCAL_FEATURES: - hci_cc_le_read_local_features(hdev, skb); - break; - case HCI_OP_LE_READ_ADV_TX_POWER: hci_cc_le_read_adv_tx_power(hdev, skb); break; @@ -2716,10 +2664,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_le_set_scan_enable(hdev, skb); break; - case HCI_OP_LE_READ_WHITE_LIST_SIZE: - hci_cc_le_read_white_list_size(hdev, skb); - break; - case HCI_OP_LE_LTK_REPLY: hci_cc_le_ltk_reply(hdev, skb); break; @@ -2728,10 +2672,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_le_ltk_neg_reply(hdev, skb); break; - case HCI_OP_LE_READ_SUPPORTED_STATES: - hci_cc_le_read_supported_states(hdev, skb); - break; - case HCI_OP_WRITE_LE_HOST_SUPPORTED: hci_cc_write_le_host_supported(hdev, skb); break; @@ -3988,6 +3928,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) void *ptr = &skb->data[1]; s8 rssi; + hci_dev_lock(hdev); + while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; @@ -3997,6 +3939,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) ptr += sizeof(*ev) + ev->length + 1; } + + hci_dev_unlock(hdev); } static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/trunk/net/bluetooth/hci_sysfs.c b/trunk/net/bluetooth/hci_sysfs.c index 23b4e242a31a..55cceee02a84 100644 --- a/trunk/net/bluetooth/hci_sysfs.c +++ b/trunk/net/bluetooth/hci_sysfs.c @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -462,18 +461,19 @@ static const struct file_operations blacklist_fops = { static void print_bt_uuid(struct seq_file *f, u8 *uuid) { - u32 data0, data5; - u16 data1, data2, data3, data4; + __be32 data0, data4; + __be16 data1, data2, data3, data5; - data5 = get_unaligned_le32(uuid); - data4 = get_unaligned_le16(uuid + 4); - data3 = get_unaligned_le16(uuid + 6); - data2 = get_unaligned_le16(uuid + 8); - data1 = get_unaligned_le16(uuid + 10); - data0 = get_unaligned_le32(uuid + 12); + memcpy(&data0, &uuid[0], 4); + memcpy(&data1, &uuid[4], 2); + memcpy(&data2, &uuid[6], 2); + memcpy(&data3, &uuid[8], 2); + memcpy(&data4, &uuid[10], 4); + memcpy(&data5, &uuid[14], 2); - seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.4x%.8x\n", - data0, data1, data2, data3, data4, data5); + seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n", + ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3), + ntohl(data4), ntohs(data5)); } static int uuids_show(struct seq_file *f, void *p) diff --git a/trunk/net/bluetooth/l2cap_core.c b/trunk/net/bluetooth/l2cap_core.c index 7c7e9321f1ea..22e658322845 100644 --- a/trunk/net/bluetooth/l2cap_core.c +++ b/trunk/net/bluetooth/l2cap_core.c @@ -1527,12 +1527,17 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); switch (hcon->type) { + case AMP_LINK: + conn->mtu = hcon->hdev->block_mtu; + break; + case LE_LINK: if (hcon->hdev->le_mtu) { conn->mtu = hcon->hdev->le_mtu; break; } /* fall through */ + default: conn->mtu = hcon->hdev->acl_mtu; break; diff --git a/trunk/net/bluetooth/mgmt.c b/trunk/net/bluetooth/mgmt.c index 39395c7144aa..f559b966279c 100644 --- a/trunk/net/bluetooth/mgmt.c +++ b/trunk/net/bluetooth/mgmt.c @@ -35,7 +35,7 @@ bool enable_hs; #define MGMT_VERSION 1 -#define MGMT_REVISION 3 +#define MGMT_REVISION 2 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, @@ -435,117 +435,35 @@ static u32 get_current_settings(struct hci_dev *hdev) #define PNP_INFO_SVCLASS_ID 0x1200 -static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) -{ - u8 *ptr = data, *uuids_start = NULL; - struct bt_uuid *uuid; - - if (len < 4) - return ptr; - - list_for_each_entry(uuid, &hdev->uuids, list) { - u16 uuid16; - - if (uuid->size != 16) - continue; - - uuid16 = get_unaligned_le16(&uuid->uuid[12]); - if (uuid16 < 0x1100) - continue; - - if (uuid16 == PNP_INFO_SVCLASS_ID) - continue; - - if (!uuids_start) { - uuids_start = ptr; - uuids_start[0] = 1; - uuids_start[1] = EIR_UUID16_ALL; - ptr += 2; - } - - /* Stop if not enough space to put next UUID */ - if ((ptr - data) + sizeof(u16) > len) { - uuids_start[1] = EIR_UUID16_SOME; - break; - } - - *ptr++ = (uuid16 & 0x00ff); - *ptr++ = (uuid16 & 0xff00) >> 8; - uuids_start[0] += sizeof(uuid16); - } - - return ptr; -} +static u8 bluetooth_base_uuid[] = { + 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; -static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) +static u16 get_uuid16(u8 *uuid128) { - u8 *ptr = data, *uuids_start = NULL; - struct bt_uuid *uuid; - - if (len < 6) - return ptr; - - list_for_each_entry(uuid, &hdev->uuids, list) { - if (uuid->size != 32) - continue; - - if (!uuids_start) { - uuids_start = ptr; - uuids_start[0] = 1; - uuids_start[1] = EIR_UUID32_ALL; - ptr += 2; - } - - /* Stop if not enough space to put next UUID */ - if ((ptr - data) + sizeof(u32) > len) { - uuids_start[1] = EIR_UUID32_SOME; - break; - } + u32 val; + int i; - memcpy(ptr, &uuid->uuid[12], sizeof(u32)); - ptr += sizeof(u32); - uuids_start[0] += sizeof(u32); + for (i = 0; i < 12; i++) { + if (bluetooth_base_uuid[i] != uuid128[i]) + return 0; } - return ptr; -} - -static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) -{ - u8 *ptr = data, *uuids_start = NULL; - struct bt_uuid *uuid; - - if (len < 18) - return ptr; - - list_for_each_entry(uuid, &hdev->uuids, list) { - if (uuid->size != 128) - continue; - - if (!uuids_start) { - uuids_start = ptr; - uuids_start[0] = 1; - uuids_start[1] = EIR_UUID128_ALL; - ptr += 2; - } - - /* Stop if not enough space to put next UUID */ - if ((ptr - data) + 16 > len) { - uuids_start[1] = EIR_UUID128_SOME; - break; - } - - memcpy(ptr, uuid->uuid, 16); - ptr += 16; - uuids_start[0] += 16; - } + val = get_unaligned_le32(&uuid128[12]); + if (val > 0xffff) + return 0; - return ptr; + return (u16) val; } static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; + u16 eir_len = 0; + u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; + int i, truncated = 0; + struct bt_uuid *uuid; size_t name_len; name_len = strlen(hdev->dev_name); @@ -563,6 +481,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) memcpy(ptr + 2, hdev->dev_name, name_len); + eir_len += (name_len + 2); ptr += (name_len + 2); } @@ -571,6 +490,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr[1] = EIR_TX_POWER; ptr[2] = (u8) hdev->inq_tx_power; + eir_len += 3; ptr += 3; } @@ -583,12 +503,60 @@ static void create_eir(struct hci_dev *hdev, u8 *data) put_unaligned_le16(hdev->devid_product, ptr + 6); put_unaligned_le16(hdev->devid_version, ptr + 8); + eir_len += 10; ptr += 10; } - ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); - ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); - ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); + memset(uuid16_list, 0, sizeof(uuid16_list)); + + /* Group all UUID16 types */ + list_for_each_entry(uuid, &hdev->uuids, list) { + u16 uuid16; + + uuid16 = get_uuid16(uuid->uuid); + if (uuid16 == 0) + return; + + if (uuid16 < 0x1100) + continue; + + if (uuid16 == PNP_INFO_SVCLASS_ID) + continue; + + /* Stop if not enough space to put next UUID */ + if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { + truncated = 1; + break; + } + + /* Check for duplicates */ + for (i = 0; uuid16_list[i] != 0; i++) + if (uuid16_list[i] == uuid16) + break; + + if (uuid16_list[i] == 0) { + uuid16_list[i] = uuid16; + eir_len += sizeof(u16); + } + } + + if (uuid16_list[0] != 0) { + u8 *length = ptr; + + /* EIR Data type */ + ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; + + ptr += 2; + eir_len += 2; + + for (i = 0; uuid16_list[i] != 0; i++) { + *ptr++ = (uuid16_list[i] & 0x00ff); + *ptr++ = (uuid16_list[i] & 0xff00) >> 8; + } + + /* EIR Data length */ + *length = (i * sizeof(u16)) + 1; + } } static int update_eir(struct hci_dev *hdev) @@ -760,9 +728,13 @@ static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, void *data), void *data) { - struct pending_cmd *cmd, *tmp; + struct list_head *p, *n; + + list_for_each_safe(p, n, &hdev->mgmt_pending) { + struct pending_cmd *cmd; + + cmd = list_entry(p, struct pending_cmd, list); - list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { if (opcode > 0 && cmd->opcode != opcode) continue; @@ -805,19 +777,14 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { cancel_delayed_work(&hdev->power_off); if (cp->val) { - mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, - data, len); - err = mgmt_powered(hdev, 1); + err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); + mgmt_powered(hdev, 1); goto failed; } } @@ -840,9 +807,9 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, } if (cp->val) - queue_work(hdev->req_workqueue, &hdev->power_on); + schedule_work(&hdev->power_on); else - queue_work(hdev->req_workqueue, &hdev->power_off.work); + schedule_work(&hdev->power_off.work); err = 0; @@ -905,10 +872,6 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); - timeout = __le16_to_cpu(cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, @@ -1008,10 +971,6 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1082,10 +1041,6 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (cp->val) @@ -1118,10 +1073,6 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1182,16 +1133,14 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (!lmp_ssp_capable(hdev)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_SUPPORTED); - - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); + if (!lmp_ssp_capable(hdev)) { + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + val = !!cp->val; if (!hdev_is_powered(hdev)) { @@ -1250,10 +1199,6 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, - MGMT_STATUS_INVALID_PARAMS); - if (cp->val) set_bit(HCI_HS_ENABLED, &hdev->dev_flags); else @@ -1272,16 +1217,14 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (!lmp_le_capable(hdev)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_NOT_SUPPORTED); - - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); + if (!lmp_le_capable(hdev)) { + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, + MGMT_STATUS_NOT_SUPPORTED); + goto unlock; + } + val = !!cp->val; enabled = lmp_host_le_capable(hdev); @@ -1332,25 +1275,6 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) return err; } -static const u8 bluetooth_base_uuid[] = { - 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static u8 get_uuid_size(const u8 *uuid) -{ - u32 val; - - if (memcmp(uuid, bluetooth_base_uuid, 12)) - return 128; - - val = get_unaligned_le32(&uuid[12]); - if (val > 0xffff) - return 32; - - return 16; -} - static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -1376,9 +1300,8 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) memcpy(uuid->uuid, cp->uuid, 16); uuid->svc_hint = cp->svc_hint; - uuid->size = get_uuid_size(cp->uuid); - list_add_tail(&uuid->list, &hdev->uuids); + list_add(&uuid->list, &hdev->uuids); err = update_class(hdev); if (err < 0) @@ -1409,8 +1332,7 @@ static bool enable_service_cache(struct hci_dev *hdev) return false; if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { - queue_delayed_work(hdev->workqueue, &hdev->service_cache, - CACHE_TIMEOUT); + schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT); return true; } @@ -1422,7 +1344,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_remove_uuid *cp = data; struct pending_cmd *cmd; - struct bt_uuid *match, *tmp; + struct list_head *p, *n; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int err, found; @@ -1450,7 +1372,9 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, found = 0; - list_for_each_entry_safe(match, tmp, &hdev->uuids, list) { + list_for_each_safe(p, n, &hdev->uuids) { + struct bt_uuid *match = list_entry(p, struct bt_uuid, list); + if (memcmp(match->uuid, cp->uuid, 16) != 0) continue; @@ -1498,20 +1422,14 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (!lmp_bredr_capable(hdev)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_NOT_SUPPORTED); - - if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_BUSY); - - if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, + MGMT_STATUS_BUSY); + goto unlock; + } + hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -1565,21 +1483,9 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, MGMT_STATUS_INVALID_PARAMS); } - if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); - BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, key_count); - for (i = 0; i < key_count; i++) { - struct mgmt_link_key_info *key = &cp->keys[i]; - - if (key->addr.type != BDADDR_BREDR) - return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); - } - hci_dev_lock(hdev); hci_link_keys_clear(hdev); @@ -1627,22 +1533,12 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; + hci_dev_lock(hdev); + memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - if (!bdaddr_type_is_valid(cp->addr.type)) - return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &rp, sizeof(rp)); - - if (cp->disconnect != 0x00 && cp->disconnect != 0x01) - return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &rp, sizeof(rp)); - - hci_dev_lock(hdev); - if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); @@ -1700,7 +1596,6 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_disconnect *cp = data; - struct mgmt_rp_disconnect rp; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; @@ -1708,26 +1603,17 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - memset(&rp, 0, sizeof(rp)); - bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); - rp.addr.type = cp->addr.type; - - if (!bdaddr_type_is_valid(cp->addr.type)) - return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_INVALID_PARAMS, - &rp, sizeof(rp)); - hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { - err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, + MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { - err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_BUSY, &rp, sizeof(rp)); + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, + MGMT_STATUS_BUSY); goto failed; } @@ -1738,8 +1624,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) { - err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp)); + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, + MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -2017,20 +1903,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - memset(&rp, 0, sizeof(rp)); - bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); - rp.addr.type = cp->addr.type; - - if (!bdaddr_type_is_valid(cp->addr.type)) - return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &rp, sizeof(rp)); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); + err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -2047,6 +1924,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, cp->addr.type, sec_level, auth_type); + memset(&rp, 0, sizeof(rp)); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; + if (IS_ERR(conn)) { int status; @@ -2373,16 +2254,24 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, &cp->addr, + sizeof(cp->addr)); + goto unlock; + } + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) status = MGMT_STATUS_FAILED; else - status = MGMT_STATUS_SUCCESS; + status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); +unlock: hci_dev_unlock(hdev); return err; } @@ -2398,15 +2287,24 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, hdev->id, + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, &cp->addr, + sizeof(cp->addr)); + goto unlock; + } + err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) status = MGMT_STATUS_INVALID_PARAMS; else - status = MGMT_STATUS_SUCCESS; + status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); +unlock: hci_dev_unlock(hdev); return err; } @@ -2467,45 +2365,31 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: - if (!lmp_bredr_capable(hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_NOT_SUPPORTED); - mgmt_pending_remove(cmd); - goto failed; - } - - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + if (lmp_bredr_capable(hdev)) + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + else + err = -ENOTSUPP; break; case DISCOV_TYPE_LE: - if (!lmp_host_le_capable(hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_NOT_SUPPORTED); - mgmt_pending_remove(cmd); - goto failed; - } - - err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, - LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + if (lmp_host_le_capable(hdev)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + else + err = -ENOTSUPP; break; case DISCOV_TYPE_INTERLEAVED: - if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_NOT_SUPPORTED); - mgmt_pending_remove(cmd); - goto failed; - } - - err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, - LE_SCAN_TIMEOUT_BREDR_LE); + if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + LE_SCAN_WIN, + LE_SCAN_TIMEOUT_BREDR_LE); + else + err = -ENOTSUPP; break; default: - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - mgmt_pending_remove(cmd); - goto failed; + err = -EINVAL; } if (err < 0) @@ -2626,8 +2510,7 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, hci_inquiry_cache_update_resolve(hdev, e); } - err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr, - sizeof(cp->addr)); + err = 0; failed: hci_dev_unlock(hdev); @@ -2643,18 +2526,13 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (!bdaddr_type_is_valid(cp->addr.type)) - return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) status = MGMT_STATUS_FAILED; else - status = MGMT_STATUS_SUCCESS; + status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); @@ -2673,18 +2551,13 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (!bdaddr_type_is_valid(cp->addr.type)) - return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) status = MGMT_STATUS_INVALID_PARAMS; else - status = MGMT_STATUS_SUCCESS; + status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); @@ -2739,10 +2612,6 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - if (!hdev_is_powered(hdev)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_NOT_POWERED); @@ -2790,23 +2659,12 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, return err; } -static bool ltk_is_valid(struct mgmt_ltk_info *key) -{ - if (key->authenticated != 0x00 && key->authenticated != 0x01) - return false; - if (key->master != 0x00 && key->master != 0x01) - return false; - if (!bdaddr_type_is_le(key->addr.type)) - return false; - return true; -} - static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, void *cp_data, u16 len) { struct mgmt_cp_load_long_term_keys *cp = cp_data; u16 key_count, expected_len; - int i, err; + int i; key_count = __le16_to_cpu(cp->key_count); @@ -2816,20 +2674,11 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, BT_ERR("load_keys: expected %u bytes, got %u bytes", len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, - MGMT_STATUS_INVALID_PARAMS); + EINVAL); } BT_DBG("%s key_count %u", hdev->name, key_count); - for (i = 0; i < key_count; i++) { - struct mgmt_ltk_info *key = &cp->keys[i]; - - if (!ltk_is_valid(key)) - return cmd_status(sk, hdev->id, - MGMT_OP_LOAD_LONG_TERM_KEYS, - MGMT_STATUS_INVALID_PARAMS); - } - hci_dev_lock(hdev); hci_smp_ltks_clear(hdev); @@ -2849,12 +2698,9 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, key->enc_size, key->ediv, key->rand); } - err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0, - NULL, 0); - hci_dev_unlock(hdev); - return err; + return 0; } static const struct mgmt_handler { @@ -3069,8 +2915,6 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); if (powered) { - u8 link_sec; - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && !lmp_host_ssp_capable(hdev)) { u8 ssp = 1; @@ -3094,11 +2938,6 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) sizeof(cp), &cp); } - link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags); - if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) - hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, - sizeof(link_sec), &link_sec); - if (lmp_bredr_capable(hdev)) { set_bredr_scan(hdev); update_class(hdev); @@ -3107,13 +2946,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) } } else { u8 status = MGMT_STATUS_NOT_POWERED; - u8 zero_cod[] = { 0, 0, 0 }; - mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); - - if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) - mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, - zero_cod, sizeof(zero_cod), NULL); } err = new_settings(hdev, match.sk); diff --git a/trunk/net/bluetooth/sco.c b/trunk/net/bluetooth/sco.c index b5178d62064e..57f250c20e39 100644 --- a/trunk/net/bluetooth/sco.c +++ b/trunk/net/bluetooth/sco.c @@ -900,6 +900,8 @@ static void sco_conn_ready(struct sco_conn *conn) BT_DBG("conn %p", conn); + sco_conn_lock(conn); + if (sk) { sco_sock_clear_timer(sk); bh_lock_sock(sk); @@ -907,13 +909,9 @@ static void sco_conn_ready(struct sco_conn *conn) sk->sk_state_change(sk); bh_unlock_sock(sk); } else { - sco_conn_lock(conn); - parent = sco_get_sock_listen(conn->src); - if (!parent) { - sco_conn_unlock(conn); - return; - } + if (!parent) + goto done; bh_lock_sock(parent); @@ -921,8 +919,7 @@ static void sco_conn_ready(struct sco_conn *conn) BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); - sco_conn_unlock(conn); - return; + goto done; } sco_sock_init(sk, parent); @@ -942,9 +939,10 @@ static void sco_conn_ready(struct sco_conn *conn) parent->sk_data_ready(parent, 1); bh_unlock_sock(parent); - - sco_conn_unlock(conn); } + +done: + sco_conn_unlock(conn); } /* ----- SCO interface with lower layer (HCI) ----- */ diff --git a/trunk/net/mac80211/mesh_plink.c b/trunk/net/mac80211/mesh_plink.c index fe7c3334d6fe..67524e7d2548 100644 --- a/trunk/net/mac80211/mesh_plink.c +++ b/trunk/net/mac80211/mesh_plink.c @@ -592,6 +592,9 @@ static void mesh_plink_timer(unsigned long data) #ifdef CONFIG_PM void mesh_plink_quiesce(struct sta_info *sta) { + if (!ieee80211_vif_is_mesh(&sta->sdata->vif)) + return; + if (del_timer_sync(&sta->plink_timer)) sta->plink_timer_was_running = true; } diff --git a/trunk/net/nfc/llcp/llcp.c b/trunk/net/nfc/llcp/llcp.c index 746f5a2f9804..85bc75c38dea 100644 --- a/trunk/net/nfc/llcp/llcp.c +++ b/trunk/net/nfc/llcp/llcp.c @@ -549,13 +549,14 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) pr_err("No LLCP device\n"); return -ENODEV; } - if (gb_len < 3) - return -EINVAL; memset(local->remote_gb, 0, NFC_MAX_GT_LEN); memcpy(local->remote_gb, gb, gb_len); local->remote_gb_len = gb_len; + if (local->remote_gb == NULL || local->remote_gb_len == 0) + return -ENODEV; + if (memcmp(local->remote_gb, llcp_magic, 3)) { pr_err("MAC does not support LLCP\n"); return -EINVAL;