diff options
Diffstat (limited to 'drivers')
56 files changed, 2953 insertions, 2831 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index d9c08c619a3a..7b4c074e12fa 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -25,6 +25,7 @@ config ATH9K config ATH9K_PCI bool "Atheros ath9k PCI/PCIe bus support" + default y depends on ATH9K && PCI ---help--- This option enables the PCI bus support in ath9k. diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 3b262ba6b172..a93bd63ad23b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -121,10 +121,8 @@ static const struct ar9300_eeprom ar9300_default = { * if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {1, 1, 1},/* 3 chain */ - .db_stage2 = {1, 1, 1}, /* 3 chain */ - .db_stage3 = {0, 0, 0}, - .db_stage4 = {0, 0, 0}, + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -144,7 +142,7 @@ static const struct ar9300_eeprom ar9300_default = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { FREQ2FBIN(2412, 1), @@ -323,10 +321,8 @@ static const struct ar9300_eeprom ar9300_default = { .spurChans = {0, 0, 0, 0, 0}, /* noiseFloorThreshCh Check if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {3, 3, 3}, /* 3 chain */ - .db_stage2 = {3, 3, 3}, /* 3 chain */ - .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ - .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -698,10 +694,8 @@ static const struct ar9300_eeprom ar9300_x113 = { * if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {1, 1, 1},/* 3 chain */ - .db_stage2 = {1, 1, 1}, /* 3 chain */ - .db_stage3 = {0, 0, 0}, - .db_stage4 = {0, 0, 0}, + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -721,7 +715,7 @@ static const struct ar9300_eeprom ar9300_x113 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { FREQ2FBIN(2412, 1), @@ -900,10 +894,8 @@ static const struct ar9300_eeprom ar9300_x113 = { .spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0}, /* noiseFloorThreshCh Check if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {3, 3, 3}, /* 3 chain */ - .db_stage2 = {3, 3, 3}, /* 3 chain */ - .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ - .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0xf, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -1276,10 +1268,8 @@ static const struct ar9300_eeprom ar9300_h112 = { * if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {1, 1, 1},/* 3 chain */ - .db_stage2 = {1, 1, 1}, /* 3 chain */ - .db_stage3 = {0, 0, 0}, - .db_stage4 = {0, 0, 0}, + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -1291,20 +1281,20 @@ static const struct ar9300_eeprom ar9300_h112 = { .txEndToRxOn = 0x2, .txFrameToXpaOn = 0xe, .thresh62 = 28, - .papdRateMaskHt20 = LE32(0x80c080), - .papdRateMaskHt40 = LE32(0x80c080), + .papdRateMaskHt20 = LE32(0x0c80c080), + .papdRateMaskHt40 = LE32(0x0080c080), .futureModal = { 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { FREQ2FBIN(2412, 1), FREQ2FBIN(2437, 1), - FREQ2FBIN(2472, 1), + FREQ2FBIN(2462, 1), }, /* ar9300_cal_data_per_freq_op_loop 2g */ .calPierData2G = { @@ -1314,7 +1304,7 @@ static const struct ar9300_eeprom ar9300_h112 = { }, .calTarget_freqbin_Cck = { FREQ2FBIN(2412, 1), - FREQ2FBIN(2484, 1), + FREQ2FBIN(2472, 1), }, .calTarget_freqbin_2G = { FREQ2FBIN(2412, 1), @@ -1478,10 +1468,8 @@ static const struct ar9300_eeprom ar9300_h112 = { .spurChans = {0, 0, 0, 0, 0}, /* noiseFloorThreshCh Check if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {3, 3, 3}, /* 3 chain */ - .db_stage2 = {3, 3, 3}, /* 3 chain */ - .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ - .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -1515,7 +1503,7 @@ static const struct ar9300_eeprom ar9300_h112 = { FREQ2FBIN(5500, 0), FREQ2FBIN(5600, 0), FREQ2FBIN(5700, 0), - FREQ2FBIN(5825, 0) + FREQ2FBIN(5785, 0) }, .calPierData5G = { { @@ -1854,10 +1842,8 @@ static const struct ar9300_eeprom ar9300_x112 = { * if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {1, 1, 1},/* 3 chain */ - .db_stage2 = {1, 1, 1}, /* 3 chain */ - .db_stage3 = {0, 0, 0}, - .db_stage4 = {0, 0, 0}, + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -1877,7 +1863,7 @@ static const struct ar9300_eeprom ar9300_x112 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { FREQ2FBIN(2412, 1), @@ -2056,10 +2042,8 @@ static const struct ar9300_eeprom ar9300_x112 = { .spurChans = {0, 0, 0, 0, 0}, /* noiseFloorThreshch check if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {3, 3, 3}, /* 3 chain */ - .db_stage2 = {3, 3, 3}, /* 3 chain */ - .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ - .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -2431,10 +2415,8 @@ static const struct ar9300_eeprom ar9300_h116 = { * if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {1, 1, 1},/* 3 chain */ - .db_stage2 = {1, 1, 1}, /* 3 chain */ - .db_stage3 = {0, 0, 0}, - .db_stage4 = {0, 0, 0}, + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -2454,12 +2436,12 @@ static const struct ar9300_eeprom ar9300_h116 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { FREQ2FBIN(2412, 1), FREQ2FBIN(2437, 1), - FREQ2FBIN(2472, 1), + FREQ2FBIN(2462, 1), }, /* ar9300_cal_data_per_freq_op_loop 2g */ .calPierData2G = { @@ -2633,10 +2615,8 @@ static const struct ar9300_eeprom ar9300_h116 = { .spurChans = {0, 0, 0, 0, 0}, /* noiseFloorThreshCh Check if the register is per chain */ .noiseFloorThreshCh = {-1, 0, 0}, - .ob = {3, 3, 3}, /* 3 chain */ - .db_stage2 = {3, 3, 3}, /* 3 chain */ - .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ - .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .quick_drop = 0, .xpaBiasLvl = 0, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, @@ -2663,7 +2643,7 @@ static const struct ar9300_eeprom ar9300_h116 = { .xatten1MarginHigh = {0, 0, 0} }, .calFreqPier5G = { - FREQ2FBIN(5180, 0), + FREQ2FBIN(5160, 0), FREQ2FBIN(5220, 0), FREQ2FBIN(5320, 0), FREQ2FBIN(5400, 0), @@ -3023,6 +3003,8 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, return eep->modalHeader5G.antennaGain; case EEP_ANTENNA_GAIN_2G: return eep->modalHeader2G.antennaGain; + case EEP_QUICK_DROP: + return pBase->miscConfiguration & BIT(1); default: return 0; } @@ -3428,25 +3410,14 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size, PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]); + PR_EEP("Quick Drop", modal_hdr->quick_drop); + PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); PR_EEP("txClip", modal_hdr->txClip); PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); - PR_EEP("Chain0 ob", modal_hdr->ob[0]); - PR_EEP("Chain1 ob", modal_hdr->ob[1]); - PR_EEP("Chain2 ob", modal_hdr->ob[2]); - - PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]); - PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]); - PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]); - PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]); - PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]); - PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]); - PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]); - PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]); - PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]); return len; } @@ -3503,6 +3474,7 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4))); PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5))); PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0))); + PR_EEP("Quick Drop", !!(pBase->miscConfiguration & BIT(1))); PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1); PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio); PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio); @@ -3965,6 +3937,40 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah) } } +static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + int quick_drop = ath9k_hw_ar9300_get_eeprom(ah, EEP_QUICK_DROP); + s32 t[3], f[3] = {5180, 5500, 5785}; + + if (!quick_drop) + return; + + if (freq < 4000) + quick_drop = eep->modalHeader2G.quick_drop; + else { + t[0] = eep->base_ext1.quick_drop_low; + t[1] = eep->modalHeader5G.quick_drop; + t[2] = eep->base_ext1.quick_drop_high; + quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3); + } + REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop); +} + +static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, u16 freq) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + u32 value; + + value = (freq < 4000) ? eep->modalHeader2G.txEndToXpaOff : + eep->modalHeader5G.txEndToXpaOff; + + REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, + AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value); + REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, + AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value); +} + static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -3972,10 +3978,12 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); ar9003_hw_drive_strength_apply(ah); ar9003_hw_atten_apply(ah, chan); + ar9003_hw_quick_drop_apply(ah, chan->channel); if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah)) ar9003_hw_internal_regulator_apply(ah); if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) ar9003_hw_apply_tuning_caps(ah); + ar9003_hw_txend_to_xpa_off_apply(ah, chan->channel); } static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah, @@ -5051,6 +5059,8 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, regulatory->max_power_level = targetPowerValT2[i]; } + ath9k_hw_update_regulatory_maxpower(ah); + if (test) return; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 6335a867527e..bb223fe82816 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -216,10 +216,8 @@ struct ar9300_modal_eep_header { u8 spurChans[AR_EEPROM_MODAL_SPURS]; /* 3 Check if the register is per chain */ int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS]; - u8 ob[AR9300_MAX_CHAINS]; - u8 db_stage2[AR9300_MAX_CHAINS]; - u8 db_stage3[AR9300_MAX_CHAINS]; - u8 db_stage4[AR9300_MAX_CHAINS]; + u8 reserved[11]; + int8_t quick_drop; u8 xpaBiasLvl; u8 txFrameToDataStart; u8 txFrameToPaOn; @@ -269,7 +267,9 @@ struct cal_ctl_data_5g { struct ar9300_BaseExtension_1 { u8 ant_div_control; - u8 future[13]; + u8 future[11]; + int8_t quick_drop_low; + int8_t quick_drop_high; } __packed; struct ar9300_BaseExtension_2 { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 4114fe752c6b..497d7461838a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -389,6 +389,8 @@ #define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 #define AR_PHY_RIFS_INIT_DELAY 0x3ff0000 +#define AR_PHY_AGC_QUICK_DROP 0x03c00000 +#define AR_PHY_AGC_QUICK_DROP_S 22 #define AR_PHY_AGC_COARSE_LOW 0x00007F80 #define AR_PHY_AGC_COARSE_LOW_S 7 #define AR_PHY_AGC_COARSE_HIGH 0x003F8000 diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 49abd34be741..5ff7ab965120 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -249,7 +249,8 @@ enum eeprom_param { EEP_ANT_DIV_CTL1, EEP_CHAIN_MASK_REDUCE, EEP_ANTENNA_GAIN_2G, - EEP_ANTENNA_GAIN_5G + EEP_ANTENNA_GAIN_5G, + EEP_QUICK_DROP }; enum ar5416_rates { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 43b44961a41a..22913af26db8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -687,14 +687,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) return -EBADE; } - if (pendok && ((bus->ci->c_inf[1].id == PCMCIA_CORE_ID) - && (bus->ci->c_inf[1].rev == 9))) { - u32 dummy, retries; - r_sdreg32(bus, &dummy, - offsetof(struct sdpcmd_regs, clockctlstatus), - &retries); - } - /* Check current status */ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -911,13 +903,6 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - /* Force pad isolation off if possible - (in case power never toggled) */ - if ((bus->ci->c_inf[1].id == PCMCIA_CORE_ID) - && (bus->ci->c_inf[1].rev >= 10)) - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, 0, NULL); - /* Make sure the controller has the bus up */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -1107,6 +1092,28 @@ static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len) return ret; } +/* return total length of buffer chain */ +static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus) +{ + struct sk_buff *p; + uint total; + + total = 0; + skb_queue_walk(&bus->glom, p) + total += p->len; + return total; +} + +static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus) +{ + struct sk_buff *cur, *next; + + skb_queue_walk_safe(&bus->glom, cur, next) { + skb_unlink(cur, &bus->glom); + brcmu_pkt_buf_free_skb(cur); + } +} + static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) { u16 dlen, totlen; @@ -1191,11 +1198,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) } pfirst = pnext = NULL; } else { - if (!skb_queue_empty(&bus->glom)) - skb_queue_walk_safe(&bus->glom, pfirst, pnext) { - skb_unlink(pfirst, &bus->glom); - brcmu_pkt_buf_free_skb(pfirst); - } + brcmf_sdbrcm_free_glom(bus); num = 0; } @@ -1218,7 +1221,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) } pfirst = skb_peek(&bus->glom); - dlen = (u16) brcmu_pkttotlen(pfirst); + dlen = (u16) brcmf_sdbrcm_glom_len(bus); /* Do an SDIO read for the superframe. Configurable iovar to * read directly into the chained packet, or allocate a large @@ -1262,10 +1265,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) bus->glomerr = 0; brcmf_sdbrcm_rxfail(bus, true, false); bus->rxglomfail++; - skb_queue_walk_safe(&bus->glom, pfirst, pnext) { - skb_unlink(pfirst, &bus->glom); - brcmu_pkt_buf_free_skb(pfirst); - } + brcmf_sdbrcm_free_glom(bus); } return 0; } @@ -1387,10 +1387,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) bus->glomerr = 0; brcmf_sdbrcm_rxfail(bus, true, false); bus->rxglomfail++; - skb_queue_walk_safe(&bus->glom, pfirst, pnext) { - skb_unlink(pfirst, &bus->glom); - brcmu_pkt_buf_free_skb(pfirst); - } + brcmf_sdbrcm_free_glom(bus); } bus->nextlen = 0; return 0; @@ -3098,7 +3095,6 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) { uint retries; int bcmerror = 0; - u8 idx; struct chip_info *ci = bus->ci; /* To enter download state, disable ARM and reset SOCRAM. @@ -3107,11 +3103,9 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) if (enter) { bus->alp_only = true; - idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); - brcmf_sdio_chip_coredisable(bus->sdiodev, ci->c_inf[idx].base); + ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3); - idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_INTERNAL_MEM); - brcmf_sdio_chip_resetcore(bus->sdiodev, ci->c_inf[idx].base); + ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM); /* Clear the top bit of memory */ if (bus->ramsize) { @@ -3120,9 +3114,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) (u8 *)&zeros, 4); } } else { - idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_INTERNAL_MEM); - if (!brcmf_sdio_chip_iscoreup(bus->sdiodev, - ci->c_inf[idx].base)) { + if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) { brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n"); bcmerror = -EBADE; goto fail; @@ -3137,8 +3129,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) w_sdreg32(bus, 0xFFFFFFFF, offsetof(struct sdpcmd_regs, intstatus), &retries); - idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); - brcmf_sdio_chip_resetcore(bus->sdiodev, ci->c_inf[idx].base); + ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3); /* Allow HT Clock now that the ARM is running. */ bus->alp_only = false; @@ -3363,8 +3354,6 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) u8 saveclk; uint retries; int err; - struct sk_buff *cur; - struct sk_buff *next; brcmf_dbg(TRACE, "Enter\n"); @@ -3424,11 +3413,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) /* Clear any held glomming stuff */ if (bus->glomd) brcmu_pkt_buf_free_skb(bus->glomd); - if (!skb_queue_empty(&bus->glom)) - skb_queue_walk_safe(&bus->glom, cur, next) { - skb_unlink(cur, &bus->glom); - brcmu_pkt_buf_free_skb(cur); - } + brcmf_sdbrcm_free_glom(bus); /* Clear rx control and wake any waiters */ bus->rxlen = 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index 99d00ddc1639..f6b1822031fe 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -45,6 +45,14 @@ ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ ((sbidh) & SSB_IDHIGH_RCLO)) +/* SOC Interconnect types (aka chip types) */ +#define SOCI_SB 0 +#define SOCI_AI 1 + +/* EROM CompIdentB */ +#define CIB_REV_MASK 0xff000000 +#define CIB_REV_SHIFT 24 + #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) /* SDIO Pad drive strength to select value mappings */ struct sdiod_drive_str { @@ -96,148 +104,263 @@ brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid) } static u32 -brcmf_sdio_chip_corerev(struct brcmf_sdio_dev *sdiodev, - u32 corebase) +brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) { u32 regdata; + u8 idx; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbidhigh), 4); + CORE_SB(ci->c_inf[idx].base, sbidhigh), 4); return SBCOREREV(regdata); } -bool -brcmf_sdio_chip_iscoreup(struct brcmf_sdio_dev *sdiodev, - u32 corebase) +static u32 +brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) +{ + u8 idx; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); + + return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT; +} + +static bool +brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) { u32 regdata; + u8 idx; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); return (SSB_TMSLOW_CLOCK == regdata); } -void -brcmf_sdio_chip_coredisable(struct brcmf_sdio_dev *sdiodev, u32 corebase) +static bool +brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) +{ + u32 regdata; + u8 idx; + bool ret; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); + + regdata = brcmf_sdcard_reg_read(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); + ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; + + regdata = brcmf_sdcard_reg_read(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + 4); + ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); + + return ret; +} + +static void +brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) { u32 regdata; + u8 idx; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); if (regdata & SSB_TMSLOW_RESET) return; regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); if ((regdata & SSB_TMSLOW_CLOCK) != 0) { /* * set target reject and spin until busy is clear * (preserve core-specific bits) */ regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), - 4, regdata | SSB_TMSLOW_REJECT); + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + 4, regdata | SSB_TMSLOW_REJECT); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); udelay(1); SPINWAIT((brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4) & + CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) & SSB_TMSHIGH_BUSY), 100000); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4); if (regdata & SSB_TMSHIGH_BUSY) brcmf_dbg(ERROR, "core state still busy\n"); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbidlow), 4); + CORE_SB(ci->c_inf[idx].base, sbidlow), 4); if (regdata & SSB_IDLOW_INITIATOR) { regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4) | + CORE_SB(ci->c_inf[idx].base, sbimstate), 4) | SSB_IMSTATE_REJECT; brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbimstate), 4, + CORE_SB(ci->c_inf[idx].base, sbimstate), 4, regdata); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4); + CORE_SB(ci->c_inf[idx].base, sbimstate), 4); udelay(1); SPINWAIT((brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4) & + CORE_SB(ci->c_inf[idx].base, sbimstate), 4) & SSB_IMSTATE_BUSY), 100000); } /* set reset and reject while enabling the clocks */ brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); udelay(10); /* clear the initiator reject bit */ regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbidlow), 4); + CORE_SB(ci->c_inf[idx].base, sbidlow), 4); if (regdata & SSB_IDLOW_INITIATOR) { regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4) & + CORE_SB(ci->c_inf[idx].base, sbimstate), 4) & ~SSB_IMSTATE_REJECT; brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbimstate), 4, + CORE_SB(ci->c_inf[idx].base, sbimstate), 4, regdata); } } /* leave reset and reject asserted */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); udelay(1); } -void -brcmf_sdio_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase) +static void +brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) +{ + u8 idx; + u32 regdata; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); + + /* if core is already in reset, just return */ + regdata = brcmf_sdcard_reg_read(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + 4); + if ((regdata & BCMA_RESET_CTL_RESET) != 0) + return; + + brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + 4, 0); + regdata = brcmf_sdcard_reg_read(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); + udelay(10); + + brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + 4, BCMA_RESET_CTL_RESET); + udelay(1); +} + +static void +brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) { u32 regdata; + u8 idx; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); /* * Must do the disable sequence first to work for * arbitrary current core state. */ - brcmf_sdio_chip_coredisable(sdiodev, corebase); + brcmf_sdio_sb_coredisable(sdiodev, ci, coreid); /* * Now do the initialization sequence. * set reset while enabling the clock and * forcing them on throughout the core */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, - SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET); + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, + SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET); + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); udelay(1); + /* clear any serror */ regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4); + CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4); if (regdata & SSB_TMSHIGH_SERR) brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4, 0); + CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0); regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4); + CORE_SB(ci->c_inf[idx].base, sbimstate), 4); if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4, + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbimstate), 4, regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO)); /* clear reset and allow it to propagate throughout the core */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK); + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); udelay(1); /* leave clock enabled */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, SSB_TMSLOW_CLOCK); + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + udelay(1); +} + +static void +brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid) +{ + u8 idx; + u32 regdata; + + idx = brcmf_sdio_chip_getinfidx(ci, coreid); + + /* must disable first to work for arbitrary current core state */ + brcmf_sdio_ai_coredisable(sdiodev, ci, coreid); + + /* now do initialization sequence */ + brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + 4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); + regdata = brcmf_sdcard_reg_read(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); + brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + 4, 0); + udelay(1); + + brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + 4, BCMA_IOCTL_CLK); + regdata = brcmf_sdcard_reg_read(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); udelay(1); } @@ -258,6 +381,7 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, CORE_CC_REG(ci->c_inf[0].base, chipid), 4); ci->chip = regdata & CID_ID_MASK; ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; + ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev); @@ -277,6 +401,24 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, return -ENODEV; } + switch (ci->socitype) { + case SOCI_SB: + ci->iscoreup = brcmf_sdio_sb_iscoreup; + ci->corerev = brcmf_sdio_sb_corerev; + ci->coredisable = brcmf_sdio_sb_coredisable; + ci->resetcore = brcmf_sdio_sb_resetcore; + break; + case SOCI_AI: + ci->iscoreup = brcmf_sdio_ai_iscoreup; + ci->corerev = brcmf_sdio_ai_corerev; + ci->coredisable = brcmf_sdio_ai_coredisable; + ci->resetcore = brcmf_sdio_ai_resetcore; + break; + default: + brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype); + return -ENODEV; + } + return 0; } @@ -332,12 +474,8 @@ static void brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci) { - u32 regdata; - u8 idx; - /* get chipcommon rev */ - ci->c_inf[0].rev = - brcmf_sdio_chip_corerev(sdiodev, ci->c_inf[0].base); + ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id); /* get chipcommon capabilites */ ci->c_inf[0].caps = @@ -351,10 +489,7 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, ci->pmurev = ci->pmucaps & PCAP_REV_MASK; } - ci->c_inf[1].rev = brcmf_sdio_chip_corerev(sdiodev, ci->c_inf[1].base); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[1].base, sbidhigh), 4); - ci->c_inf[1].id = (regdata & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; + ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id); brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", ci->c_inf[0].rev, ci->pmurev, @@ -364,8 +499,7 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, * Make sure any on-chip ARM is off (in case strapping is wrong), * or downloaded code was already running. */ - idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); - brcmf_sdio_chip_coredisable(sdiodev, ci->c_inf[idx].base); + ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3); } int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h index 0ee37ae4c958..ce974d76bd92 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h @@ -60,17 +60,28 @@ struct chip_core_info { u32 base; u32 wrapbase; u32 caps; + u32 cib; }; struct chip_info { u32 chip; u32 chiprev; + u32 socitype; /* core info */ /* always put chipcommon core at 0, bus core at 1 */ struct chip_core_info c_inf[BRCMF_MAX_CORENUM]; u32 pmurev; u32 pmucaps; u32 ramsize; + + bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, + u16 coreid); + u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, + u16 coreid); + void (*coredisable)(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid); + void (*resetcore)(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u16 coreid); }; struct sbconfig { @@ -113,12 +124,6 @@ struct sbconfig { u32 sbidhigh; /* identification */ }; -extern void brcmf_sdio_chip_resetcore(struct brcmf_sdio_dev *sdiodev, - u32 corebase); -extern bool brcmf_sdio_chip_iscoreup(struct brcmf_sdio_dev *sdiodev, - u32 corebase); -extern void brcmf_sdio_chip_coredisable(struct brcmf_sdio_dev *sdiodev, - u32 corebase); extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, struct chip_info **ci_ptr, u32 regs); extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 73be2c8d4cee..cc19a733ac65 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -2049,10 +2049,10 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, notify_timestamp, notify_capability, notify_interval, notify_ie, notify_ielen, notify_signal, GFP_KERNEL); - if (!bss) { - WL_ERR("cfg80211_inform_bss_frame error\n"); - return -EINVAL; - } + if (!bss) + return -ENOMEM; + + cfg80211_put_bss(bss); return err; } @@ -2096,6 +2096,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, struct ieee80211_channel *notify_channel; struct brcmf_bss_info_le *bi = NULL; struct ieee80211_supported_band *band; + struct cfg80211_bss *bss; u8 *buf = NULL; s32 err = 0; u16 channel; @@ -2149,10 +2150,17 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, WL_CONN("signal: %d\n", notify_signal); WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); - cfg80211_inform_bss(wiphy, notify_channel, bssid, + bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, notify_timestamp, notify_capability, notify_interval, notify_ie, notify_ielen, notify_signal, GFP_KERNEL); + if (!bss) { + err = -ENOMEM; + goto CleanUp; + } + + cfg80211_put_bss(bss); + CleanUp: kfree(buf); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 7f27dbdb6b60..43f7a724dda8 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -649,7 +649,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, len = roundup(len, 4); ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN); - dma_len += (u16) brcmu_pkttotlen(p); + dma_len += (u16) p->len; BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d" " seg_cnt %d null delim %d\n", @@ -741,9 +741,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, if (p) { if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && ((u8) (p->priority) == tid)) { - - plen = brcmu_pkttotlen(p) + - AMPDU_MAX_MPDU_OVERHEAD; + plen = p->len + AMPDU_MAX_MPDU_OVERHEAD; plen = max(scb_ampdu->min_len, plen); if ((plen + ampdu_len) > max_ampdu_bytes) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 89ad1b7dab8f..55e9f45fce22 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -1153,121 +1153,6 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, &txpwr); } -#ifdef POWER_DBG -static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr) -{ - int i; - char buf[80]; - char fraction[4][4] = { " ", ".25", ".5 ", ".75" }; - - sprintf(buf, "CCK "); - for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "20 MHz OFDM SISO "); - for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "20 MHz OFDM CDD "); - for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "40 MHz OFDM SISO "); - for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->ofdm_40_siso[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "40 MHz OFDM CDD "); - for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->ofdm_40_cdd[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "20 MHz MCS0-7 SISO "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_20_siso[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "20 MHz MCS0-7 CDD "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_20_cdd[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "20 MHz MCS0-7 STBC "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_20_stbc[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "20 MHz MCS8-15 SDM "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_20_mimo[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "40 MHz MCS0-7 SISO "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_40_siso[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "40 MHz MCS0-7 CDD "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_40_cdd[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "40 MHz MCS0-7 STBC "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_40_stbc[i] % - BRCMS_TXPWR_DB_FACTOR]); - printk(KERN_DEBUG "%s\n", buf); - - sprintf(buf, "40 MHz MCS8-15 SDM "); - for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) - sprintf(buf[strlen(buf)], " %2d%s", - txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs_40_mimo[i] % - BRCMS_TXPWR_DB_FACTOR]); - } - printk(KERN_DEBUG "%s\n", buf); - - printk(KERN_DEBUG "MCS32 %2d%s\n", - txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR, - fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]); -} -#endif /* POWER_DBG */ - void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, struct txpwr_limits *txpwr) @@ -1478,9 +1363,6 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i]; } -#ifdef POWER_DBG - wlc_phy_txpower_limits_dump(txpwr); -#endif return; } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 8e35c62d0bb1..6d3c7b6c5aa0 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -619,13 +619,6 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wl->pub->global_ampdu->scb = scb; wl->pub->global_ampdu->max_pdu = 16; - sta->ht_cap.ht_supported = true; - sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY; - sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD | - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT; - /* * minstrel_ht initiates addBA on our behalf by calling * ieee80211_start_tx_ba_session() diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index f193fab675dc..36e3e0638300 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -109,11 +109,6 @@ #define BPHY_PLCP_TIME 192 #define RIFS_11N_TIME 2 -#define AC_BE 0 -#define AC_BK 1 -#define AC_VI 2 -#define AC_VO 3 - /* length of the BCN template area */ #define BCN_TMPL_LEN 512 @@ -305,10 +300,22 @@ uint brcm_msg_level = #endif /* BCMDBG */ /* TX FIFO number to WME/802.1E Access Category */ -static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE }; +static const u8 wme_fifo2ac[] = { + IEEE80211_AC_BK, + IEEE80211_AC_BE, + IEEE80211_AC_VI, + IEEE80211_AC_VO, + IEEE80211_AC_BE, + IEEE80211_AC_BE +}; -/* WME/802.1E Access Category to TX FIFO number */ -static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 }; +/* ieee80211 Access Category to TX FIFO number */ +static const u8 wme_ac2fifo[] = { + TX_AC_VO_FIFO, + TX_AC_VI_FIFO, + TX_AC_BE_FIFO, + TX_AC_BK_FIFO +}; /* 802.1D Priority to precedence queue mapping */ const u8 wlc_prio2prec_map[] = { @@ -893,7 +900,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) lfbl, /* Long Frame Rate Fallback Limit */ fbl; - if (queue < AC_COUNT) { + if (queue < IEEE80211_NUM_ACS) { sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]], EDCF_SFB); lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]], @@ -942,7 +949,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) tx_info->flags |= IEEE80211_TX_STAT_ACK; } - totlen = brcmu_pkttotlen(p); + totlen = p->len; free_pdu = true; brcms_c_txfifo_complete(wlc, queue, 1); @@ -3576,42 +3583,30 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, brcms_c_set_phy_chanspec(wlc, chanspec); } -static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc) -{ - if (wlc->bcnmisc_monitor) - brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC); - else - brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0); -} - -void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc) -{ - wlc->bcnmisc_monitor = promisc; - brcms_c_mac_bcn_promisc(wlc); -} - -/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */ +/* + * Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and + * MCTL_KEEPCONTROL + */ static void brcms_c_mac_promisc(struct brcms_c_info *wlc) { u32 promisc_bits = 0; - /* - * promiscuous mode just sets MCTL_PROMISC - * Note: APs get all BSS traffic without the need to set - * the MCTL_PROMISC bit since all BSS data traffic is - * directed at the AP - */ - if (wlc->pub->promisc) - promisc_bits |= MCTL_PROMISC; + if (wlc->bcnmisc_monitor) + promisc_bits |= MCTL_BCNS_PROMISC; - /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL - * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is - * handled in brcms_c_mac_bcn_promisc() - */ if (wlc->monitor) - promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL; + promisc_bits |= + MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL; - brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits); + brcms_b_mctrl(wlc->hw, + MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL, + promisc_bits); +} + +void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc) +{ + wlc->bcnmisc_monitor = promisc; + brcms_c_mac_promisc(wlc); } /* @@ -3643,7 +3638,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc) } /* update the various promisc bits */ - brcms_c_mac_bcn_promisc(wlc); brcms_c_mac_promisc(wlc); } @@ -4125,7 +4119,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, EDCF_TXOP2USEC(acp_shm.txop); acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK); - if (aci == AC_VI && acp_shm.txop == 0 + if (aci == IEEE80211_AC_VI && acp_shm.txop == 0 && acp_shm.aifs < EDCF_AIFSN_MAX) acp_shm.aifs++; @@ -4175,7 +4169,7 @@ static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) }; /* ucode needs these parameters during its initialization */ const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0]; - for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) { + for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) { /* find out which ac this set of params applies to */ aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT; @@ -5172,7 +5166,7 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc) if (!wlc->clk) return; - for (ac = 0; ac < AC_COUNT; ac++) + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac), wlc->wme_retries[ac]); } @@ -5647,7 +5641,7 @@ int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl) brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL); - for (ac = 0; ac < AC_COUNT; ac++) { + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_SHORT, wlc->SRL); wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], @@ -6709,7 +6703,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, qos = ieee80211_is_data_qos(h->frame_control); /* compute length of frame in bytes for use in PLCP computations */ - len = brcmu_pkttotlen(p); + len = p->len; phylen = len + FCS_LEN; /* Get tx_info */ @@ -8358,7 +8352,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) /* Uninitialized; read from HW */ int ac; - for (ac = 0; ac < AC_COUNT; ac++) + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) wlc->wme_retries[ac] = brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac)); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h index 9a7535d3838d..251c350b3164 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -44,8 +44,6 @@ /* transmit buffer max headroom for protocol headers */ #define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN) -#define AC_COUNT 4 - /* Macros for doing definition and get/set of bitfields * Usage example, e.g. a three-bit field (bits 4-6): * #define <NAME>_M BITFIELD_MASK(3) @@ -436,7 +434,7 @@ struct brcms_txq_info { * bcn_li_dtim: beacon listen interval in # dtims. * WDarmed: watchdog timer is armed. * WDlast: last time wlc_watchdog() was called. - * edcf_txop[AC_COUNT]: current txop for each ac. + * edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac. * wme_retries: per-AC retry limits. * tx_prec_map: Precedence map based on HW FIFO space. * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME. @@ -535,9 +533,9 @@ struct brcms_c_info { u32 WDlast; /* WME */ - u16 edcf_txop[AC_COUNT]; + u16 edcf_txop[IEEE80211_NUM_ACS]; - u16 wme_retries[AC_COUNT]; + u16 wme_retries[IEEE80211_NUM_ACS]; u16 tx_prec_map; u16 fifo2prec_map[NFIFO]; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 2faea509f017..e17edf7e6833 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -190,15 +190,7 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr) data = R_REG(&pi->regs->radioregdata); } else { W_REG_FLUSH(&pi->regs->phy4waddr, addr); - -#ifdef __ARM_ARCH_4T__ - __asm__(" .align 4 "); - __asm__(" nop "); - data = R_REG(&pi->regs->phy4wdatalo); -#else data = R_REG(&pi->regs->phy4wdatalo); -#endif - } pi->phy_wreg = 0; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 022523a5a532..21ccf3a03987 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -248,7 +248,6 @@ enum brcms_srom_id { }; #define BRCMS_NUMRATES 16 /* max # of rates in a rateset */ -#define D11_PHY_HDR_LEN 6 /* Phy header length - 6 bytes */ /* phy types */ #define PHY_TYPE_A 0 /* Phy type A */ @@ -382,7 +381,6 @@ struct brcms_pub { uint _nbands; /* # bands supported */ uint now; /* # elapsed seconds */ - bool promisc; /* promiscuous destination address */ bool delayed_down; /* down delayed */ bool associated; /* true:part of [I]BSS, false: not */ /* (union of stas_associated, aps_associated) */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c index 0539a6a831c5..b6987ea9fc68 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c @@ -638,7 +638,7 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) struct brcms_srom_list_head *entry; enum brcms_srom_id id; u16 w; - u32 val; + u32 val = 0; const struct brcms_sromvar *srv; uint width; uint flags; @@ -835,6 +835,8 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords) */ return -ENODATA; + /* fixup the endianness so crc8 will pass */ + cpu_to_le16_buf(buf, sz); if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table)) err = -EIO; diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c index 12b795ffd369..b7537f70a795 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c @@ -41,44 +41,20 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb); /* Free the driver packet. Free the tag if present */ void brcmu_pkt_buf_free_skb(struct sk_buff *skb) { - struct sk_buff *nskb; - int nest = 0; - - /* perversion: we use skb->next to chain multi-skb packets */ - while (skb) { - nskb = skb->next; - skb->next = NULL; - - if (skb->destructor) - /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if - * destructor exists - */ - dev_kfree_skb_any(skb); - else - /* can free immediately (even in_irq()) if destructor - * does not exist - */ - dev_kfree_skb(skb); - - nest++; - skb = nskb; - } + WARN_ON(skb->next); + if (skb->destructor) + /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if + * destructor exists + */ + dev_kfree_skb_any(skb); + else + /* can free immediately (even in_irq()) if destructor + * does not exist + */ + dev_kfree_skb(skb); } EXPORT_SYMBOL(brcmu_pkt_buf_free_skb); - -/* return total length of buffer chain */ -uint brcmu_pkttotlen(struct sk_buff *p) -{ - uint total; - - total = 0; - for (; p; p = p->next) - total += p->len; - return total; -} -EXPORT_SYMBOL(brcmu_pkttotlen); - /* * osl multiple-precedence packet queue * hi_prec is always >= the number of the highest non-empty precedence @@ -86,21 +62,13 @@ EXPORT_SYMBOL(brcmu_pkttotlen); struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, struct sk_buff *p) { - struct pktq_prec *q; + struct sk_buff_head *q; if (pktq_full(pq) || pktq_pfull(pq, prec)) return NULL; - q = &pq->q[prec]; - - if (q->head) - q->tail->prev = p; - else - q->head = p; - - q->tail = p; - q->len++; - + q = &pq->q[prec].skblist; + skb_queue_tail(q, p); pq->len++; if (pq->hi_prec < prec) @@ -113,20 +81,13 @@ EXPORT_SYMBOL(brcmu_pktq_penq); struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, struct sk_buff *p) { - struct pktq_prec *q; + struct sk_buff_head *q; if (pktq_full(pq) || pktq_pfull(pq, prec)) return NULL; - q = &pq->q[prec]; - - if (q->head == NULL) - q->tail = p; - - p->prev = q->head; - q->head = p; - q->len++; - + q = &pq->q[prec].skblist; + skb_queue_head(q, p); pq->len++; if (pq->hi_prec < prec) @@ -138,53 +99,30 @@ EXPORT_SYMBOL(brcmu_pktq_penq_head); struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec) { - struct pktq_prec *q; + struct sk_buff_head *q; struct sk_buff *p; - q = &pq->q[prec]; - - p = q->head; + q = &pq->q[prec].skblist; + p = skb_dequeue(q); if (p == NULL) return NULL; - q->head = p->prev; - if (q->head == NULL) - q->tail = NULL; - - q->len--; - pq->len--; - - p->prev = NULL; - return p; } EXPORT_SYMBOL(brcmu_pktq_pdeq); struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec) { - struct pktq_prec *q; - struct sk_buff *p, *prev; - - q = &pq->q[prec]; + struct sk_buff_head *q; + struct sk_buff *p; - p = q->head; + q = &pq->q[prec].skblist; + p = skb_dequeue_tail(q); if (p == NULL) return NULL; - for (prev = NULL; p != q->tail; p = p->prev) - prev = p; - - if (prev) - prev->prev = NULL; - else - q->head = NULL; - - q->tail = prev; - q->len--; - pq->len--; - return p; } EXPORT_SYMBOL(brcmu_pktq_pdeq_tail); @@ -193,31 +131,17 @@ void brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir, bool (*fn)(struct sk_buff *, void *), void *arg) { - struct pktq_prec *q; - struct sk_buff *p, *prev = NULL; + struct sk_buff_head *q; + struct sk_buff *p, *next; - q = &pq->q[prec]; - p = q->head; - while (p) { + q = &pq->q[prec].skblist; + skb_queue_walk_safe(q, p, next) { if (fn == NULL || (*fn) (p, arg)) { - bool head = (p == q->head); - if (head) - q->head = p->prev; - else - prev->prev = p->prev; - p->prev = NULL; + skb_unlink(p, q); brcmu_pkt_buf_free_skb(p); - q->len--; pq->len--; - p = (head ? q->head : prev->prev); - } else { - prev = p; - p = p->prev; } } - - if (q->head == NULL) - q->tail = NULL; } EXPORT_SYMBOL(brcmu_pktq_pflush); @@ -242,8 +166,10 @@ void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len) pq->max = (u16) max_len; - for (prec = 0; prec < num_prec; prec++) + for (prec = 0; prec < num_prec; prec++) { pq->q[prec].max = pq->max; + skb_queue_head_init(&pq->q[prec].skblist); + } } EXPORT_SYMBOL(brcmu_pktq_init); @@ -255,13 +181,13 @@ struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out) return NULL; for (prec = 0; prec < pq->hi_prec; prec++) - if (pq->q[prec].head) + if (!skb_queue_empty(&pq->q[prec].skblist)) break; if (prec_out) *prec_out = prec; - return pq->q[prec].tail; + return skb_peek_tail(&pq->q[prec].skblist); } EXPORT_SYMBOL(brcmu_pktq_peek_tail); @@ -274,7 +200,7 @@ int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp) for (prec = 0; prec <= pq->hi_prec; prec++) if (prec_bmp & (1 << prec)) - len += pq->q[prec].len; + len += pq->q[prec].skblist.qlen; return len; } @@ -284,39 +210,32 @@ EXPORT_SYMBOL(brcmu_pktq_mlen); struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) { - struct pktq_prec *q; + struct sk_buff_head *q; struct sk_buff *p; int prec; if (pq->len == 0) return NULL; - while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + while ((prec = pq->hi_prec) > 0 && + skb_queue_empty(&pq->q[prec].skblist)) pq->hi_prec--; - while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) + while ((prec_bmp & (1 << prec)) == 0 || + skb_queue_empty(&pq->q[prec].skblist)) if (prec-- == 0) return NULL; - q = &pq->q[prec]; - - p = q->head; + q = &pq->q[prec].skblist; + p = skb_dequeue(q); if (p == NULL) return NULL; - q->head = p->prev; - if (q->head == NULL) - q->tail = NULL; - - q->len--; + pq->len--; if (prec_out) *prec_out = prec; - pq->len--; - - p->prev = NULL; - return p; } EXPORT_SYMBOL(brcmu_pktq_mdeq); diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index ccf60151953c..ad249a0b4730 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -65,9 +65,7 @@ #define ETHER_ADDR_STR_LEN 18 struct pktq_prec { - struct sk_buff *head; /* first packet to dequeue */ - struct sk_buff *tail; /* last packet to dequeue */ - u16 len; /* number of queued packets */ + struct sk_buff_head skblist; u16 max; /* maximum number of queued packets */ }; @@ -88,32 +86,32 @@ struct pktq { static inline int pktq_plen(struct pktq *pq, int prec) { - return pq->q[prec].len; + return pq->q[prec].skblist.qlen; } static inline int pktq_pavail(struct pktq *pq, int prec) { - return pq->q[prec].max - pq->q[prec].len; + return pq->q[prec].max - pq->q[prec].skblist.qlen; } static inline bool pktq_pfull(struct pktq *pq, int prec) { - return pq->q[prec].len >= pq->q[prec].max; + return pq->q[prec].skblist.qlen >= pq->q[prec].max; } static inline bool pktq_pempty(struct pktq *pq, int prec) { - return pq->q[prec].len == 0; + return skb_queue_empty(&pq->q[prec].skblist); } static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec) { - return pq->q[prec].head; + return skb_peek(&pq->q[prec].skblist); } static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec) { - return pq->q[prec].tail; + return skb_peek_tail(&pq->q[prec].skblist); } extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, @@ -172,9 +170,6 @@ extern void brcmu_pktq_flush(struct pktq *pq, bool dir, bool (*fn)(struct sk_buff *, void *), void *arg); /* externs */ -/* packet */ -extern uint brcmu_pkttotlen(struct sk_buff *p); - /* ip address */ struct ipv4_addr; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 99a710dfe771..99575884ff52 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -131,6 +131,14 @@ static struct ieee80211_rate ipw2200_rates[] = { #define ipw2200_bg_rates (ipw2200_rates + 0) #define ipw2200_num_bg_rates 12 +/* Ugly macro to convert literal channel numbers into their mhz equivalents + * There are certianly some conditions that will break this (like feeding it '30') + * but they shouldn't arise since nothing talks on channel 30. */ +#define ieee80211chan2mhz(x) \ + (((x) <= 14) ? \ + (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ + ((x) + 1000) * 5) + #ifdef CONFIG_IPW2200_QOS static int qos_enable = 0; static int qos_burst_enable = 0; diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index c73e5ed8db5e..a7ab280994c8 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,6 +1,6 @@ # WIFI obj-$(CONFIG_IWLWIFI) += iwlwifi.o -iwlwifi-objs := iwl-agn.o iwl-agn-rs.o +iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 79431977a968..b3193571ed07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -270,11 +270,6 @@ struct iwl_cfg iwl2000_2bgn_cfg = { .ht_params = &iwl2000_ht_params, }; -struct iwl_cfg iwl2000_2bg_cfg = { - .name = "2000 Series 2x2 BG", - IWL_DEVICE_2000, -}; - struct iwl_cfg iwl2000_2bgn_d_cfg = { .name = "2000D Series 2x2 BGN", IWL_DEVICE_2000, @@ -304,11 +299,6 @@ struct iwl_cfg iwl2030_2bgn_cfg = { .ht_params = &iwl2000_ht_params, }; -struct iwl_cfg iwl2030_2bg_cfg = { - .name = "2000 Series 2x2 BG/BT", - IWL_DEVICE_2030, -}; - #define IWL_DEVICE_105 \ .fw_name_pre = IWL105_FW_PRE, \ .ucode_api_max = IWL105_UCODE_API_MAX, \ @@ -326,11 +316,6 @@ struct iwl_cfg iwl2030_2bg_cfg = { .rx_with_siso_diversity = true, \ .iq_invert = true \ -struct iwl_cfg iwl105_bg_cfg = { - .name = "105 Series 1x1 BG", - IWL_DEVICE_105, -}; - struct iwl_cfg iwl105_bgn_cfg = { .name = "105 Series 1x1 BGN", IWL_DEVICE_105, @@ -361,11 +346,6 @@ struct iwl_cfg iwl105_bgn_d_cfg = { .rx_with_siso_diversity = true, \ .iq_invert = true \ -struct iwl_cfg iwl135_bg_cfg = { - .name = "135 Series 1x1 BG/BT", - IWL_DEVICE_135, -}; - struct iwl_cfg iwl135_bgn_cfg = { .name = "135 Series 1x1 BGN/BT", IWL_DEVICE_135, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c840c78278db..ee3363fdf309 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -439,16 +439,6 @@ struct iwl_cfg iwl6035_2agn_cfg = { .ht_params = &iwl6000_ht_params, }; -struct iwl_cfg iwl6035_2abg_cfg = { - .name = "6035 Series 2x2 ABG/BT", - IWL_DEVICE_6030, -}; - -struct iwl_cfg iwl6035_2bg_cfg = { - .name = "6035 Series 2x2 BG/BT", - IWL_DEVICE_6030, -}; - struct iwl_cfg iwl1030_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", IWL_DEVICE_6030, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 1a52ed29f2d6..0bc962217351 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -827,6 +827,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) case IEEE80211_SMPS_STATIC: case IEEE80211_SMPS_DYNAMIC: return IWL_NUM_IDLE_CHAINS_SINGLE; + case IEEE80211_SMPS_AUTOMATIC: case IEEE80211_SMPS_OFF: return active_cnt; default: @@ -983,3 +984,360 @@ void iwlagn_remove_notification(struct iwl_priv *priv, list_del(&wait_entry->list); spin_unlock_bh(&priv->notif_wait_lock); } + +#ifdef CONFIG_PM_SLEEP +static void iwlagn_convert_p1k(u16 *p1k, __le16 *out) +{ + int i; + + for (i = 0; i < IWLAGN_P1K_SIZE; i++) + out[i] = cpu_to_le16(p1k[i]); +} + +struct wowlan_key_data { + struct iwl_rxon_context *ctx; + struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc; + struct iwlagn_wowlan_tkip_params_cmd *tkip; + const u8 *bssid; + bool error, use_rsc_tsc, use_tkip; +}; + + +static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_priv *priv = hw->priv; + struct wowlan_key_data *data = _data; + struct iwl_rxon_context *ctx = data->ctx; + struct aes_sc *aes_sc, *aes_tx_sc = NULL; + struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; + struct iwlagn_p1k_cache *rx_p1ks; + u8 *rx_mic_key; + struct ieee80211_key_seq seq; + u32 cur_rx_iv32 = 0; + u16 p1k[IWLAGN_P1K_SIZE]; + int ret, i; + + mutex_lock(&priv->shrd->mutex); + + if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) && + !sta && !ctx->key_mapping_keys) + ret = iwl_set_default_wep_key(priv, ctx, key); + else + ret = iwl_set_dynamic_key(priv, ctx, key, sta); + + if (ret) { + IWL_ERR(priv, "Error setting key during suspend!\n"); + data->error = true; + } + + switch (key->cipher) { + 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); + iwlagn_convert_p1k(p1k, data->tkip->tx.p1k); + + memcpy(data->tkip->mic_keys.tx, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + IWLAGN_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 < IWLAGN_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, data->bssid, cur_rx_iv32, p1k); + iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k); + ieee80211_get_tkip_rx_p1k(key, data->bssid, + cur_rx_iv32 + 1, p1k); + iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k); + + memcpy(rx_mic_key, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + IWLAGN_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 < IWLAGN_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; + } + + mutex_unlock(&priv->shrd->mutex); +} + +int iwlagn_send_patterns(struct iwl_priv *priv, + struct cfg80211_wowlan *wowlan) +{ + struct iwlagn_wowlan_patterns_cmd *pattern_cmd; + struct iwl_host_cmd cmd = { + .id = REPLY_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 iwlagn_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_trans_send_cmd(trans(priv), &cmd); + kfree(pattern_cmd); + return err; +} + +int iwlagn_suspend(struct iwl_priv *priv, + struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) +{ + struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd; + struct iwl_rxon_cmd rxon; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd; + struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {}; + struct iwlagn_d3_config_cmd d3_cfg_cmd = {}; + struct wowlan_key_data key_data = { + .ctx = ctx, + .bssid = ctx->active.bssid_addr, + .use_rsc_tsc = false, + .tkip = &tkip_cmd, + .use_tkip = false, + }; + int ret, i; + u16 seq; + + key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); + if (!key_data.rsc_tsc) + return -ENOMEM; + + memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd)); + + /* + * We know the last used seqno, and the uCode expects to know that + * one, it will increment before TX. + */ + seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ; + wakeup_filter_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. + */ + for (i = 0; i < 8; i++) { + seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number; + seq -= 0x10; + wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq); + } + + if (wowlan->disconnect) + wakeup_filter_cmd.enabled |= + cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS | + IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE); + if (wowlan->magic_pkt) + wakeup_filter_cmd.enabled |= + cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET); + if (wowlan->gtk_rekey_failure) + wakeup_filter_cmd.enabled |= + cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL); + if (wowlan->eap_identity_req) + wakeup_filter_cmd.enabled |= + cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ); + if (wowlan->four_way_handshake) + wakeup_filter_cmd.enabled |= + cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE); + if (wowlan->n_patterns) + wakeup_filter_cmd.enabled |= + cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH); + + if (wowlan->rfkill_release) + d3_cfg_cmd.wakeup_flags |= + cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL); + + iwl_scan_cancel_timeout(priv, 200); + + memcpy(&rxon, &ctx->active, sizeof(rxon)); + + iwl_trans_stop_device(trans(priv)); + + priv->shrd->wowlan = true; + + ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); + if (ret) + goto out; + + /* now configure WoWLAN ucode */ + ret = iwl_alive_start(priv); + if (ret) + goto out; + + memcpy(&ctx->staging, &rxon, sizeof(rxon)); + ret = iwlagn_commit_rxon(priv, ctx); + if (ret) + goto out; + + ret = iwl_power_update_mode(priv, true); + if (ret) + goto out; + + if (!iwlagn_mod_params.sw_crypto) { + /* mark all keys clear */ + priv->ucode_key_table = 0; + ctx->key_mapping_keys = 0; + + /* + * 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(&priv->shrd->mutex); + ieee80211_iter_keys(priv->hw, ctx->vif, + iwlagn_wowlan_program_keys, + &key_data); + mutex_lock(&priv->shrd->mutex); + if (key_data.error) { + ret = -EIO; + goto out; + } + + if (key_data.use_rsc_tsc) { + struct iwl_host_cmd rsc_tsc_cmd = { + .id = REPLY_WOWLAN_TSC_RSC_PARAMS, + .flags = CMD_SYNC, + .data[0] = key_data.rsc_tsc, + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, + .len[0] = sizeof(key_data.rsc_tsc), + }; + + ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd); + if (ret) + goto out; + } + + if (key_data.use_tkip) { + ret = iwl_trans_send_cmd_pdu(trans(priv), + REPLY_WOWLAN_TKIP_PARAMS, + CMD_SYNC, sizeof(tkip_cmd), + &tkip_cmd); + if (ret) + goto out; + } + + if (priv->have_rekey_data) { + memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); + memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN); + kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN); + memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN); + kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN); + kek_kck_cmd.replay_ctr = priv->replay_ctr; + + ret = iwl_trans_send_cmd_pdu(trans(priv), + REPLY_WOWLAN_KEK_KCK_MATERIAL, + CMD_SYNC, sizeof(kek_kck_cmd), + &kek_kck_cmd); + if (ret) + goto out; + } + } + + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC, + sizeof(d3_cfg_cmd), &d3_cfg_cmd); + if (ret) + goto out; + + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER, + CMD_SYNC, sizeof(wakeup_filter_cmd), + &wakeup_filter_cmd); + if (ret) + goto out; + + ret = iwlagn_send_patterns(priv, wowlan); + out: + kfree(key_data.rsc_tsc); + return ret; +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 66118cea2af3..359c47a4fcea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1458,10 +1458,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW: /* avoid antenna B unless MIMO */ - valid_tx_ant = - first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; + tbl->action = IWL_LEGACY_SWITCH_SISO; break; case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: @@ -1636,10 +1634,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW: /* avoid antenna B unless MIMO */ - valid_tx_ant = - first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) - tbl->action = IWL_SISO_SWITCH_ANTENNA1; + tbl->action = IWL_SISO_SWITCH_MIMO2_AB; break; case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 5af9e6258a16..fdb4c3786114 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -800,7 +800,8 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, ctx->active.bssid_addr)) continue; ctx->last_tx_rejected = false; - iwl_trans_wake_any_queue(trans(priv), ctx->ctxid); + iwl_trans_wake_any_queue(trans(priv), ctx->ctxid, + "channel got active"); } } @@ -1032,6 +1033,50 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, return 0; } +static int iwlagn_rx_noa_notification(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + struct iwl_wipan_noa_data *new_data, *old_data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->u.raw; + + /* no condition -- we're in softirq */ + old_data = rcu_dereference_protected(priv->noa_data, true); + + if (noa_notif->noa_active) { + u32 len = le16_to_cpu(noa_notif->noa_attribute.length); + u32 copylen = len; + + /* EID, len, OUI, subtype */ + len += 1 + 1 + 3 + 1; + /* P2P id, P2P length */ + len += 1 + 2; + copylen += 1 + 2; + + new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC); + if (new_data) { + new_data->length = len; + new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC; + new_data->data[1] = len - 2; /* not counting EID, len */ + new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff; + new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff; + new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff; + new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P; + memcpy(&new_data->data[6], &noa_notif->noa_attribute, + copylen); + } + } else + new_data = NULL; + + rcu_assign_pointer(priv->noa_data, new_data); + + if (old_data) + kfree_rcu(old_data, rcu_head); + + return 0; +} + /** * iwl_setup_rx_handlers - Initialize Rx handler callbacks * @@ -1055,6 +1100,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif; handlers[REPLY_ADD_STA] = iwl_add_sta_callback; + handlers[REPLY_WIPAN_NOA_NOTIFICATION] = iwlagn_rx_noa_notification; + /* * The same handler is used for both the REPLY to a discrete * statistics request from the host as well as for the periodic diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 58a381c01c89..8de97f5a1825 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -45,7 +45,8 @@ static int iwlagn_disable_bss(struct iwl_priv *priv, send->filter_flags = old_filter; if (ret) - IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret); + IWL_DEBUG_QUIET_RFKILL(priv, + "Error clearing ASSOC_MSK on BSS (%d)\n", ret); return ret; } @@ -116,7 +117,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv, if (ctx->ht.enabled) ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", + IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", ctx->qos_data.qos_active, ctx->qos_data.def_qos_parm.qos_flags); @@ -124,7 +125,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv, sizeof(struct iwl_qosparam_cmd), &ctx->qos_data.def_qos_parm); if (ret) - IWL_ERR(priv, "Failed to update QoS\n"); + IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n"); } static int iwlagn_update_beacon(struct iwl_priv *priv, @@ -541,6 +542,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&priv->shrd->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) + goto out; + if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) { IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); goto out; @@ -840,7 +844,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (ctx->last_tx_rejected) { ctx->last_tx_rejected = false; iwl_trans_wake_any_queue(trans(priv), - ctx->ctxid); + ctx->ctxid, + "Disassoc: flush queue"); } ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index ed6283623932..901fd9485d75 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -647,7 +647,7 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) int ret; struct iwl_addsta_cmd sta_cmd; struct iwl_link_quality_cmd lq; - bool active; + bool active, have_lq = false; spin_lock_irqsave(&priv->shrd->sta_lock, flags); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { @@ -657,7 +657,10 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); sta_cmd.mode = 0; - memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq)); + if (priv->stations[sta_id].lq) { + memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq)); + have_lq = true; + } active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE; priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; @@ -679,7 +682,8 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (ret) IWL_ERR(priv, "failed to re-add STA %pM (%d)\n", priv->stations[sta_id].sta.sta.addr, ret); - iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); + if (have_lq) + iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); } int iwl_get_free_ucode_key_offset(struct iwl_priv *priv) @@ -825,28 +829,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, return ret; } -int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - int ret; - - IWL_DEBUG_MAC80211(priv, "enter: received request to remove " - "station %pM\n", sta->addr); - mutex_lock(&priv->shrd->mutex); - IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", - sta->addr); - ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr); - if (ret) - IWL_ERR(priv, "Error removing station %pM\n", - sta->addr); - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return ret; -} void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id, struct iwl_link_quality_cmd *link_cmd) @@ -1464,20 +1446,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); } -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - spin_lock_irqsave(&priv->shrd->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.sleep_tx_count = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); - -} void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) { @@ -1494,36 +1463,3 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); } - -void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - int sta_id; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - switch (cmd) { - case STA_NOTIFY_SLEEP: - WARN_ON(!sta_priv->client); - sta_priv->asleep = true; - if (atomic_read(&sta_priv->pending_frames) > 0) - ieee80211_sta_block_awake(hw, sta, true); - break; - case STA_NOTIFY_AWAKE: - WARN_ON(!sta_priv->client); - if (!sta_priv->asleep) - break; - sta_priv->asleep = false; - sta_id = iwl_sta_id(sta); - if (sta_id != IWL_INVALID_STATION) - iwl_sta_modify_ps_wake(priv, sta_id); - break; - default: - break; - } - IWL_DEBUG_MAC80211(priv, "leave\n"); -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 35a6b71f358c..e6a02e09ee18 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -283,6 +283,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif + if (unlikely(ieee80211_is_probe_resp(fc))) { + struct iwl_wipan_noa_data *noa_data = + rcu_dereference(priv->noa_data); + + if (noa_data && + pskb_expand_head(skb, 0, noa_data->length, + GFP_ATOMIC) == 0) { + memcpy(skb_put(skb, noa_data->length), + noa_data->data, noa_data->length); + hdr = (struct ieee80211_hdr *)skb->data; + } + } + hdr_len = ieee80211_hdrlen(fc); /* For management frames use broadcast id to do not break aggregation */ @@ -800,7 +813,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, iwl_is_associated_ctx(ctx) && ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) { ctx->last_tx_rejected = true; - iwl_trans_stop_queue(trans(priv), txq_id); + iwl_trans_stop_queue(trans(priv), txq_id, + "Tx on passive channel"); IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) " diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 8ba0dd54e37d..9ec315b31d45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/dma-mapping.h> #include "iwl-dev.h" #include "iwl-core.h" @@ -72,51 +73,98 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS} }; +/****************************************************************************** + * + * uCode download functions + * + ******************************************************************************/ + +static void iwl_free_fw_desc(struct iwl_bus *bus, struct fw_desc *desc) +{ + if (desc->v_addr) + dma_free_coherent(bus->dev, desc->len, + desc->v_addr, desc->p_addr); + desc->v_addr = NULL; + desc->len = 0; +} + +static void iwl_free_fw_img(struct iwl_bus *bus, struct fw_img *img) +{ + iwl_free_fw_desc(bus, &img->code); + iwl_free_fw_desc(bus, &img->data); +} + +void iwl_dealloc_ucode(struct iwl_trans *trans) +{ + iwl_free_fw_img(bus(trans), &trans->ucode_rt); + iwl_free_fw_img(bus(trans), &trans->ucode_init); + iwl_free_fw_img(bus(trans), &trans->ucode_wowlan); +} + +int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, + const void *data, size_t len) +{ + if (!len) { + desc->v_addr = NULL; + return -EINVAL; + } + + desc->v_addr = dma_alloc_coherent(bus->dev, len, + &desc->p_addr, GFP_KERNEL); + if (!desc->v_addr) + return -ENOMEM; + + desc->len = len; + memcpy(desc->v_addr, data, len); + return 0; +} + /* * ucode */ -static int iwlagn_load_section(struct iwl_priv *priv, const char *name, +static int iwlagn_load_section(struct iwl_trans *trans, const char *name, struct fw_desc *image, u32 dst_addr) { + struct iwl_bus *bus = bus(trans); dma_addr_t phy_addr = image->p_addr; u32 byte_cnt = image->len; int ret; - priv->ucode_write_complete = 0; + trans->ucode_write_complete = 0; - iwl_write_direct32(bus(priv), + iwl_write_direct32(bus, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); - iwl_write_direct32(bus(priv), + iwl_write_direct32(bus, FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); - iwl_write_direct32(bus(priv), + iwl_write_direct32(bus, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - iwl_write_direct32(bus(priv), + iwl_write_direct32(bus, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), (iwl_get_dma_hi_addr(phy_addr) << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); - iwl_write_direct32(bus(priv), + iwl_write_direct32(bus, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); - iwl_write_direct32(bus(priv), + iwl_write_direct32(bus, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name); - ret = wait_event_timeout(priv->shrd->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); + IWL_DEBUG_FW(bus, "%s uCode section being loaded...\n", name); + ret = wait_event_timeout(trans->shrd->wait_command_queue, + trans->ucode_write_complete, 5 * HZ); if (!ret) { - IWL_ERR(priv, "Could not load the %s uCode section\n", + IWL_ERR(trans, "Could not load the %s uCode section\n", name); return -ETIMEDOUT; } @@ -124,17 +172,41 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, return 0; } -static int iwlagn_load_given_ucode(struct iwl_priv *priv, - struct fw_img *image) +static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, + enum iwl_ucode_type ucode_type) +{ + switch (ucode_type) { + case IWL_UCODE_INIT: + return &trans->ucode_init; + case IWL_UCODE_WOWLAN: + return &trans->ucode_wowlan; + case IWL_UCODE_REGULAR: + return &trans->ucode_rt; + case IWL_UCODE_NONE: + break; + } + return NULL; +} + +static int iwlagn_load_given_ucode(struct iwl_trans *trans, + enum iwl_ucode_type ucode_type) { int ret = 0; + struct fw_img *image = iwl_get_ucode_image(trans, ucode_type); + + + if (!image) { + IWL_ERR(trans, "Invalid ucode requested (%d)\n", + ucode_type); + return -EINVAL; + } - ret = iwlagn_load_section(priv, "INST", &image->code, + ret = iwlagn_load_section(trans, "INST", &image->code, IWLAGN_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwlagn_load_section(priv, "DATA", &image->data, + return iwlagn_load_section(trans, "DATA", &image->data, IWLAGN_RTC_DATA_LOWER_BOUND); } @@ -418,7 +490,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwl_verify_inst_sparse(struct iwl_priv *priv, +static int iwl_verify_inst_sparse(struct iwl_bus *bus, struct fw_desc *fw_desc) { __le32 *image = (__le32 *)fw_desc->v_addr; @@ -426,15 +498,15 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, u32 val; u32 i; - IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len); for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR, + iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); + val = iwl_read32(bus, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) return -EIO; } @@ -442,7 +514,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, return 0; } -static void iwl_print_mismatch_inst(struct iwl_priv *priv, +static void iwl_print_mismatch_inst(struct iwl_bus *bus, struct fw_desc *fw_desc) { __le32 *image = (__le32 *)fw_desc->v_addr; @@ -451,18 +523,18 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, u32 offs; int errors = 0; - IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); + IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len); - iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR, + iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); for (offs = 0; offs < len && errors < 20; offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); + val = iwl_read32(bus, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section at " + IWL_ERR(bus, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", offs, val, le32_to_cpu(*image)); errors++; @@ -474,16 +546,24 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) +static int iwl_verify_ucode(struct iwl_trans *trans, + enum iwl_ucode_type ucode_type) { - if (!iwl_verify_inst_sparse(priv, &img->code)) { - IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n"); + struct fw_img *img = iwl_get_ucode_image(trans, ucode_type); + + if (!img) { + IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type); + return -EINVAL; + } + + if (!iwl_verify_inst_sparse(bus(trans), &img->code)) { + IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n"); return 0; } - IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - iwl_print_mismatch_inst(priv, &img->code); + iwl_print_mismatch_inst(bus(trans), &img->code); return -EIO; } @@ -519,13 +599,12 @@ static void iwlagn_alive_fn(struct iwl_priv *priv, #define UCODE_CALIB_TIMEOUT (2*HZ) int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, - struct fw_img *image, - enum iwlagn_ucode_type ucode_type) + enum iwl_ucode_type ucode_type) { struct iwl_notification_wait alive_wait; struct iwlagn_alive_data alive_data; int ret; - enum iwlagn_ucode_type old_type; + enum iwl_ucode_type old_type; ret = iwl_trans_start_device(trans(priv)); if (ret) @@ -537,7 +616,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, old_type = priv->ucode_type; priv->ucode_type = ucode_type; - ret = iwlagn_load_given_ucode(priv, image); + ret = iwlagn_load_given_ucode(trans(priv), ucode_type); if (ret) { priv->ucode_type = old_type; iwlagn_remove_notification(priv, &alive_wait); @@ -568,7 +647,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, * skip it for WoWLAN. */ if (ucode_type != IWL_UCODE_WOWLAN) { - ret = iwl_verify_ucode(priv, image); + ret = iwl_verify_ucode(trans(priv), ucode_type); if (ret) { priv->ucode_type = old_type; return ret; @@ -597,7 +676,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) lockdep_assert_held(&priv->shrd->mutex); /* No init ucode required? Curious, but maybe ok */ - if (!priv->ucode_init.code.len) + if (!trans(priv)->ucode_init.code.len) return 0; if (priv->ucode_type != IWL_UCODE_NONE) @@ -608,8 +687,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) NULL, NULL); /* Will also start the device */ - ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, - IWL_UCODE_INIT); + ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 9d463cf40380..e235e84de8b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -30,7 +30,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> -#include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/skbuff.h> @@ -452,52 +451,6 @@ static void iwl_bg_tx_flush(struct work_struct *work) iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); } -/****************************************************************************** - * - * uCode download functions - * - ******************************************************************************/ - -static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc) -{ - if (desc->v_addr) - dma_free_coherent(bus(priv)->dev, desc->len, - desc->v_addr, desc->p_addr); - desc->v_addr = NULL; - desc->len = 0; -} - -static void iwl_free_fw_img(struct iwl_priv *priv, struct fw_img *img) -{ - iwl_free_fw_desc(priv, &img->code); - iwl_free_fw_desc(priv, &img->data); -} - -static void iwl_dealloc_ucode(struct iwl_priv *priv) -{ - iwl_free_fw_img(priv, &priv->ucode_rt); - iwl_free_fw_img(priv, &priv->ucode_init); - iwl_free_fw_img(priv, &priv->ucode_wowlan); -} - -static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc, - const void *data, size_t len) -{ - if (!len) { - desc->v_addr = NULL; - return -EINVAL; - } - - desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len, - &desc->p_addr, GFP_KERNEL); - if (!desc->v_addr) - return -ENOMEM; - - desc->len = len; - memcpy(desc->v_addr, data, len); - return 0; -} - static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) { int i; @@ -555,16 +508,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); } - -struct iwlagn_ucode_capabilities { - u32 max_probe_length; - u32 standard_phy_calibration_size; - u32 flags; -}; - static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); -static int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa); #define UCODE_EXPERIMENTAL_INDEX 100 #define UCODE_EXPERIMENTAL_TAG "exp" @@ -1040,30 +984,32 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.code, + if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code, pieces.inst, pieces.inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.data, + if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.data, pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - if (iwl_alloc_fw_desc(priv, &priv->ucode_init.code, + if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code, pieces.init, pieces.init_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(priv, &priv->ucode_init.data, + if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data, pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } /* WoWLAN instructions and data */ if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { - if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.code, + if (iwl_alloc_fw_desc(bus(priv), + &trans(priv)->ucode_wowlan.code, pieces.wowlan_inst, pieces.wowlan_inst_size)) goto err_pci_alloc; - if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.data, + if (iwl_alloc_fw_desc(bus(priv), + &trans(priv)->ucode_wowlan.data, pieces.wowlan_data, pieces.wowlan_data_size)) goto err_pci_alloc; @@ -1156,7 +1102,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) err_pci_alloc: IWL_ERR(priv, "failed to allocate pci memory\n"); - iwl_dealloc_ucode(priv); + iwl_dealloc_ucode(trans(priv)); out_unbind: complete(&priv->firmware_loading_complete); device_release_driver(bus(priv)->dev); @@ -1352,7 +1298,7 @@ int iwl_alive_start(struct iwl_priv *priv) static void iwl_cancel_deferred_work(struct iwl_priv *priv); -static void __iwl_down(struct iwl_priv *priv) +void __iwl_down(struct iwl_priv *priv) { int exit_pending; @@ -1415,7 +1361,7 @@ static void __iwl_down(struct iwl_priv *priv) priv->beacon_skb = NULL; } -static void iwl_down(struct iwl_priv *priv) +void iwl_down(struct iwl_priv *priv) { mutex_lock(&priv->shrd->mutex); __iwl_down(priv); @@ -1424,57 +1370,6 @@ static void iwl_down(struct iwl_priv *priv) iwl_cancel_deferred_work(priv); } -#define MAX_HW_RESTARTS 5 - -static int __iwl_up(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx; - int ret; - - lockdep_assert_held(&priv->shrd->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { - IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); - return -EIO; - } - - for_each_context(priv, ctx) { - ret = iwlagn_alloc_bcast_station(priv, ctx); - if (ret) { - iwl_dealloc_bcast_stations(priv); - return ret; - } - } - - ret = iwlagn_run_init_ucode(priv); - if (ret) { - IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); - goto error; - } - - ret = iwlagn_load_ucode_wait_alive(priv, - &priv->ucode_rt, - IWL_UCODE_REGULAR); - if (ret) { - IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); - goto error; - } - - ret = iwl_alive_start(priv); - if (ret) - goto error; - return 0; - - error: - set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); - __iwl_down(priv); - clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); - - IWL_ERR(priv, "Unable to initialize device.\n"); - return ret; -} - - /***************************************************************************** * * Workqueue callbacks @@ -1502,7 +1397,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) mutex_unlock(&priv->shrd->mutex); } -static void iwlagn_prepare_restart(struct iwl_priv *priv) +void iwlagn_prepare_restart(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; bool bt_full_concurrent; @@ -1559,1180 +1454,8 @@ static void iwl_bg_restart(struct work_struct *data) } } -/***************************************************************************** - * - * mac80211 entry point functions - * - *****************************************************************************/ - -static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_AP), - }, -}; - -static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = { - { - .max = 2, - .types = BIT(NL80211_IFTYPE_STATION), - }, -}; - -static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_AP), - }, -}; - -static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = { - { - .max = 2, - .types = BIT(NL80211_IFTYPE_STATION), - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT), - }, -}; - -static const struct ieee80211_iface_combination -iwlagn_iface_combinations_dualmode[] = { - { .num_different_channels = 1, - .max_interfaces = 2, - .beacon_int_infra_match = true, - .limits = iwlagn_sta_ap_limits, - .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits), - }, - { .num_different_channels = 1, - .max_interfaces = 2, - .limits = iwlagn_2sta_limits, - .n_limits = ARRAY_SIZE(iwlagn_2sta_limits), - }, -}; - -static const struct ieee80211_iface_combination -iwlagn_iface_combinations_p2p[] = { - { .num_different_channels = 1, - .max_interfaces = 2, - .beacon_int_infra_match = true, - .limits = iwlagn_p2p_sta_go_limits, - .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits), - }, - { .num_different_channels = 1, - .max_interfaces = 2, - .limits = iwlagn_p2p_2sta_limits, - .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits), - }, -}; - -/* - * Not a mac80211 entry point function, but it fits in with all the - * other mac80211 functions grouped here. - */ -static int iwlagn_mac_setup_register(struct iwl_priv *priv, - struct iwlagn_ucode_capabilities *capa) -{ - int ret; - struct ieee80211_hw *hw = priv->hw; - struct iwl_rxon_context *ctx; - - hw->rate_control_algorithm = "iwl-agn-rs"; - - /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_NEED_DTIM_PERIOD | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_REPORTS_TX_ACK_STATUS; - - /* - * Including the following line will crash some AP's. This - * workaround removes the stimulus which causes the crash until - * the AP software can be fixed. - hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - */ - - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) - hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; - - if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) - hw->flags |= IEEE80211_HW_MFP_CAPABLE; - - hw->sta_data_size = sizeof(struct iwl_station_priv); - hw->vif_data_size = sizeof(struct iwl_vif_priv); - - for_each_context(priv, ctx) { - hw->wiphy->interface_modes |= ctx->interface_modes; - hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; - } - - BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); - - if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) { - hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p; - hw->wiphy->n_iface_combinations = - ARRAY_SIZE(iwlagn_iface_combinations_p2p); - } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { - hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode; - hw->wiphy->n_iface_combinations = - ARRAY_SIZE(iwlagn_iface_combinations_dualmode); - } - - hw->wiphy->max_remain_on_channel_duration = 1000; - - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; - - if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) { - hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | - WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_EAP_IDENTITY_REQ | - WIPHY_WOWLAN_RFKILL_RELEASE; - if (!iwlagn_mod_params.sw_crypto) - hw->wiphy->wowlan.flags |= - WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | - WIPHY_WOWLAN_GTK_REKEY_FAILURE; - - hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS; - hw->wiphy->wowlan.pattern_min_len = - IWLAGN_WOWLAN_MIN_PATTERN_LEN; - hw->wiphy->wowlan.pattern_max_len = - IWLAGN_WOWLAN_MAX_PATTERN_LEN; - } - - if (iwlagn_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->max_scan_ssids = PROBE_OPTION_MAX; - /* we create the 802.11 header and a zero-length SSID element */ - hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2; - - /* Default value; 4 EDCA QOS priorities */ - hw->queues = 4; - - hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; - - iwl_leds_init(priv); - - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); - return ret; - } - priv->mac80211_registered = 1; - - return 0; -} - -static int iwlagn_mac_start(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - int ret; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - /* we should be verifying the device is ready to be opened */ - mutex_lock(&priv->shrd->mutex); - ret = __iwl_up(priv); - mutex_unlock(&priv->shrd->mutex); - if (ret) - return ret; - - IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - - /* Now we should be done, and the READY bit should be set. */ - if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status))) - ret = -EIO; - - iwlagn_led_enable(priv); - - priv->is_open = 1; - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - -static void iwlagn_mac_stop(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!priv->is_open) - return; - priv->is_open = 0; - - iwl_down(priv); - - flush_workqueue(priv->shrd->workqueue); - - /* User space software may expect getting rfkill changes - * even if interface is down */ - iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF); - iwl_enable_rfkill_int(priv); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -#ifdef CONFIG_PM_SLEEP -static int iwlagn_send_patterns(struct iwl_priv *priv, - struct cfg80211_wowlan *wowlan) -{ - struct iwlagn_wowlan_patterns_cmd *pattern_cmd; - struct iwl_host_cmd cmd = { - .id = REPLY_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 iwlagn_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_trans_send_cmd(trans(priv), &cmd); - kfree(pattern_cmd); - return err; -} -#endif - -static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_gtk_rekey_data *data) -{ - struct iwl_priv *priv = hw->priv; - - if (iwlagn_mod_params.sw_crypto) - return; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif) - goto out; - - memcpy(priv->kek, data->kek, NL80211_KEK_LEN); - memcpy(priv->kck, data->kck, NL80211_KCK_LEN); - priv->replay_ctr = cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr)); - priv->have_rekey_data = true; - - out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -struct wowlan_key_data { - struct iwl_rxon_context *ctx; - struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc; - struct iwlagn_wowlan_tkip_params_cmd *tkip; - const u8 *bssid; - bool error, use_rsc_tsc, use_tkip; -}; - -#ifdef CONFIG_PM_SLEEP -static void iwlagn_convert_p1k(u16 *p1k, __le16 *out) -{ - int i; - - for (i = 0; i < IWLAGN_P1K_SIZE; i++) - out[i] = cpu_to_le16(p1k[i]); -} - -static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *_data) -{ - struct iwl_priv *priv = hw->priv; - struct wowlan_key_data *data = _data; - struct iwl_rxon_context *ctx = data->ctx; - struct aes_sc *aes_sc, *aes_tx_sc = NULL; - struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; - struct iwlagn_p1k_cache *rx_p1ks; - u8 *rx_mic_key; - struct ieee80211_key_seq seq; - u32 cur_rx_iv32 = 0; - u16 p1k[IWLAGN_P1K_SIZE]; - int ret, i; - - mutex_lock(&priv->shrd->mutex); - - if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) && - !sta && !ctx->key_mapping_keys) - ret = iwl_set_default_wep_key(priv, ctx, key); - else - ret = iwl_set_dynamic_key(priv, ctx, key, sta); - - if (ret) { - IWL_ERR(priv, "Error setting key during suspend!\n"); - data->error = true; - } - - switch (key->cipher) { - 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); - iwlagn_convert_p1k(p1k, data->tkip->tx.p1k); - - memcpy(data->tkip->mic_keys.tx, - &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], - IWLAGN_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 < IWLAGN_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, data->bssid, cur_rx_iv32, p1k); - iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k); - ieee80211_get_tkip_rx_p1k(key, data->bssid, - cur_rx_iv32 + 1, p1k); - iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k); - - memcpy(rx_mic_key, - &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], - IWLAGN_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 < IWLAGN_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; - } - - mutex_unlock(&priv->shrd->mutex); -} - -static int iwlagn_mac_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan) -{ - struct iwl_priv *priv = hw->priv; - struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd; - struct iwl_rxon_cmd rxon; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd; - struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {}; - struct wowlan_key_data key_data = { - .ctx = ctx, - .bssid = ctx->active.bssid_addr, - .use_rsc_tsc = false, - .tkip = &tkip_cmd, - .use_tkip = false, - }; - struct iwlagn_d3_config_cmd d3_cfg_cmd = {}; - int ret, i; - u16 seq; - - if (WARN_ON(!wowlan)) - return -EINVAL; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - /* Don't attempt WoWLAN when not associated, tear down instead. */ - if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION || - !iwl_is_associated_ctx(ctx)) { - ret = 1; - goto out; - } - - key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); - if (!key_data.rsc_tsc) { - ret = -ENOMEM; - goto out; - } - - memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd)); - - /* - * We know the last used seqno, and the uCode expects to know that - * one, it will increment before TX. - */ - seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ; - wakeup_filter_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. - */ - for (i = 0; i < 8; i++) { - seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number; - seq -= 0x10; - wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq); - } - - if (wowlan->disconnect) - wakeup_filter_cmd.enabled |= - cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS | - IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE); - if (wowlan->magic_pkt) - wakeup_filter_cmd.enabled |= - cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET); - if (wowlan->gtk_rekey_failure) - wakeup_filter_cmd.enabled |= - cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL); - if (wowlan->eap_identity_req) - wakeup_filter_cmd.enabled |= - cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ); - if (wowlan->four_way_handshake) - wakeup_filter_cmd.enabled |= - cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE); - if (wowlan->n_patterns) - wakeup_filter_cmd.enabled |= - cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH); - - if (wowlan->rfkill_release) - d3_cfg_cmd.wakeup_flags |= - cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL); - - iwl_scan_cancel_timeout(priv, 200); - - memcpy(&rxon, &ctx->active, sizeof(rxon)); - - iwl_trans_stop_device(trans(priv)); - - priv->shrd->wowlan = true; - - ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan, - IWL_UCODE_WOWLAN); - if (ret) - goto error; - - /* now configure WoWLAN ucode */ - ret = iwl_alive_start(priv); - if (ret) - goto error; - - memcpy(&ctx->staging, &rxon, sizeof(rxon)); - ret = iwlagn_commit_rxon(priv, ctx); - if (ret) - goto error; - - ret = iwl_power_update_mode(priv, true); - if (ret) - goto error; - - if (!iwlagn_mod_params.sw_crypto) { - /* mark all keys clear */ - priv->ucode_key_table = 0; - ctx->key_mapping_keys = 0; - - /* - * 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(&priv->shrd->mutex); - ieee80211_iter_keys(priv->hw, ctx->vif, - iwlagn_wowlan_program_keys, - &key_data); - mutex_lock(&priv->shrd->mutex); - if (key_data.error) { - ret = -EIO; - goto error; - } - - if (key_data.use_rsc_tsc) { - struct iwl_host_cmd rsc_tsc_cmd = { - .id = REPLY_WOWLAN_TSC_RSC_PARAMS, - .flags = CMD_SYNC, - .data[0] = key_data.rsc_tsc, - .dataflags[0] = IWL_HCMD_DFL_NOCOPY, - .len[0] = sizeof(*key_data.rsc_tsc), - }; - - ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd); - if (ret) - goto error; - } - - if (key_data.use_tkip) { - ret = iwl_trans_send_cmd_pdu(trans(priv), - REPLY_WOWLAN_TKIP_PARAMS, - CMD_SYNC, sizeof(tkip_cmd), - &tkip_cmd); - if (ret) - goto error; - } - - if (priv->have_rekey_data) { - memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); - memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN); - kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN); - memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN); - kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN); - kek_kck_cmd.replay_ctr = priv->replay_ctr; - - ret = iwl_trans_send_cmd_pdu(trans(priv), - REPLY_WOWLAN_KEK_KCK_MATERIAL, - CMD_SYNC, sizeof(kek_kck_cmd), - &kek_kck_cmd); - if (ret) - goto error; - } - } - - ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC, - sizeof(d3_cfg_cmd), &d3_cfg_cmd); - if (ret) - goto error; - - ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER, - CMD_SYNC, sizeof(wakeup_filter_cmd), - &wakeup_filter_cmd); - if (ret) - goto error; - - ret = iwlagn_send_patterns(priv, wowlan); - if (ret) - goto error; - - device_set_wakeup_enable(bus(priv)->dev, true); - - /* Now let the ucode operate on its own */ - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - - goto out; - - error: - priv->shrd->wowlan = false; - iwlagn_prepare_restart(priv); - ieee80211_restart_hw(priv->hw); - out: - mutex_unlock(&priv->shrd->mutex); - kfree(key_data.rsc_tsc); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return ret; -} - -static int iwlagn_mac_resume(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct ieee80211_vif *vif; - unsigned long flags; - u32 base, status = 0xffffffff; - int ret = -EIO; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - - base = priv->device_pointers.error_event_table; - if (iwlagn_hw_valid_rtc_data_addr(base)) { - spin_lock_irqsave(&bus(priv)->reg_lock, flags); - ret = iwl_grab_nic_access_silent(bus(priv)); - if (ret == 0) { - iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base); - status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(bus(priv)); - } - spin_unlock_irqrestore(&bus(priv)->reg_lock, flags); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (ret == 0) { - if (!priv->wowlan_sram) - priv->wowlan_sram = - kzalloc(priv->ucode_wowlan.data.len, - GFP_KERNEL); - - if (priv->wowlan_sram) - _iwl_read_targ_mem_words( - bus(priv), 0x800000, priv->wowlan_sram, - priv->ucode_wowlan.data.len / 4); - } -#endif - } - - /* we'll clear ctx->vif during iwlagn_prepare_restart() */ - vif = ctx->vif; - - priv->shrd->wowlan = false; - - device_set_wakeup_enable(bus(priv)->dev, false); - - iwlagn_prepare_restart(priv); - - memset((void *)&ctx->active, 0, sizeof(ctx->active)); - iwl_connection_init_rx_config(priv, ctx); - iwlagn_set_rxon_chain(priv, ctx); - - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - ieee80211_resume_disconnect(vif); - - return 1; -} -#endif - -static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MACDUMP(priv, "enter\n"); - - IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - - if (iwlagn_tx_skb(priv, skb)) - dev_kfree_skb_any(skb); - - IWL_DEBUG_MACDUMP(priv, "leave\n"); -} - -static void iwlagn_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_priv *priv = hw->priv; - - iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key); -} - -static int iwlagn_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_priv *priv = hw->priv; - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; - struct iwl_rxon_context *ctx = vif_priv->ctx; - int ret; - bool is_default_wep_key = false; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (iwlagn_mod_params.sw_crypto) { - IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); - return -EOPNOTSUPP; - } - - /* - * We could program these keys into the hardware as well, but we - * don't expect much multicast traffic in IBSS and having keys - * for more stations is probably more useful. - * - * Mark key TX-only and return 0. - */ - if (vif->type == NL80211_IFTYPE_ADHOC && - !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { - key->hw_key_idx = WEP_INVALID_OFFSET; - return 0; - } - - /* If they key was TX-only, accept deletion */ - if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET) - return 0; - - mutex_lock(&priv->shrd->mutex); - iwl_scan_cancel_timeout(priv, 100); - - BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT); - - /* - * If we are getting WEP group key and we didn't receive any key mapping - * so far, we are in legacy wep mode (group key only), otherwise we are - * in 1X mode. - * In legacy wep mode, we use another host command to the uCode. - */ - if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) { - if (cmd == SET_KEY) - is_default_wep_key = !ctx->key_mapping_keys; - else - is_default_wep_key = - key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT; - } - - - switch (cmd) { - case SET_KEY: - if (is_default_wep_key) { - ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key); - break; - } - ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta); - if (ret) { - /* - * can't add key for RX, but we don't need it - * in the device for TX so still return 0 - */ - ret = 0; - key->hw_key_idx = WEP_INVALID_OFFSET; - } - - IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n"); - break; - case DISABLE_KEY: - if (is_default_wep_key) - ret = iwl_remove_default_wep_key(priv, ctx, key); - else - ret = iwl_remove_dynamic_key(priv, ctx, key, sta); - - IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n"); - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return ret; -} - -static int iwlagn_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_priv *priv = hw->priv; - int ret = -EINVAL; - struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", - sta->addr, tid); - - if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)) - return -EACCES; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - switch (action) { - case IEEE80211_AMPDU_RX_START: - IWL_DEBUG_HT(priv, "start Rx\n"); - ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); - break; - case IEEE80211_AMPDU_RX_STOP: - IWL_DEBUG_HT(priv, "stop Rx\n"); - ret = iwl_sta_rx_agg_stop(priv, sta, tid); - if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) - ret = 0; - break; - case IEEE80211_AMPDU_TX_START: - IWL_DEBUG_HT(priv, "start Tx\n"); - ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); - break; - case IEEE80211_AMPDU_TX_STOP: - IWL_DEBUG_HT(priv, "stop Tx\n"); - ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); - if ((ret == 0) && (priv->agg_tids_count > 0)) { - priv->agg_tids_count--; - IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", - priv->agg_tids_count); - } - if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) - ret = 0; - if (!priv->agg_tids_count && priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation) { - /* - * switch off RTS/CTS if it was previously enabled - */ - sta_priv->lq_sta.lq.general_params.flags &= - ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; - iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), - &sta_priv->lq_sta.lq, CMD_ASYNC, false); - } - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); - - iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta), - tid, buf_size); - - /* - * If the limit is 0, then it wasn't initialised yet, - * use the default. We can do that since we take the - * minimum below, and we don't want to go above our - * default due to hardware restrictions. - */ - if (sta_priv->max_agg_bufsize == 0) - sta_priv->max_agg_bufsize = - LINK_QUAL_AGG_FRAME_LIMIT_DEF; - - /* - * 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. - */ - sta_priv->max_agg_bufsize = - min(sta_priv->max_agg_bufsize, buf_size); - - if (priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation) { - /* - * switch to RTS/CTS if it is the prefer protection - * method for HT traffic - */ - - sta_priv->lq_sta.lq.general_params.flags |= - LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; - } - priv->agg_tids_count++; - IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", - priv->agg_tids_count); - - sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = - sta_priv->max_agg_bufsize; - - iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), - &sta_priv->lq_sta.lq, CMD_ASYNC, false); - - IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", - sta->addr, tid); - ret = 0; - break; - } - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - return ret; -} - -static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; - bool is_ap = vif->type == NL80211_IFTYPE_STATION; - int ret = 0; - u8 sta_id; - - IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n", - sta->addr); - mutex_lock(&priv->shrd->mutex); - IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n", - sta->addr); - sta_priv->sta_id = IWL_INVALID_STATION; - - atomic_set(&sta_priv->pending_frames, 0); - if (vif->type == NL80211_IFTYPE_AP) - sta_priv->client = true; - - ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr, - is_ap, sta, &sta_id); - if (ret) { - IWL_ERR(priv, "Unable to add station %pM (%d)\n", - sta->addr, ret); - /* Should we return success if return code is EEXIST ? */ - goto out; - } - - sta_priv->sta_id = sta_id; - - /* Initialize rate scaling */ - IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n", - sta->addr); - iwl_rs_rate_init(priv, sta, sta_id); - out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return ret; -} - -static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_channel *channel = ch_switch->channel; - struct iwl_ht_config *ht_conf = &priv->current_ht_config; - /* - * MULTI-FIXME - * When we add support for multiple interfaces, we need to - * revisit this. The channel switch command in the device - * only affects the BSS context, but what does that really - * mean? And what if we get a CSA on the second interface? - * This needs a lot of work. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - u16 ch; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->shrd->mutex); - - if (iwl_is_rfkill(priv->shrd)) - goto out; - - if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) || - test_bit(STATUS_SCANNING, &priv->shrd->status) || - test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status)) - goto out; - - if (!iwl_is_associated_ctx(ctx)) - goto out; - - if (!priv->cfg->lib->set_channel_switch) - goto out; - - ch = channel->hw_value; - if (le16_to_cpu(ctx->active.channel) == ch) - goto out; - - ch_info = iwl_get_channel_info(priv, channel->band, ch); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211(priv, "invalid channel\n"); - goto out; - } - - spin_lock_irq(&priv->shrd->lock); - - priv->current_ht_config.smps = conf->smps_mode; - - /* Configure HT40 channels */ - ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else - ctx->ht.is_40mhz = false; - - if ((le16_to_cpu(ctx->staging.channel) != ch)) - ctx->staging.flags = 0; - - iwl_set_rxon_channel(priv, channel, ctx); - iwl_set_rxon_ht(priv, ht_conf); - iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); - - spin_unlock_irq(&priv->shrd->lock); - - iwl_set_rate(priv); - /* - * at this point, staging_rxon has the - * configuration for channel switch - */ - set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); - priv->switch_channel = cpu_to_le16(ch); - if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) { - clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); - priv->switch_channel = 0; - ieee80211_chswitch_done(ctx->vif, false); - } - -out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -static void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct iwl_priv *priv = hw->priv; - __le32 filter_or = 0, filter_nand = 0; - struct iwl_rxon_context *ctx; - -#define CHK(test, flag) do { \ - if (*total_flags & (test)) \ - filter_or |= (flag); \ - else \ - filter_nand |= (flag); \ - } while (0) - - IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", - changed_flags, *total_flags); - - CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); - /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */ - CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK); - CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); - -#undef CHK - - mutex_lock(&priv->shrd->mutex); - - for_each_context(priv, ctx) { - ctx->staging.filter_flags &= ~filter_nand; - ctx->staging.filter_flags |= filter_or; - - /* - * Not committing directly because hardware can perform a scan, - * but we'll eventually commit the filter flags change anyway. - */ - } - - mutex_unlock(&priv->shrd->mutex); - - /* - * Receiving all multicast frames is always enabled by the - * default flags setup in iwl_connection_init_rx_config() - * since we currently do not support programming multicast - * filters into the device. - */ - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | - FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; -} - -static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) -{ - struct iwl_priv *priv = hw->priv; - - mutex_lock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { - IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n"); - goto done; - } - if (iwl_is_rfkill(priv->shrd)) { - IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n"); - goto done; - } - - /* - * mac80211 will not push any more frames for transmit - * until the flush is completed - */ - if (drop) { - IWL_DEBUG_MAC80211(priv, "send flush command\n"); - if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { - IWL_ERR(priv, "flush request fail\n"); - goto done; - } - } - IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); - iwl_trans_wait_tx_queue_empty(trans(priv)); -done: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); -} void iwlagn_disable_roc(struct iwl_priv *priv) { @@ -2766,160 +1489,6 @@ static void iwlagn_disable_roc_work(struct work_struct *work) mutex_unlock(&priv->shrd->mutex); } -static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, - struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type, - int duration) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; - int err = 0; - - if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) - return -EOPNOTSUPP; - - if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT))) - return -EOPNOTSUPP; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { - err = -EBUSY; - goto out; - } - - priv->hw_roc_channel = channel; - priv->hw_roc_chantype = channel_type; - priv->hw_roc_duration = duration; - priv->hw_roc_start_notified = false; - cancel_delayed_work(&priv->hw_roc_disable_work); - - if (!ctx->is_active) { - ctx->is_active = true; - ctx->staging.dev_type = RXON_DEV_TYPE_P2P; - memcpy(ctx->staging.node_addr, - priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, - ETH_ALEN); - memcpy(ctx->staging.bssid_addr, - priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, - ETH_ALEN); - err = iwlagn_commit_rxon(priv, ctx); - if (err) - goto out; - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK | - RXON_FILTER_PROMISC_MSK | - RXON_FILTER_CTL2HOST_MSK; - - err = iwlagn_commit_rxon(priv, ctx); - if (err) { - iwlagn_disable_roc(priv); - goto out; - } - priv->hw_roc_setup = true; - } - - err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band); - if (err) - iwlagn_disable_roc(priv); - - out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return err; -} - -static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - - if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) - return -EOPNOTSUPP; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - iwl_scan_cancel_timeout(priv, priv->hw_roc_duration); - iwlagn_disable_roc(priv); - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return 0; -} - -static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const u8 *bssid, - enum ieee80211_tx_sync_type type) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; - struct iwl_rxon_context *ctx = vif_priv->ctx; - int ret; - u8 sta_id; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - if (iwl_is_associated_ctx(ctx)) { - ret = 0; - goto out; - } - - if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { - ret = -EBUSY; - goto out; - } - - ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id); - if (ret) - goto out; - - if (WARN_ON(sta_id != ctx->ap_sta_id)) { - ret = -EIO; - goto out_remove_sta; - } - - memcpy(ctx->bssid, bssid, ETH_ALEN); - ctx->preauth_bssid = true; - - ret = iwlagn_commit_rxon(priv, ctx); - - if (ret == 0) - goto out; - - out_remove_sta: - iwl_remove_station(priv, sta_id, bssid); - out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return ret; -} - -static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const u8 *bssid, - enum ieee80211_tx_sync_type type) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; - struct iwl_rxon_context *ctx = vif_priv->ctx; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - if (iwl_is_associated_ctx(ctx)) - goto out; - - iwl_remove_station(priv, ctx->ap_sta_id, bssid); - ctx->preauth_bssid = false; - /* no need to commit */ - out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - /***************************************************************************** * * driver setup and teardown @@ -3069,81 +1638,13 @@ static void iwl_uninit_drv(struct iwl_priv *priv) kmem_cache_destroy(priv->tx_cmd_pool); kfree(priv->scan_cmd); kfree(priv->beacon_cmd); + kfree(rcu_dereference_raw(priv->noa_data)); #ifdef CONFIG_IWLWIFI_DEBUGFS kfree(priv->wowlan_sram); #endif } -static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, - enum ieee80211_rssi_event rssi_event) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->shrd->mutex); - - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { - if (rssi_event == RSSI_EVENT_LOW) - priv->bt_enable_pspoll = true; - else if (rssi_event == RSSI_EVENT_HIGH) - priv->bt_enable_pspoll = false; - - iwlagn_send_advance_bt_config(priv); - } else { - IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled," - "ignoring RSSI callback\n"); - } - - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, bool set) -{ - struct iwl_priv *priv = hw->priv; - queue_work(priv->shrd->workqueue, &priv->beacon_update); - - return 0; -} - -struct ieee80211_ops iwlagn_hw_ops = { - .tx = iwlagn_mac_tx, - .start = iwlagn_mac_start, - .stop = iwlagn_mac_stop, -#ifdef CONFIG_PM_SLEEP - .suspend = iwlagn_mac_suspend, - .resume = iwlagn_mac_resume, -#endif - .add_interface = iwlagn_mac_add_interface, - .remove_interface = iwlagn_mac_remove_interface, - .change_interface = iwlagn_mac_change_interface, - .config = iwlagn_mac_config, - .configure_filter = iwlagn_configure_filter, - .set_key = iwlagn_mac_set_key, - .update_tkip_key = iwlagn_mac_update_tkip_key, - .set_rekey_data = iwlagn_mac_set_rekey_data, - .conf_tx = iwlagn_mac_conf_tx, - .bss_info_changed = iwlagn_bss_info_changed, - .ampdu_action = iwlagn_mac_ampdu_action, - .hw_scan = iwlagn_mac_hw_scan, - .sta_notify = iwlagn_mac_sta_notify, - .sta_add = iwlagn_mac_sta_add, - .sta_remove = iwlagn_mac_sta_remove, - .channel_switch = iwlagn_mac_channel_switch, - .flush = iwlagn_mac_flush, - .tx_last_beacon = iwlagn_mac_tx_last_beacon, - .remain_on_channel = iwlagn_mac_remain_on_channel, - .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel, - .rssi_callback = iwlagn_mac_rssi_callback, - CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd) - CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump) - .tx_sync = iwlagn_mac_tx_sync, - .finish_tx_sync = iwlagn_mac_finish_tx_sync, - .set_tim = iwlagn_mac_set_tim, -}; static u32 iwl_hw_detect(struct iwl_priv *priv) { @@ -3177,24 +1678,7 @@ static int iwl_set_hw_params(struct iwl_priv *priv) return priv->cfg->lib->set_hw_params(priv); } -/* This function both allocates and initializes hw and priv. */ -static struct ieee80211_hw *iwl_alloc_all(void) -{ - struct iwl_priv *priv; - /* mac80211 allocates memory for this device instance, including - * space for this driver's private structure */ - struct ieee80211_hw *hw; - - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); - if (!hw) - goto out; - priv = hw->priv; - priv->hw = hw; - -out: - return hw; -} int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, struct iwl_cfg *cfg) @@ -3402,7 +1886,7 @@ void __devexit iwl_remove(struct iwl_priv * priv) /*This will stop the queues, move the device to low power state */ iwl_trans_stop_device(trans(priv)); - iwl_dealloc_ucode(priv); + iwl_dealloc_ucode(trans(priv)); iwl_eeprom_free(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5b936ec1a541..5d8d2f445923 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -65,6 +65,12 @@ #include "iwl-dev.h" +struct iwlagn_ucode_capabilities { + u32 max_probe_length; + u32 standard_phy_calibration_size; + u32 flags; +}; + extern struct ieee80211_ops iwlagn_hw_ops; int iwl_reset_ict(struct iwl_trans *trans); @@ -77,6 +83,15 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) hdr->data_valid = 1; } +void __iwl_down(struct iwl_priv *priv); +void iwl_down(struct iwl_priv *priv); +void iwlagn_prepare_restart(struct iwl_priv *priv); + +/* MAC80211 */ +struct ieee80211_hw *iwl_alloc_all(void); +int iwlagn_mac_setup_register(struct iwl_priv *priv, + struct iwlagn_ucode_capabilities *capa); + /* RXON */ int iwlagn_set_pan_params(struct iwl_priv *priv); int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -95,8 +110,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); int iwlagn_run_init_ucode(struct iwl_priv *priv); int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, - struct fw_img *image, - enum iwlagn_ucode_type ucode_type); + enum iwl_ucode_type ucode_type); /* lib */ int iwlagn_send_tx_power(struct iwl_priv *priv); @@ -105,6 +119,12 @@ u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); +#ifdef CONFIG_PM_SLEEP +int iwlagn_send_patterns(struct iwl_priv *priv, + struct cfg80211_wowlan *wowlan); +int iwlagn_suspend(struct iwl_priv *priv, + struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); +#endif /* rx */ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); @@ -196,9 +216,6 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct ieee80211_sta *sta, u8 *sta_id_r); int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, const u8 *addr); -int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); - u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, const u8 *addr, bool is_ap, struct ieee80211_sta *sta); @@ -316,10 +333,6 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); int iwl_update_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwl_update_bcast_stations(struct iwl_priv *priv); -void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta); /* rate */ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h index 2a2dc4597ba1..e1d78257e4a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-cfg.h +++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h @@ -101,17 +101,11 @@ extern struct iwl_cfg iwl100_bg_cfg; extern struct iwl_cfg iwl130_bgn_cfg; extern struct iwl_cfg iwl130_bg_cfg; extern struct iwl_cfg iwl2000_2bgn_cfg; -extern struct iwl_cfg iwl2000_2bg_cfg; extern struct iwl_cfg iwl2000_2bgn_d_cfg; extern struct iwl_cfg iwl2030_2bgn_cfg; -extern struct iwl_cfg iwl2030_2bg_cfg; extern struct iwl_cfg iwl6035_2agn_cfg; -extern struct iwl_cfg iwl6035_2abg_cfg; -extern struct iwl_cfg iwl6035_2bg_cfg; -extern struct iwl_cfg iwl105_bg_cfg; extern struct iwl_cfg iwl105_bgn_cfg; extern struct iwl_cfg iwl105_bgn_d_cfg; -extern struct iwl_cfg iwl135_bg_cfg; extern struct iwl_cfg iwl135_bgn_cfg; #endif /* __iwl_pci_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 001fdf140abb..f9e9170e977a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1120,229 +1120,8 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) &statistics_cmd); } -int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx; - unsigned long flags; - int q; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv->shrd)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (queue >= AC_NUM) { - IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); - return 0; - } - - q = AC_NUM - 1 - queue; - - spin_lock_irqsave(&priv->shrd->lock, flags); - - /* - * MULTI-FIXME - * This may need to be done per interface in nl80211/cfg80211/mac80211. - */ - for_each_context(priv, ctx) { - ctx->qos_data.def_qos_parm.ac[q].cw_min = - cpu_to_le16(params->cw_min); - ctx->qos_data.def_qos_parm.ac[q].cw_max = - cpu_to_le16(params->cw_max); - ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; - ctx->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->txop * 32)); - - ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0; - } - - spin_unlock_irqrestore(&priv->shrd->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - -int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - - return priv->ibss_manager == IWL_IBSS_MANAGER; -} - -static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - iwl_connection_init_rx_config(priv, ctx); - - iwlagn_set_rxon_chain(priv, ctx); - - return iwlagn_commit_rxon(priv, ctx); -} - -static int iwl_setup_interface(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - struct ieee80211_vif *vif = ctx->vif; - int err; - - lockdep_assert_held(&priv->shrd->mutex); - - /* - * This variable will be correct only when there's just - * a single context, but all code using it is for hardware - * that supports only one context. - */ - priv->iw_mode = vif->type; - - ctx->is_active = true; - - err = iwl_set_mode(priv, ctx); - if (err) { - if (!ctx->always_active) - ctx->is_active = false; - return err; - } - - if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && - vif->type == NL80211_IFTYPE_ADHOC) { - /* - * pretend to have high BT traffic as long as we - * are operating in IBSS mode, as this will cause - * the rate scaling etc. to behave as intended. - */ - priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; - } - - return 0; -} - -int iwlagn_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; - struct iwl_rxon_context *tmp, *ctx = NULL; - int err; - enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif); - - IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", - viftype, vif->addr); - - cancel_delayed_work_sync(&priv->hw_roc_disable_work); - - mutex_lock(&priv->shrd->mutex); - - iwlagn_disable_roc(priv); - - if (!iwl_is_ready_rf(priv->shrd)) { - IWL_WARN(priv, "Try to add interface when device not ready\n"); - err = -EINVAL; - goto out; - } - - for_each_context(priv, tmp) { - u32 possible_modes = - tmp->interface_modes | tmp->exclusive_interface_modes; - - if (tmp->vif) { - /* check if this busy context is exclusive */ - if (tmp->exclusive_interface_modes & - BIT(tmp->vif->type)) { - err = -EINVAL; - goto out; - } - continue; - } - - if (!(possible_modes & BIT(viftype))) - continue; - /* have maybe usable context w/o interface */ - ctx = tmp; - break; - } - - if (!ctx) { - err = -EOPNOTSUPP; - goto out; - } - - vif_priv->ctx = ctx; - ctx->vif = vif; - - err = iwl_setup_interface(priv, ctx); - if (!err) - goto out; - ctx->vif = NULL; - priv->iw_mode = NL80211_IFTYPE_STATION; - out: - mutex_unlock(&priv->shrd->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return err; -} - -static void iwl_teardown_interface(struct iwl_priv *priv, - struct ieee80211_vif *vif, - bool mode_change) -{ - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - lockdep_assert_held(&priv->shrd->mutex); - - if (priv->scan_vif == vif) { - iwl_scan_cancel_timeout(priv, 200); - iwl_force_scan_end(priv); - } - - if (!mode_change) { - iwl_set_mode(priv, ctx); - if (!ctx->always_active) - ctx->is_active = false; - } - - /* - * When removing the IBSS interface, overwrite the - * BT traffic load with the stored one from the last - * notification, if any. If this is a device that - * doesn't implement this, this has no effect since - * both values are the same and zero. - */ - if (vif->type == NL80211_IFTYPE_ADHOC) - priv->bt_traffic_load = priv->last_bt_traffic_load; -} - -void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->shrd->mutex); - - if (WARN_ON(ctx->vif != vif)) { - struct iwl_rxon_context *tmp; - IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif); - for_each_context(priv, tmp) - IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n", - tmp->ctxid, tmp, tmp->vif); - } - ctx->vif = NULL; - - iwl_teardown_interface(priv, vif, false); - - mutex_unlock(&priv->shrd->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -} #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1649,97 +1428,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) return 0; } -int iwlagn_mac_change_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum nl80211_iftype newtype, bool newp2p) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl_rxon_context *tmp; - enum nl80211_iftype newviftype = newtype; - u32 interface_modes; - int err; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - newtype = ieee80211_iftype_p2p(newtype, newp2p); - - mutex_lock(&priv->shrd->mutex); - - if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) { - /* - * Huh? But wait ... this can maybe happen when - * we're in the middle of a firmware restart! - */ - err = -EBUSY; - goto out; - } - - interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; - - if (!(interface_modes & BIT(newtype))) { - err = -EBUSY; - goto out; - } - - /* - * Refuse a change that should be done by moving from the PAN - * context to the BSS context instead, if the BSS context is - * available and can support the new interface type. - */ - if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && - (bss_ctx->interface_modes & BIT(newtype) || - bss_ctx->exclusive_interface_modes & BIT(newtype))) { - BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); - err = -EBUSY; - goto out; - } - - if (ctx->exclusive_interface_modes & BIT(newtype)) { - for_each_context(priv, tmp) { - if (ctx == tmp) - continue; - - if (!tmp->vif) - continue; - - /* - * The current mode switch would be exclusive, but - * another context is active ... refuse the switch. - */ - err = -EBUSY; - goto out; - } - } - - /* success */ - iwl_teardown_interface(priv, vif, true); - vif->type = newviftype; - vif->p2p = newp2p; - err = iwl_setup_interface(priv, ctx); - WARN_ON(err); - /* - * We've switched internally, but submitting to the - * device may have failed for some reason. Mask this - * error, because otherwise mac80211 will not switch - * (and set the interface type back) and we'll be - * out of sync with it. - */ - err = 0; - - out: - mutex_unlock(&priv->shrd->mutex); - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return err; -} int iwl_cmd_echo_test(struct iwl_priv *priv) { int ret; struct iwl_host_cmd cmd = { .id = REPLY_ECHO, + .len = { 0 }, .flags = CMD_SYNC, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 137da3380704..fa47f75185df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -237,10 +237,6 @@ struct iwl_cfg { * L i b * ***************************/ -int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, - const struct ieee80211_tx_queue_params *params); -int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -260,13 +256,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, void iwl_connection_init_rx_config(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwl_set_rate(struct iwl_priv *priv); -int iwlagn_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -int iwlagn_mac_change_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum nl80211_iftype newtype, bool newp2p); int iwl_cmd_echo_test(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); @@ -323,9 +312,6 @@ void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); void iwl_force_scan_end(struct iwl_priv *priv); -int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req); void iwl_internal_short_hw_scan(struct iwl_priv *priv); int iwl_force_reset(struct iwl_priv *priv, int mode, bool external); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 69a77e24d229..40ef97bac1aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -70,10 +70,25 @@ do { \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) +#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...) \ +do { \ + if (!iwl_is_rfkill(p->shrd)) \ + dev_printk(KERN_ERR, bus(p)->dev, "%c %s " fmt, \ + (in_interrupt() ? 'I' : 'U'), __func__ , ##args); \ + else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO) \ + dev_printk(KERN_ERR, bus(p)->dev, "(RFKILL) %c %s " fmt, \ + (in_interrupt() ? 'I' : 'U'), __func__ , ##args); \ +} while (0) + #else #define IWL_DEBUG(m, level, fmt, args...) #define IWL_DEBUG_LIMIT(m, level, fmt, args...) #define iwl_print_hex_dump(m, level, p, len) +#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...) \ +do { \ + if (!iwl_is_rfkill(p->shrd)) \ + IWL_ERR(p, fmt, ##args); \ +} while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -151,7 +166,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DL_11H (1 << 28) #define IWL_DL_STATS (1 << 29) #define IWL_DL_TX_REPLY (1 << 30) -#define IWL_DL_QOS (1 << 31) +#define IWL_DL_TX_QUEUES (1 << 31) #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) @@ -188,7 +203,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a) #define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a) -#define IWL_DEBUG_QOS(p, f, a...) IWL_DEBUG(p, IWL_DL_QOS, f, ## a) +#define IWL_DEBUG_TX_QUEUES(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a) #define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a) #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a1670e3f8bfa..68b04f5b10ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -236,9 +236,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; if (priv->ucode_type == IWL_UCODE_INIT) - priv->dbgfs_sram_len = priv->ucode_init.data.len; + priv->dbgfs_sram_len = trans(priv)->ucode_init.data.len; else - priv->dbgfs_sram_len = priv->ucode_rt.data.len; + priv->dbgfs_sram_len = trans(priv)->ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -341,7 +341,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, priv->wowlan_sram, - priv->ucode_wowlan.data.len); + trans(priv)->ucode_wowlan.data.len); } static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -430,7 +430,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, " "version: 0x%x\n", - (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", eeprom_ver); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6c00a447963d..556e4a2c19bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -230,17 +230,6 @@ struct iwl_vif_priv { u8 ibss_bssid_sta_id; }; -/* one for each uCode image (inst/data, boot/init/runtime) */ -struct fw_desc { - void *v_addr; /* access by driver */ - dma_addr_t p_addr; /* access by card's busmaster DMA */ - u32 len; /* bytes */ -}; - -struct fw_img { - struct fw_desc code, data; -}; - /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -805,13 +794,6 @@ enum iwl_scan_type { IWL_SCAN_ROC, }; -enum iwlagn_ucode_type { - IWL_UCODE_NONE, - IWL_UCODE_REGULAR, - IWL_UCODE_INIT, - IWL_UCODE_WOWLAN, -}; - #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL struct iwl_testmode_trace { u32 buff_size; @@ -824,6 +806,12 @@ struct iwl_testmode_trace { }; #endif +struct iwl_wipan_noa_data { + struct rcu_head rcu_head; + u32 length; + u8 data[]; +}; + struct iwl_priv { /*data shared among all the driver's layers */ @@ -883,6 +871,8 @@ struct iwl_priv { /* init calibration results */ struct iwl_calib_result calib_results[IWL_CALIB_MAX]; + struct iwl_wipan_noa_data __rcu *noa_data; + /* Scan related variables */ unsigned long scan_start; unsigned long scan_start_tsf; @@ -907,12 +897,7 @@ struct iwl_priv { u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - struct fw_img ucode_rt; - struct fw_img ucode_init; - struct fw_img ucode_wowlan; - - enum iwlagn_ucode_type ucode_type; - u8 ucode_write_complete; /* the image write is complete */ + enum iwl_ucode_type ucode_type; char firmware_name[25]; struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; @@ -959,7 +944,6 @@ struct iwl_priv { /* eeprom -- this is in the card's little endian byte order */ u8 *eeprom; - int nvm_device_type; struct iwl_eeprom_calib_info *calib_info; enum nl80211_iftype iw_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index a4e43bd4a547..dcada0827ea4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -149,23 +149,23 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * EEPROM chip, not a single event, so even reads could conflict if they * weren't arbitrated by the semaphore. */ -static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) +static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus) { u16 count; int ret; for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { /* Request semaphore */ - iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(bus, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(bus(priv), CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(bus, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (ret >= 0) { - IWL_DEBUG_EEPROM(priv, + IWL_DEBUG_EEPROM(bus, "Acquired semaphore after %d tries.\n", count+1); return ret; @@ -175,39 +175,39 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) return ret; } -static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +static void iwl_eeprom_release_semaphore(struct iwl_bus *bus) { - iwl_clear_bit(bus(priv), CSR_HW_IF_CONFIG_REG, + iwl_clear_bit(bus, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); } -static int iwl_eeprom_verify_signature(struct iwl_priv *priv) +static int iwl_eeprom_verify_signature(struct iwl_trans *trans) { - u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; + u32 gp = iwl_read32(bus(trans), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; int ret = 0; - IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp); + IWL_DEBUG_EEPROM(trans, "EEPROM signature=0x%08x\n", gp); switch (gp) { case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP: - if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) { - IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n", + if (trans->nvm_device_type != NVM_DEVICE_TYPE_OTP) { + IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n", gp); ret = -ENOENT; } break; case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: - if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { - IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp); + if (trans->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { + IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp); ret = -ENOENT; } break; case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP: default: - IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, " + IWL_ERR(trans, "bad EEPROM/OTP signature, type=%s, " "EEPROM_GP=0x%08x\n", - (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", gp); ret = -ENOENT; break; @@ -302,19 +302,19 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) * ******************************************************************************/ -static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) +static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode) { - iwl_read32(bus(priv), CSR_OTP_GP_REG); + iwl_read32(bus, CSR_OTP_GP_REG); if (mode == IWL_OTP_ACCESS_ABSOLUTE) - iwl_clear_bit(bus(priv), CSR_OTP_GP_REG, + iwl_clear_bit(bus, CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); else - iwl_set_bit(bus(priv), CSR_OTP_GP_REG, + iwl_set_bit(bus, CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) +static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev) { u32 otpgp; int nvm_type; @@ -322,7 +322,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) /* OTP only valid for CP/PP and after */ switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: - IWL_ERR(priv, "Unknown hardware type\n"); + IWL_ERR(bus, "Unknown hardware type\n"); return -ENOENT; case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: @@ -331,7 +331,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) nvm_type = NVM_DEVICE_TYPE_EEPROM; break; default: - otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG); + otpgp = iwl_read32(bus, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) nvm_type = NVM_DEVICE_TYPE_OTP; else @@ -341,73 +341,73 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) return nvm_type; } -static int iwl_init_otp_access(struct iwl_priv *priv) +static int iwl_init_otp_access(struct iwl_bus *bus) { int ret; /* Enable 40MHz radio clock */ - iwl_write32(bus(priv), CSR_GP_CNTRL, - iwl_read32(bus(priv), CSR_GP_CNTRL) | + iwl_write32(bus, CSR_GP_CNTRL, + iwl_read32(bus, CSR_GP_CNTRL) | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ - ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL, + ret = iwl_poll_bit(bus, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) - IWL_ERR(priv, "Time out access OTP\n"); + IWL_ERR(bus, "Time out access OTP\n"); else { - iwl_set_bits_prph(bus(priv), APMG_PS_CTRL_REG, + iwl_set_bits_prph(bus, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_prph(bus(priv), APMG_PS_CTRL_REG, + iwl_clear_bits_prph(bus, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); /* * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ - if (priv->cfg->base_params->shadow_ram_support) - iwl_set_bit(bus(priv), CSR_DBG_LINK_PWR_MGMT_REG, + if (priv(bus)->cfg->base_params->shadow_ram_support) + iwl_set_bit(bus, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } return ret; } -static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data) +static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data) { int ret = 0; u32 r; u32 otpgp; - iwl_write32(bus(priv), CSR_EEPROM_REG, + iwl_write32(bus, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG, + ret = iwl_poll_bit(bus, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { - IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + IWL_ERR(bus, "Time out reading OTP[%d]\n", addr); return ret; } - r = iwl_read32(bus(priv), CSR_EEPROM_REG); + r = iwl_read32(bus, CSR_EEPROM_REG); /* check for ECC errors: */ - otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG); + otpgp = iwl_read32(bus, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ /* set the uncorrectable OTP ECC bit for acknowledgement */ - iwl_set_bit(bus(priv), CSR_OTP_GP_REG, + iwl_set_bit(bus, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); + IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n"); return -EINVAL; } if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ /* set the correctable OTP ECC bit for acknowledgement */ - iwl_set_bit(bus(priv), CSR_OTP_GP_REG, + iwl_set_bit(bus, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + IWL_ERR(bus, "Correctable OTP ECC error, continue read\n"); } *eeprom_data = cpu_to_le16(r >> 16); return 0; @@ -416,20 +416,20 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat /* * iwl_is_otp_empty: check for empty OTP */ -static bool iwl_is_otp_empty(struct iwl_priv *priv) +static bool iwl_is_otp_empty(struct iwl_bus *bus) { u16 next_link_addr = 0; __le16 link_value; bool is_empty = false; /* locate the beginning of OTP link list */ - if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { + if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) { if (!link_value) { - IWL_ERR(priv, "OTP is empty\n"); + IWL_ERR(bus, "OTP is empty\n"); is_empty = true; } } else { - IWL_ERR(priv, "Unable to read first block of OTP list.\n"); + IWL_ERR(bus, "Unable to read first block of OTP list.\n"); is_empty = true; } @@ -446,7 +446,7 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv) * we should read and used to configure the device. * only perform this operation if shadow RAM is disabled */ -static int iwl_find_otp_image(struct iwl_priv *priv, +static int iwl_find_otp_image(struct iwl_bus *bus, u16 *validblockaddr) { u16 next_link_addr = 0, valid_addr; @@ -454,10 +454,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv, int usedblocks = 0; /* set addressing mode to absolute to traverse the link list */ - iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); + iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE); /* checking for empty OTP or error */ - if (iwl_is_otp_empty(priv)) + if (iwl_is_otp_empty(bus)) return -EINVAL; /* @@ -471,9 +471,9 @@ static int iwl_find_otp_image(struct iwl_priv *priv, */ valid_addr = next_link_addr; next_link_addr = le16_to_cpu(link_value) * sizeof(u16); - IWL_DEBUG_EEPROM(priv, "OTP blocks %d addr 0x%x\n", + IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n", usedblocks, next_link_addr); - if (iwl_read_otp_word(priv, next_link_addr, &link_value)) + if (iwl_read_otp_word(bus, next_link_addr, &link_value)) return -EINVAL; if (!link_value) { /* @@ -488,10 +488,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv, } /* more in the link list, continue */ usedblocks++; - } while (usedblocks <= priv->cfg->base_params->max_ll_items); + } while (usedblocks <= priv(bus)->cfg->base_params->max_ll_items); /* OTP has no valid blocks */ - IWL_DEBUG_EEPROM(priv, "OTP has no valid blocks\n"); + IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n"); return -EINVAL; } @@ -504,28 +504,28 @@ static int iwl_find_otp_image(struct iwl_priv *priv, * iwl_get_max_txpower_avg - get the highest tx power from all chains. * find the highest tx power from all chains for the channel */ -static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, +static s8 iwl_get_max_txpower_avg(struct iwl_cfg *cfg, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element, s8 *max_txpower_in_half_dbm) { s8 max_txpower_avg = 0; /* (dBm) */ /* Take the highest tx power from any valid chains */ - if ((priv->cfg->valid_tx_ant & ANT_A) && + if ((cfg->valid_tx_ant & ANT_A) && (enhanced_txpower[element].chain_a_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].chain_a_max; - if ((priv->cfg->valid_tx_ant & ANT_B) && + if ((cfg->valid_tx_ant & ANT_B) && (enhanced_txpower[element].chain_b_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].chain_b_max; - if ((priv->cfg->valid_tx_ant & ANT_C) && + if ((cfg->valid_tx_ant & ANT_C) && (enhanced_txpower[element].chain_c_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].chain_c_max; - if (((priv->cfg->valid_tx_ant == ANT_AB) | - (priv->cfg->valid_tx_ant == ANT_BC) | - (priv->cfg->valid_tx_ant == ANT_AC)) && + if (((cfg->valid_tx_ant == ANT_AB) | + (cfg->valid_tx_ant == ANT_BC) | + (cfg->valid_tx_ant == ANT_AC)) && (enhanced_txpower[element].mimo2_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].mimo2_max; - if ((priv->cfg->valid_tx_ant == ANT_ABC) && + if ((cfg->valid_tx_ant == ANT_ABC) && (enhanced_txpower[element].mimo3_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].mimo3_max; @@ -627,7 +627,7 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) ((txp->delta_20_in_40 & 0xf0) >> 4), (txp->delta_20_in_40 & 0x0f)); - max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx, + max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx, &max_txp_avg_halfdbm); /* @@ -660,8 +660,8 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) u16 validblockaddr = 0; u16 cache_addr = 0; - priv->nvm_device_type = iwl_get_nvm_type(priv, hw_rev); - if (priv->nvm_device_type == -ENOENT) + trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev); + if (trans(priv)->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ sz = priv->cfg->base_params->eeprom_size; @@ -675,7 +675,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) iwl_apm_init(priv); - ret = iwl_eeprom_verify_signature(priv); + ret = iwl_eeprom_verify_signature(trans(priv)); if (ret < 0) { IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); ret = -ENOENT; @@ -683,16 +683,16 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = iwl_eeprom_acquire_semaphore(priv); + ret = iwl_eeprom_acquire_semaphore(bus(priv)); if (ret < 0) { IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; goto err; } - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - ret = iwl_init_otp_access(priv); + ret = iwl_init_otp_access(bus(priv)); if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); ret = -ENOENT; @@ -707,7 +707,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ if (!priv->cfg->base_params->shadow_ram_support) { - if (iwl_find_otp_image(priv, &validblockaddr)) { + if (iwl_find_otp_image(bus(priv), &validblockaddr)) { ret = -ENOENT; goto done; } @@ -716,7 +716,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) addr += sizeof(u16)) { __le16 eeprom_data; - ret = iwl_read_otp_word(priv, addr, &eeprom_data); + ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data); if (ret) goto done; e[cache_addr / 2] = eeprom_data; @@ -744,13 +744,13 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) } IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n", - (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", iwl_eeprom_query16(priv, EEPROM_VERSION)); ret = 0; done: - iwl_eeprom_release_semaphore(priv); + iwl_eeprom_release_semaphore(bus(priv)); err: if (ret) diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c new file mode 100644 index 000000000000..05b1f0d2f387 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -0,0 +1,1632 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/firmware.h> +#include <linux/etherdevice.h> +#include <linux/if_arp.h> + +#include <net/mac80211.h> + +#include <asm/div64.h> + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-agn-calib.h" +#include "iwl-agn.h" +#include "iwl-shared.h" +#include "iwl-bus.h" +#include "iwl-trans.h" + +/***************************************************************************** + * + * mac80211 entry point functions + * + *****************************************************************************/ + +static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, +}; + +static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +static const struct ieee80211_iface_combination +iwlagn_iface_combinations_dualmode[] = { + { .num_different_channels = 1, + .max_interfaces = 2, + .beacon_int_infra_match = true, + .limits = iwlagn_sta_ap_limits, + .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits), + }, + { .num_different_channels = 1, + .max_interfaces = 2, + .limits = iwlagn_2sta_limits, + .n_limits = ARRAY_SIZE(iwlagn_2sta_limits), + }, +}; + +static const struct ieee80211_iface_combination +iwlagn_iface_combinations_p2p[] = { + { .num_different_channels = 1, + .max_interfaces = 2, + .beacon_int_infra_match = true, + .limits = iwlagn_p2p_sta_go_limits, + .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits), + }, + { .num_different_channels = 1, + .max_interfaces = 2, + .limits = iwlagn_p2p_2sta_limits, + .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits), + }, +}; + +/* + * Not a mac80211 entry point function, but it fits in with all the + * other mac80211 functions grouped here. + */ +int iwlagn_mac_setup_register(struct iwl_priv *priv, + struct iwlagn_ucode_capabilities *capa) +{ + int ret; + struct ieee80211_hw *hw = priv->hw; + struct iwl_rxon_context *ctx; + + hw->rate_control_algorithm = "iwl-agn-rs"; + + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_NEED_DTIM_PERIOD | + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_REPORTS_TX_ACK_STATUS; + + /* + * Including the following line will crash some AP's. This + * workaround removes the stimulus which causes the crash until + * the AP software can be fixed. + hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + */ + + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + + if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) + hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | + IEEE80211_HW_SUPPORTS_STATIC_SMPS; + + if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + + hw->sta_data_size = sizeof(struct iwl_station_priv); + hw->vif_data_size = sizeof(struct iwl_vif_priv); + + for_each_context(priv, ctx) { + hw->wiphy->interface_modes |= ctx->interface_modes; + hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; + } + + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + + if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) { + hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(iwlagn_iface_combinations_p2p); + } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { + hw->wiphy->iface_combinations = + iwlagn_iface_combinations_dualmode; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(iwlagn_iface_combinations_dualmode); + } + + hw->wiphy->max_remain_on_channel_duration = 1000; + + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS | + WIPHY_FLAG_IBSS_RSN; + + if (trans(priv)->ucode_wowlan.code.len && + device_can_wakeup(bus(priv)->dev)) { + hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_RFKILL_RELEASE; + if (!iwlagn_mod_params.sw_crypto) + hw->wiphy->wowlan.flags |= + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE; + + hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS; + hw->wiphy->wowlan.pattern_min_len = + IWLAGN_WOWLAN_MIN_PATTERN_LEN; + hw->wiphy->wowlan.pattern_max_len = + IWLAGN_WOWLAN_MAX_PATTERN_LEN; + } + + if (iwlagn_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->max_scan_ssids = PROBE_OPTION_MAX; + /* we create the 802.11 header and a zero-length SSID element */ + hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2; + + /* Default value; 4 EDCA QOS priorities */ + hw->queues = 4; + + hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + iwl_leds_init(priv); + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); + return ret; + } + priv->mac80211_registered = 1; + + return 0; +} + +static int __iwl_up(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + int ret; + + lockdep_assert_held(&priv->shrd->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { + IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); + return -EIO; + } + + for_each_context(priv, ctx) { + ret = iwlagn_alloc_bcast_station(priv, ctx); + if (ret) { + iwl_dealloc_bcast_stations(priv); + return ret; + } + } + + ret = iwlagn_run_init_ucode(priv); + if (ret) { + IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); + goto error; + } + + ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); + if (ret) { + IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); + goto error; + } + + ret = iwl_alive_start(priv); + if (ret) + goto error; + return 0; + + error: + set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); + __iwl_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); + + IWL_ERR(priv, "Unable to initialize device.\n"); + return ret; +} + +static int iwlagn_mac_start(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->shrd->mutex); + ret = __iwl_up(priv); + mutex_unlock(&priv->shrd->mutex); + if (ret) + return ret; + + IWL_DEBUG_INFO(priv, "Start UP work done.\n"); + + /* Now we should be done, and the READY bit should be set. */ + if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status))) + ret = -EIO; + + iwlagn_led_enable(priv); + + priv->is_open = 1; + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; +} + +static void iwlagn_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!priv->is_open) + return; + + priv->is_open = 0; + + iwl_down(priv); + + flush_workqueue(priv->shrd->workqueue); + + /* User space software may expect getting rfkill changes + * even if interface is down */ + iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF); + iwl_enable_rfkill_int(priv); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + struct iwl_priv *priv = hw->priv; + + if (iwlagn_mod_params.sw_crypto) + return; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif) + goto out; + + memcpy(priv->kek, data->kek, NL80211_KEK_LEN); + memcpy(priv->kck, data->kck, NL80211_KCK_LEN); + priv->replay_ctr = + cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr)); + priv->have_rekey_data = true; + + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +#ifdef CONFIG_PM_SLEEP + +static int iwlagn_mac_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + int ret; + + if (WARN_ON(!wowlan)) + return -EINVAL; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + /* Don't attempt WoWLAN when not associated, tear down instead. */ + if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION || + !iwl_is_associated_ctx(ctx)) { + ret = 1; + goto out; + } + + ret = iwlagn_suspend(priv, hw, wowlan); + if (ret) + goto error; + + device_set_wakeup_enable(bus(priv)->dev, true); + + /* Now let the ucode operate on its own */ + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); + + goto out; + + error: + priv->shrd->wowlan = false; + iwlagn_prepare_restart(priv); + ieee80211_restart_hw(priv->hw); + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +static int iwlagn_mac_resume(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct ieee80211_vif *vif; + unsigned long flags; + u32 base, status = 0xffffffff; + int ret = -EIO; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); + + base = priv->device_pointers.error_event_table; + if (iwlagn_hw_valid_rtc_data_addr(base)) { + spin_lock_irqsave(&bus(priv)->reg_lock, flags); + ret = iwl_grab_nic_access_silent(bus(priv)); + if (ret == 0) { + iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base); + status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); + iwl_release_nic_access(bus(priv)); + } + spin_unlock_irqrestore(&bus(priv)->reg_lock, flags); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (ret == 0) { + struct iwl_trans *trans = trans(priv); + if (!priv->wowlan_sram) + priv->wowlan_sram = + kzalloc(trans->ucode_wowlan.data.len, + GFP_KERNEL); + + if (priv->wowlan_sram) + _iwl_read_targ_mem_words( + bus(priv), 0x800000, priv->wowlan_sram, + trans->ucode_wowlan.data.len / 4); + } +#endif + } + + /* we'll clear ctx->vif during iwlagn_prepare_restart() */ + vif = ctx->vif; + + priv->shrd->wowlan = false; + + device_set_wakeup_enable(bus(priv)->dev, false); + + iwlagn_prepare_restart(priv); + + memset((void *)&ctx->active, 0, sizeof(ctx->active)); + iwl_connection_init_rx_config(priv, ctx); + iwlagn_set_rxon_chain(priv, ctx); + + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + ieee80211_resume_disconnect(vif); + + return 1; +} + +#endif + +static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MACDUMP(priv, "enter\n"); + + IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); + + if (iwlagn_tx_skb(priv, skb)) + dev_kfree_skb_any(skb); + + IWL_DEBUG_MACDUMP(priv, "leave\n"); +} + +static void iwlagn_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_priv *priv = hw->priv; + + iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key); +} + +static int iwlagn_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_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *ctx = vif_priv->ctx; + int ret; + bool is_default_wep_key = false; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (iwlagn_mod_params.sw_crypto) { + IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } + + /* + * We could program these keys into the hardware as well, but we + * don't expect much multicast traffic in IBSS and having keys + * for more stations is probably more useful. + * + * Mark key TX-only and return 0. + */ + if (vif->type == NL80211_IFTYPE_ADHOC && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + key->hw_key_idx = WEP_INVALID_OFFSET; + return 0; + } + + /* If they key was TX-only, accept deletion */ + if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET) + return 0; + + mutex_lock(&priv->shrd->mutex); + iwl_scan_cancel_timeout(priv, 100); + + BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT); + + /* + * If we are getting WEP group key and we didn't receive any key mapping + * so far, we are in legacy wep mode (group key only), otherwise we are + * in 1X mode. + * In legacy wep mode, we use another host command to the uCode. + */ + if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) { + if (cmd == SET_KEY) + is_default_wep_key = !ctx->key_mapping_keys; + else + is_default_wep_key = + key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT; + } + + + switch (cmd) { + case SET_KEY: + if (is_default_wep_key) { + ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key); + break; + } + ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta); + if (ret) { + /* + * can't add key for RX, but we don't need it + * in the device for TX so still return 0 + */ + ret = 0; + key->hw_key_idx = WEP_INVALID_OFFSET; + } + + IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n"); + break; + case DISABLE_KEY: + if (is_default_wep_key) + ret = iwl_remove_default_wep_key(priv, ctx, key); + else + ret = iwl_remove_dynamic_key(priv, ctx, key, sta); + + IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n"); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +static int iwlagn_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_priv *priv = hw->priv; + int ret = -EINVAL; + struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + + IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", + sta->addr, tid); + + if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)) + return -EACCES; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + switch (action) { + case IEEE80211_AMPDU_RX_START: + IWL_DEBUG_HT(priv, "start Rx\n"); + ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); + break; + case IEEE80211_AMPDU_RX_STOP: + IWL_DEBUG_HT(priv, "stop Rx\n"); + ret = iwl_sta_rx_agg_stop(priv, sta, tid); + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) + ret = 0; + break; + case IEEE80211_AMPDU_TX_START: + IWL_DEBUG_HT(priv, "start Tx\n"); + ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); + break; + case IEEE80211_AMPDU_TX_STOP: + IWL_DEBUG_HT(priv, "stop Tx\n"); + ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); + if ((ret == 0) && (priv->agg_tids_count > 0)) { + priv->agg_tids_count--; + IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", + priv->agg_tids_count); + } + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) + ret = 0; + if (!priv->agg_tids_count && priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation) { + /* + * switch off RTS/CTS if it was previously enabled + */ + sta_priv->lq_sta.lq.general_params.flags &= + ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; + iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), + &sta_priv->lq_sta.lq, CMD_ASYNC, false); + } + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + + iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta), + tid, buf_size); + + /* + * If the limit is 0, then it wasn't initialised yet, + * use the default. We can do that since we take the + * minimum below, and we don't want to go above our + * default due to hardware restrictions. + */ + if (sta_priv->max_agg_bufsize == 0) + sta_priv->max_agg_bufsize = + LINK_QUAL_AGG_FRAME_LIMIT_DEF; + + /* + * 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. + */ + sta_priv->max_agg_bufsize = + min(sta_priv->max_agg_bufsize, buf_size); + + if (priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation) { + /* + * switch to RTS/CTS if it is the prefer protection + * method for HT traffic + */ + + sta_priv->lq_sta.lq.general_params.flags |= + LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; + } + priv->agg_tids_count++; + IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", + priv->agg_tids_count); + + sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize; + + iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), + &sta_priv->lq_sta.lq, CMD_ASYNC, false); + + IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", + sta->addr, tid); + ret = 0; + break; + } + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + return ret; +} + +static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + bool is_ap = vif->type == NL80211_IFTYPE_STATION; + int ret = 0; + u8 sta_id; + + IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n", + sta->addr); + mutex_lock(&priv->shrd->mutex); + IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n", + sta->addr); + sta_priv->sta_id = IWL_INVALID_STATION; + + atomic_set(&sta_priv->pending_frames, 0); + if (vif->type == NL80211_IFTYPE_AP) + sta_priv->client = true; + + ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr, + is_ap, sta, &sta_id); + if (ret) { + IWL_ERR(priv, "Unable to add station %pM (%d)\n", + sta->addr, ret); + /* Should we return success if return code is EEXIST ? */ + goto out; + } + + sta_priv->sta_id = sta_id; + + /* Initialize rate scaling */ + IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n", + sta->addr); + iwl_rs_rate_init(priv, sta, sta_id); + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_channel *channel = ch_switch->channel; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; + /* + * MULTI-FIXME + * When we add support for multiple interfaces, we need to + * revisit this. The channel switch command in the device + * only affects the BSS context, but what does that really + * mean? And what if we get a CSA on the second interface? + * This needs a lot of work. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + u16 ch; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + mutex_lock(&priv->shrd->mutex); + + if (iwl_is_rfkill(priv->shrd)) + goto out; + + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) || + test_bit(STATUS_SCANNING, &priv->shrd->status) || + test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status)) + goto out; + + if (!iwl_is_associated_ctx(ctx)) + goto out; + + if (!priv->cfg->lib->set_channel_switch) + goto out; + + ch = channel->hw_value; + if (le16_to_cpu(ctx->active.channel) == ch) + goto out; + + ch_info = iwl_get_channel_info(priv, channel->band, ch); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211(priv, "invalid channel\n"); + goto out; + } + + spin_lock_irq(&priv->shrd->lock); + + priv->current_ht_config.smps = conf->smps_mode; + + /* Configure HT40 channels */ + ctx->ht.enabled = conf_is_ht(conf); + if (ctx->ht.enabled) { + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } + } else + ctx->ht.is_40mhz = false; + + if ((le16_to_cpu(ctx->staging.channel) != ch)) + ctx->staging.flags = 0; + + iwl_set_rxon_channel(priv, channel, ctx); + iwl_set_rxon_ht(priv, ht_conf); + iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); + + spin_unlock_irq(&priv->shrd->lock); + + iwl_set_rate(priv); + /* + * at this point, staging_rxon has the + * configuration for channel switch + */ + set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); + priv->switch_channel = cpu_to_le16(ch); + if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) { + clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); + priv->switch_channel = 0; + ieee80211_chswitch_done(ctx->vif, false); + } + +out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct iwl_priv *priv = hw->priv; + __le32 filter_or = 0, filter_nand = 0; + struct iwl_rxon_context *ctx; + +#define CHK(test, flag) do { \ + if (*total_flags & (test)) \ + filter_or |= (flag); \ + else \ + filter_nand |= (flag); \ + } while (0) + + IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); + /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */ + CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK); + CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); + +#undef CHK + + mutex_lock(&priv->shrd->mutex); + + for_each_context(priv, ctx) { + ctx->staging.filter_flags &= ~filter_nand; + ctx->staging.filter_flags |= filter_or; + + /* + * Not committing directly because hardware can perform a scan, + * but we'll eventually commit the filter flags change anyway. + */ + } + + mutex_unlock(&priv->shrd->mutex); + + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; +} + +static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) +{ + struct iwl_priv *priv = hw->priv; + + mutex_lock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { + IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n"); + goto done; + } + if (iwl_is_rfkill(priv->shrd)) { + IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n"); + goto done; + } + + /* + * mac80211 will not push any more frames for transmit + * until the flush is completed + */ + if (drop) { + IWL_DEBUG_MAC80211(priv, "send flush command\n"); + if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { + IWL_ERR(priv, "flush request fail\n"); + goto done; + } + } + IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); + iwl_trans_wait_tx_queue_empty(trans(priv)); +done: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + int duration) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; + int err = 0; + + if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT))) + return -EOPNOTSUPP; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { + err = -EBUSY; + goto out; + } + + priv->hw_roc_channel = channel; + priv->hw_roc_chantype = channel_type; + /* convert from ms to TU */ + priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024); + priv->hw_roc_start_notified = false; + cancel_delayed_work(&priv->hw_roc_disable_work); + + if (!ctx->is_active) { + static const struct iwl_qos_info default_qos_data = { + .def_qos_parm = { + .ac[0] = { + .cw_min = cpu_to_le16(3), + .cw_max = cpu_to_le16(7), + .aifsn = 2, + .edca_txop = cpu_to_le16(1504), + }, + .ac[1] = { + .cw_min = cpu_to_le16(7), + .cw_max = cpu_to_le16(15), + .aifsn = 2, + .edca_txop = cpu_to_le16(3008), + }, + .ac[2] = { + .cw_min = cpu_to_le16(15), + .cw_max = cpu_to_le16(1023), + .aifsn = 3, + }, + .ac[3] = { + .cw_min = cpu_to_le16(15), + .cw_max = cpu_to_le16(1023), + .aifsn = 7, + }, + }, + }; + + ctx->is_active = true; + ctx->qos_data = default_qos_data; + ctx->staging.dev_type = RXON_DEV_TYPE_P2P; + memcpy(ctx->staging.node_addr, + priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, + ETH_ALEN); + memcpy(ctx->staging.bssid_addr, + priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, + ETH_ALEN); + err = iwlagn_commit_rxon(priv, ctx); + if (err) + goto out; + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK | + RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK; + + err = iwlagn_commit_rxon(priv, ctx); + if (err) { + iwlagn_disable_roc(priv); + goto out; + } + priv->hw_roc_setup = true; + } + + err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band); + if (err) + iwlagn_disable_roc(priv); + + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return err; +} + +static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + iwl_scan_cancel_timeout(priv, priv->hw_roc_duration); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return 0; +} + +static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid, + enum ieee80211_tx_sync_type type) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *ctx = vif_priv->ctx; + int ret; + u8 sta_id; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (iwl_is_associated_ctx(ctx)) { + ret = 0; + goto out; + } + + if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, + &priv->shrd->status)) { + ret = -EBUSY; + goto out; + } + + ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id); + if (ret) + goto out; + + if (WARN_ON(sta_id != ctx->ap_sta_id)) { + ret = -EIO; + goto out_remove_sta; + } + + memcpy(ctx->bssid, bssid, ETH_ALEN); + ctx->preauth_bssid = true; + + ret = iwlagn_commit_rxon(priv, ctx); + + if (ret == 0) + goto out; + + out_remove_sta: + iwl_remove_station(priv, sta_id, bssid); + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid, + enum ieee80211_tx_sync_type type) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *ctx = vif_priv->ctx; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (iwl_is_associated_ctx(ctx)) + goto out; + + iwl_remove_station(priv, ctx->ap_sta_id, bssid); + ctx->preauth_bssid = false; + /* no need to commit */ + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, + enum ieee80211_rssi_event rssi_event) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { + if (rssi_event == RSSI_EVENT_LOW) + priv->bt_enable_pspoll = true; + else if (rssi_event == RSSI_EVENT_HIGH) + priv->bt_enable_pspoll = false; + + iwlagn_send_advance_bt_config(priv); + } else { + IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled," + "ignoring RSSI callback\n"); + } + + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) +{ + struct iwl_priv *priv = hw->priv; + + queue_work(priv->shrd->workqueue, &priv->beacon_update); + + return 0; +} + +static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *ctx = vif_priv->ctx; + unsigned long flags; + int q; + + if (WARN_ON(!ctx)) + return -EINVAL; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv->shrd)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); + return 0; + } + + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->shrd->lock, flags); + + ctx->qos_data.def_qos_parm.ac[q].cw_min = + cpu_to_le16(params->cw_min); + ctx->qos_data.def_qos_parm.ac[q].cw_max = + cpu_to_le16(params->cw_max); + ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + ctx->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->txop * 32)); + + ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0; + + spin_unlock_irqrestore(&priv->shrd->lock, flags); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; +} + +static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + return priv->ibss_manager == IWL_IBSS_MANAGER; +} + +static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + iwl_connection_init_rx_config(priv, ctx); + + iwlagn_set_rxon_chain(priv, ctx); + + return iwlagn_commit_rxon(priv, ctx); +} + +static int iwl_setup_interface(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + struct ieee80211_vif *vif = ctx->vif; + int err; + + lockdep_assert_held(&priv->shrd->mutex); + + /* + * This variable will be correct only when there's just + * a single context, but all code using it is for hardware + * that supports only one context. + */ + priv->iw_mode = vif->type; + + ctx->is_active = true; + + err = iwl_set_mode(priv, ctx); + if (err) { + if (!ctx->always_active) + ctx->is_active = false; + return err; + } + + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && + vif->type == NL80211_IFTYPE_ADHOC) { + /* + * pretend to have high BT traffic as long as we + * are operating in IBSS mode, as this will cause + * the rate scaling etc. to behave as intended. + */ + priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; + } + + return 0; +} + +static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *tmp, *ctx = NULL; + int err; + enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif); + + IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", + viftype, vif->addr); + + cancel_delayed_work_sync(&priv->hw_roc_disable_work); + + mutex_lock(&priv->shrd->mutex); + + iwlagn_disable_roc(priv); + + if (!iwl_is_ready_rf(priv->shrd)) { + IWL_WARN(priv, "Try to add interface when device not ready\n"); + err = -EINVAL; + goto out; + } + + for_each_context(priv, tmp) { + u32 possible_modes = + tmp->interface_modes | tmp->exclusive_interface_modes; + + if (tmp->vif) { + /* check if this busy context is exclusive */ + if (tmp->exclusive_interface_modes & + BIT(tmp->vif->type)) { + err = -EINVAL; + goto out; + } + continue; + } + + if (!(possible_modes & BIT(viftype))) + continue; + + /* have maybe usable context w/o interface */ + ctx = tmp; + break; + } + + if (!ctx) { + err = -EOPNOTSUPP; + goto out; + } + + vif_priv->ctx = ctx; + ctx->vif = vif; + + err = iwl_setup_interface(priv, ctx); + if (!err) + goto out; + + ctx->vif = NULL; + priv->iw_mode = NL80211_IFTYPE_STATION; + out: + mutex_unlock(&priv->shrd->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + return err; +} + +static void iwl_teardown_interface(struct iwl_priv *priv, + struct ieee80211_vif *vif, + bool mode_change) +{ + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + + lockdep_assert_held(&priv->shrd->mutex); + + if (priv->scan_vif == vif) { + iwl_scan_cancel_timeout(priv, 200); + iwl_force_scan_end(priv); + } + + if (!mode_change) { + iwl_set_mode(priv, ctx); + if (!ctx->always_active) + ctx->is_active = false; + } + + /* + * When removing the IBSS interface, overwrite the + * BT traffic load with the stored one from the last + * notification, if any. If this is a device that + * doesn't implement this, this has no effect since + * both values are the same and zero. + */ + if (vif->type == NL80211_IFTYPE_ADHOC) + priv->bt_traffic_load = priv->last_bt_traffic_load; +} + +static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + mutex_lock(&priv->shrd->mutex); + + if (WARN_ON(ctx->vif != vif)) { + struct iwl_rxon_context *tmp; + IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif); + for_each_context(priv, tmp) + IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n", + tmp->ctxid, tmp, tmp->vif); + } + ctx->vif = NULL; + + iwl_teardown_interface(priv, vif, false); + + mutex_unlock(&priv->shrd->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + +} + +static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype newtype, bool newp2p) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl_rxon_context *tmp; + enum nl80211_iftype newviftype = newtype; + u32 interface_modes; + int err; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + newtype = ieee80211_iftype_p2p(newtype, newp2p); + + mutex_lock(&priv->shrd->mutex); + + if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) { + /* + * Huh? But wait ... this can maybe happen when + * we're in the middle of a firmware restart! + */ + err = -EBUSY; + goto out; + } + + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; + + if (!(interface_modes & BIT(newtype))) { + err = -EBUSY; + goto out; + } + + /* + * Refuse a change that should be done by moving from the PAN + * context to the BSS context instead, if the BSS context is + * available and can support the new interface type. + */ + if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && + (bss_ctx->interface_modes & BIT(newtype) || + bss_ctx->exclusive_interface_modes & BIT(newtype))) { + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + err = -EBUSY; + goto out; + } + + if (ctx->exclusive_interface_modes & BIT(newtype)) { + for_each_context(priv, tmp) { + if (ctx == tmp) + continue; + + if (!tmp->vif) + continue; + + /* + * The current mode switch would be exclusive, but + * another context is active ... refuse the switch. + */ + err = -EBUSY; + goto out; + } + } + + /* success */ + iwl_teardown_interface(priv, vif, true); + vif->type = newviftype; + vif->p2p = newp2p; + err = iwl_setup_interface(priv, ctx); + WARN_ON(err); + /* + * We've switched internally, but submitting to the + * device may have failed for some reason. Mask this + * error, because otherwise mac80211 will not switch + * (and set the interface type back) and we'll be + * out of sync with it. + */ + err = 0; + + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return err; +} + +static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_scan_request *req) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (req->n_channels == 0) + return -EINVAL; + + mutex_lock(&priv->shrd->mutex); + + /* + * If an internal scan is in progress, just set + * up the scan_request as per above. + */ + if (priv->scan_type != IWL_SCAN_NORMAL) { + IWL_DEBUG_SCAN(priv, + "SCAN request during internal scan - defer\n"); + priv->scan_request = req; + priv->scan_vif = vif; + ret = 0; + } else { + priv->scan_request = req; + priv->scan_vif = vif; + /* + * mac80211 will only ask for one band at a time + * so using channels[0] here is ok + */ + ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL, + req->channels[0]->band); + if (ret) { + priv->scan_request = NULL; + priv->scan_vif = NULL; + } + } + + IWL_DEBUG_MAC80211(priv, "leave\n"); + + mutex_unlock(&priv->shrd->mutex); + + return ret; +} + +static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + int ret; + + IWL_DEBUG_MAC80211(priv, "enter: received request to remove " + "station %pM\n", sta->addr); + mutex_lock(&priv->shrd->mutex); + IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", + sta->addr); + ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr); + if (ret) + IWL_DEBUG_QUIET_RFKILL(priv, "Error removing station %pM\n", + sta->addr); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.sleep_tx_count = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + +} + +static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + int sta_id; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + switch (cmd) { + case STA_NOTIFY_SLEEP: + WARN_ON(!sta_priv->client); + sta_priv->asleep = true; + if (atomic_read(&sta_priv->pending_frames) > 0) + ieee80211_sta_block_awake(hw, sta, true); + break; + case STA_NOTIFY_AWAKE: + WARN_ON(!sta_priv->client); + if (!sta_priv->asleep) + break; + sta_priv->asleep = false; + sta_id = iwl_sta_id(sta); + if (sta_id != IWL_INVALID_STATION) + iwl_sta_modify_ps_wake(priv, sta_id); + break; + default: + break; + } + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +struct ieee80211_ops iwlagn_hw_ops = { + .tx = iwlagn_mac_tx, + .start = iwlagn_mac_start, + .stop = iwlagn_mac_stop, +#ifdef CONFIG_PM_SLEEP + .suspend = iwlagn_mac_suspend, + .resume = iwlagn_mac_resume, +#endif + .add_interface = iwlagn_mac_add_interface, + .remove_interface = iwlagn_mac_remove_interface, + .change_interface = iwlagn_mac_change_interface, + .config = iwlagn_mac_config, + .configure_filter = iwlagn_configure_filter, + .set_key = iwlagn_mac_set_key, + .update_tkip_key = iwlagn_mac_update_tkip_key, + .set_rekey_data = iwlagn_mac_set_rekey_data, + .conf_tx = iwlagn_mac_conf_tx, + .bss_info_changed = iwlagn_bss_info_changed, + .ampdu_action = iwlagn_mac_ampdu_action, + .hw_scan = iwlagn_mac_hw_scan, + .sta_notify = iwlagn_mac_sta_notify, + .sta_add = iwlagn_mac_sta_add, + .sta_remove = iwlagn_mac_sta_remove, + .channel_switch = iwlagn_mac_channel_switch, + .flush = iwlagn_mac_flush, + .tx_last_beacon = iwlagn_mac_tx_last_beacon, + .remain_on_channel = iwlagn_mac_remain_on_channel, + .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel, + .rssi_callback = iwlagn_mac_rssi_callback, + CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd) + CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump) + .tx_sync = iwlagn_mac_tx_sync, + .finish_tx_sync = iwlagn_mac_finish_tx_sync, + .set_tim = iwlagn_mac_set_tim, +}; + +/* This function both allocates and initializes hw and priv. */ +struct ieee80211_hw *iwl_alloc_all(void) +{ + struct iwl_priv *priv; + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + struct ieee80211_hw *hw; + + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); + if (!hw) + goto out; + + priv = hw->priv; + priv->hw = hw; + +out: + return hw; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 19cc6a81da57..86d6a2354e8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -255,6 +255,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)}, {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)}, {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)}, + {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */ + {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */ /* 6x30 Series */ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)}, @@ -324,46 +326,28 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)}, {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)}, {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)}, - {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)}, - {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)}, - {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)}, {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)}, /* 2x30 Series */ {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)}, {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)}, {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)}, - {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)}, - {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)}, - {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)}, /* 6x35 Series */ {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)}, - {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)}, - {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)}, - {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)}, - {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)}, - {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, - {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, /* 105 Series */ {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)}, {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)}, /* 135 Series */ {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)}, {0} }; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index a26fbd33a5d9..359d2182757b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -416,6 +416,8 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) if (!iwl_is_associated_ctx(ctx)) continue; + if (ctx->staging.dev_type == RXON_DEV_TYPE_P2P) + continue; value = ctx->beacon_int; if (!value) value = IWL_PASSIVE_DWELL_BASE; @@ -939,51 +941,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, return 0; } -int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct iwl_priv *priv = hw->priv; - int ret; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (req->n_channels == 0) - return -EINVAL; - - mutex_lock(&priv->shrd->mutex); - - /* - * If an internal scan is in progress, just set - * up the scan_request as per above. - */ - if (priv->scan_type != IWL_SCAN_NORMAL) { - IWL_DEBUG_SCAN(priv, - "SCAN request during internal scan - defer\n"); - priv->scan_request = req; - priv->scan_vif = vif; - ret = 0; - } else { - priv->scan_request = req; - priv->scan_vif = vif; - /* - * mac80211 will only ask for one band at a time - * so using channels[0] here is ok - */ - ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL, - req->channels[0]->band); - if (ret) { - priv->scan_request = NULL; - priv->scan_vif = NULL; - } - } - - IWL_DEBUG_MAC80211(priv, "leave\n"); - - mutex_unlock(&priv->shrd->mutex); - - return ret; -} /* * internal short scan, this function should only been called while associated. diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c index 5e50d88f302b..e3882d0cfc85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c @@ -396,8 +396,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: - status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, - IWL_UCODE_INIT); + status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT); if (status) IWL_DEBUG_INFO(priv, "Error loading init ucode: %d\n", status); @@ -409,9 +408,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: - status = iwlagn_load_ucode_wait_alive(priv, - &priv->ucode_rt, - IWL_UCODE_REGULAR); + status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); if (status) { IWL_DEBUG_INFO(priv, "Error loading runtime ucode: %d\n", status); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 2b6756e8b8f9..afaaa2a51b96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -355,7 +355,7 @@ static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) } static inline void iwl_wake_queue(struct iwl_trans *trans, - struct iwl_tx_queue *txq) + struct iwl_tx_queue *txq, const char *msg) { u8 queue = txq->swq_id; u8 ac = queue & 3; @@ -363,13 +363,22 @@ static inline void iwl_wake_queue(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) - if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) + if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) { + if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) { iwl_wake_sw_queue(priv(trans), ac); + IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s", + hwq, ac, msg); + } else { + IWL_DEBUG_TX_QUEUES(trans, "Don't wake hwq %d ac %d" + " stop count %d. %s", + hwq, ac, atomic_read(&trans_pcie-> + queue_stop_count[ac]), msg); + } + } } static inline void iwl_stop_queue(struct iwl_trans *trans, - struct iwl_tx_queue *txq) + struct iwl_tx_queue *txq, const char *msg) { u8 queue = txq->swq_id; u8 ac = queue & 3; @@ -377,9 +386,23 @@ static inline void iwl_stop_queue(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) - if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) + if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) { + if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) { iwl_stop_sw_queue(priv(trans), ac); + IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d" + " stop count %d. %s", + hwq, ac, atomic_read(&trans_pcie-> + queue_stop_count[ac]), msg); + } else { + IWL_DEBUG_TX_QUEUES(trans, "Don't stop hwq %d ac %d" + " stop count %d. %s", + hwq, ac, atomic_read(&trans_pcie-> + queue_stop_count[ac]), msg); + } + } else { + IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped/ %s", + hwq, msg); + } } #ifdef ieee80211_stop_queue diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index 374c68cc1d70..ee126f844a5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -1108,7 +1108,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) isr_stats->tx++; handled |= CSR_INT_BIT_FH_TX; /* Wake up uCode load routine, now that load is complete */ - priv(trans)->ucode_write_complete = 1; + trans->ucode_write_complete = 1; wake_up(&trans->shrd->wait_command_queue); } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index 4a0c95302a7e..6dba1515023c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -430,7 +430,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, txq->sched_retry = scd_retry; - IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n", + IWL_DEBUG_TX_QUEUES(trans, "%s %s Queue %d on FIFO %d\n", active ? "Activate" : "Deactivate", scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } @@ -561,12 +561,13 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, tid_data = &trans->shrd->tid_data[sta_id][tid]; if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_HT(trans, "HW queue is empty\n"); + IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); } else { - IWL_DEBUG_HT(trans, "HW queue is NOT empty: %d packets in HW" - "queue\n", tid_data->tfds_in_queue); + IWL_DEBUG_TX_QUEUES(trans, + "HW queue is NOT empty: %d packets in HW" + " queue\n", tid_data->tfds_in_queue); tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; } spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); @@ -643,14 +644,15 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, /* The queue is not empty */ if (write_ptr != read_ptr) { - IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n"); + IWL_DEBUG_TX_QUEUES(trans, + "Stopping a non empty AGG HW QUEUE\n"); trans->shrd->tid_data[sta_id][tid].agg.state = IWL_EMPTYING_HW_QUEUE_DELBA; spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); return 0; } - IWL_DEBUG_HT(trans, "HW queue is empty\n"); + IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n"); turn_off: trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; @@ -982,7 +984,8 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) ret = iwl_enqueue_hcmd(trans, cmd); if (ret < 0) { - IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", + IWL_DEBUG_QUIET_RFKILL(trans, + "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } @@ -1000,6 +1003,20 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); + if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) + return -EBUSY; + + + if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) { + IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + return -ECANCELED; + } + if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) { + IWL_ERR(trans, "Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + return -EIO; + } set_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->id)); @@ -1008,7 +1025,8 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (cmd_idx < 0) { ret = cmd_idx; clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); - IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", + IWL_DEBUG_QUIET_RFKILL(trans, + "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } @@ -1022,12 +1040,12 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) &trans_pcie->txq[trans->shrd->cmd_queue]; struct iwl_queue *q = &txq->q; - IWL_ERR(trans, + IWL_DEBUG_QUIET_RFKILL(trans, "Error sending %s: time out after %dms.\n", get_cmd_string(cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - IWL_ERR(trans, + IWL_DEBUG_QUIET_RFKILL(trans, "Current CMD queue read_ptr %d write_ptr %d\n", q->read_ptr, q->write_ptr); @@ -1039,18 +1057,6 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) } } - if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) { - IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n", - get_cmd_string(cmd->id)); - ret = -ECANCELED; - goto fail; - } - if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) { - IWL_ERR(trans, "Command %s failed: FW Error\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto fail; - } if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { IWL_ERR(trans, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); @@ -1071,7 +1077,7 @@ cancel: trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &= ~CMD_WANT_SKB; } -fail: + if (cmd->reply_page) { iwl_free_pages(trans->shrd, cmd->reply_page); cmd->reply_page = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index da3411057afc..a1a58330273f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1231,7 +1231,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, txq->need_update = 1; iwl_txq_update_write_ptr(trans, txq); } else { - iwl_stop_queue(trans, txq); + iwl_stop_queue(trans, txq, "Queue is full"); } } return 0; @@ -1283,20 +1283,21 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans, /* aggregated HW queue */ if ((txq_id == tid_data->agg.txq_id) && (q->read_ptr == q->write_ptr)) { - IWL_DEBUG_HT(trans, + IWL_DEBUG_TX_QUEUES(trans, "HW queue empty: continue DELBA flow\n"); iwl_trans_pcie_txq_agg_disable(trans, txq_id); tid_data->agg.state = IWL_AGG_OFF; iwl_stop_tx_ba_trans_ready(priv(trans), NUM_IWL_RXON_CTX, sta_id, tid); - iwl_wake_queue(trans, &trans_pcie->txq[txq_id]); + iwl_wake_queue(trans, &trans_pcie->txq[txq_id], + "DELBA flow complete"); } break; case IWL_EMPTYING_HW_QUEUE_ADDBA: /* We are reclaiming the last packet of the queue */ if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_HT(trans, + IWL_DEBUG_TX_QUEUES(trans, "HW queue empty: continue ADDBA flow\n"); tid_data->agg.state = IWL_AGG_ON; iwl_start_tx_ba_trans_ready(priv(trans), @@ -1354,7 +1355,7 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, ssn , tfd_num, txq_id, txq->swq_id); freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs); if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond) - iwl_wake_queue(trans, txq); + iwl_wake_queue(trans, txq, "Packets reclaimed"); } iwl_free_tfds_in_queue(trans, sta_id, tid, freed); @@ -1418,7 +1419,8 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) #endif /* CONFIG_PM_SLEEP */ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx) + enum iwl_rxon_context_id ctx, + const char *msg) { u8 ac, txq_id; struct iwl_trans_pcie *trans_pcie = @@ -1426,11 +1428,11 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans, for (ac = 0; ac < AC_NUM; ac++) { txq_id = trans_pcie->ac_to_queue[ctx][ac]; - IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n", + IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n", ac, (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0) ? "stopped" : "awake"); - iwl_wake_queue(trans, &trans_pcie->txq[txq_id]); + iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg); } } @@ -1453,11 +1455,12 @@ static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd) return iwl_trans; } -static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id) +static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id, + const char *msg) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - iwl_stop_queue(trans, &trans_pcie->txq[txq_id]); + iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg); } #define IWL_FLUSH_WAIT_MS 2000 diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index c5923125c3f9..50227ebc0ee2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -171,7 +171,8 @@ struct iwl_trans_ops { void (*tx_start)(struct iwl_trans *trans); void (*wake_any_queue)(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx); + enum iwl_rxon_context_id ctx, + const char *msg); int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); @@ -196,7 +197,7 @@ struct iwl_trans_ops { void (*free)(struct iwl_trans *trans); - void (*stop_queue)(struct iwl_trans *trans, int q); + void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg); int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); int (*check_stuck_queue)(struct iwl_trans *trans, int q); @@ -207,17 +208,48 @@ struct iwl_trans_ops { #endif }; +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + dma_addr_t p_addr; /* hardware address */ + void *v_addr; /* software address */ + u32 len; /* size in bytes */ +}; + +struct fw_img { + struct fw_desc code; /* firmware code image */ + struct fw_desc data; /* firmware data image */ +}; + +enum iwl_ucode_type { + IWL_UCODE_NONE, + IWL_UCODE_REGULAR, + IWL_UCODE_INIT, + IWL_UCODE_WOWLAN, +}; + /** * struct iwl_trans - transport common data * @ops - pointer to iwl_trans_ops * @shrd - pointer to iwl_shared which holds shared data from the upper layer * @hcmd_lock: protects HCMD + * @ucode_write_complete: indicates that the ucode has been copied. + * @ucode_rt: run time ucode image + * @ucode_init: init ucode image + * @ucode_wowlan: wake on wireless ucode image (optional) */ struct iwl_trans { const struct iwl_trans_ops *ops; struct iwl_shared *shrd; spinlock_t hcmd_lock; + u8 ucode_write_complete; /* the image write is complete */ + struct fw_img ucode_rt; + struct fw_img ucode_init; + struct fw_img ucode_wowlan; + + /* eeprom related variables */ + int nvm_device_type; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[0] __attribute__((__aligned__(sizeof(void *)))); @@ -249,9 +281,10 @@ static inline void iwl_trans_tx_start(struct iwl_trans *trans) } static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx) + enum iwl_rxon_context_id ctx, + const char *msg) { - trans->ops->wake_any_queue(trans, ctx); + trans->ops->wake_any_queue(trans, ctx, msg); } @@ -311,9 +344,10 @@ static inline void iwl_trans_free(struct iwl_trans *trans) trans->ops->free(trans); } -static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q) +static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q, + const char *msg) { - trans->ops->stop_queue(trans, q); + trans->ops->stop_queue(trans, q, msg); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) @@ -348,4 +382,8 @@ static inline int iwl_trans_resume(struct iwl_trans *trans) ******************************************************/ extern const struct iwl_trans_ops trans_ops_pcie; +int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc, + const void *data, size_t len); +void iwl_dealloc_ucode(struct iwl_trans *trans); + #endif /* __iwl_trans_h__ */ diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 4fcd653bddc4..89f34ad8d34a 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -485,6 +485,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, struct cmd_header *resp) { + struct cfg80211_bss *bss; struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp; int bsssize; const u8 *pos; @@ -632,12 +633,14 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, LBS_SCAN_RSSI_TO_MBM(rssi)/100); if (channel && - !(channel->flags & IEEE80211_CHAN_DISABLED)) - cfg80211_inform_bss(wiphy, channel, + !(channel->flags & IEEE80211_CHAN_DISABLED)) { + bss = cfg80211_inform_bss(wiphy, channel, bssid, le64_to_cpu(*(__le64 *)tsfdesc), capa, intvl, ie, ielen, LBS_SCAN_RSSI_TO_MBM(rssi), GFP_KERNEL); + cfg80211_put_bss(bss); + } } else lbs_deb_scan("scan response: missing BSS channel IE\n"); @@ -1720,6 +1723,7 @@ static void lbs_join_post(struct lbs_private *priv, 2 + 2 + /* atim */ 2 + 8]; /* extended rates */ u8 *fake = fake_ie; + struct cfg80211_bss *bss; lbs_deb_enter(LBS_DEB_CFG80211); @@ -1763,14 +1767,15 @@ static void lbs_join_post(struct lbs_private *priv, *fake++ = 0x6c; lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie); - cfg80211_inform_bss(priv->wdev->wiphy, - params->channel, - bssid, - 0, - capability, - params->beacon_interval, - fake_ie, fake - fake_ie, - 0, GFP_KERNEL); + bss = cfg80211_inform_bss(priv->wdev->wiphy, + params->channel, + bssid, + 0, + capability, + params->beacon_interval, + fake_ie, fake - fake_ie, + 0, GFP_KERNEL); + cfg80211_put_bss(bss); memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); priv->wdev->ssid_len = params->ssid_len; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 7aa9aa0ac958..681d3f2a4c28 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -33,7 +33,7 @@ * Since the buffer is linear, the function uses rotation to simulate * circular buffer. */ -static int +static void mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, int start_win) @@ -71,8 +71,6 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, rx_reor_tbl_ptr->start_win = start_win; spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - - return 0; } /* @@ -83,7 +81,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, * Since the buffer is linear, the function uses rotation to simulate * circular buffer. */ -static int +static void mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) { @@ -119,7 +117,6 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) &(MAX_TID_VALUE - 1); spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - return 0; } /* @@ -405,7 +402,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, u8 *ta, u8 pkt_type, void *payload) { struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; - int start_win, end_win, win_size, ret; + int start_win, end_win, win_size; u16 pkt_index; rx_reor_tbl_ptr = @@ -452,11 +449,8 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, start_win = (end_win - win_size) + 1; else start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; - ret = mwifiex_11n_dispatch_pkt_until_start_win(priv, + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, start_win); - - if (ret) - return ret; } if (pkt_type != PKT_TYPE_BAR) { @@ -475,9 +469,9 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, * Dispatch all packets sequentially from start_win until a * hole is found and adjust the start_win appropriately */ - ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); + mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); - return ret; + return 0; } /* diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 462c71067bfb..e9ab9a3fbe9c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -780,6 +780,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) { struct ieee80211_channel *chan; struct mwifiex_bss_info bss_info; + struct cfg80211_bss *bss; int ie_len; u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; enum ieee80211_band band; @@ -800,9 +801,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) ieee80211_channel_to_frequency(bss_info.bss_chan, band)); - cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 0, ie_buf, ie_len, 0, GFP_KERNEL); + cfg80211_put_bss(bss); memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); return 0; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 0cc5d73cb0c1..35cb29cbd96e 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -673,7 +673,7 @@ struct host_cmd_ds_802_11_ad_hoc_start { union ieee_types_phy_param_set phy_param_set; u16 reserved1; __le16 cap_info_bitmap; - u8 DataRate[HOSTCMD_SUPPORTED_RATES]; + u8 data_rate[HOSTCMD_SUPPORTED_RATES]; } __packed; struct host_cmd_ds_802_11_ad_hoc_result { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index d792b3fb7c16..26940455255b 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -187,8 +187,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL; skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm)); - sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) - (adapter->sleep_cfm->data); adapter->cmd_sent = false; @@ -254,6 +252,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) mwifiex_wmm_init(adapter); if (adapter->sleep_cfm) { + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) + adapter->sleep_cfm->data; memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); sleep_cfm_buf->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 62b4c2938608..1c4981367e50 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -724,8 +724,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, u32 cmd_append_size = 0; u32 i; u16 tmp_cap; - uint16_t ht_cap_info; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u8 radio_type; struct mwifiex_ie_types_htcap *ht_cap; struct mwifiex_ie_types_htinfo *ht_info; @@ -837,8 +837,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; } - memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate)); - mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); + memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate)); + mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); if ((adapter->adhoc_start_band & BAND_G) && (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, @@ -850,20 +850,19 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, } } /* Find the last non zero */ - for (i = 0; i < sizeof(adhoc_start->DataRate) && - adhoc_start->DataRate[i]; - i++) - ; + for (i = 0; i < sizeof(adhoc_start->data_rate); i++) + if (!adhoc_start->data_rate[i]) + break; priv->curr_bss_params.num_of_rates = i; /* Copy the ad-hoc creating rates into Current BSS rate structure */ memcpy(&priv->curr_bss_params.data_rates, - &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates); + &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", - adhoc_start->DataRate[0], adhoc_start->DataRate[1], - adhoc_start->DataRate[2], adhoc_start->DataRate[3]); + adhoc_start->data_rate[0], adhoc_start->data_rate[1], + adhoc_start->data_rate[2], adhoc_start->data_rate[3]); dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); @@ -914,55 +913,40 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, } if (adapter->adhoc_11n_enabled) { - { - ht_cap = (struct mwifiex_ie_types_htcap *) pos; - memset(ht_cap, 0, - sizeof(struct mwifiex_ie_types_htcap)); - ht_cap->header.type = - cpu_to_le16(WLAN_EID_HT_CAPABILITY); - ht_cap->header.len = - cpu_to_le16(sizeof(struct ieee80211_ht_cap)); - ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); - - ht_cap_info |= IEEE80211_HT_CAP_SGI_20; - if (adapter->chan_offset) { - ht_cap_info |= IEEE80211_HT_CAP_SGI_40; - ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40; - ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); - } + /* Fill HT CAPABILITY */ + ht_cap = (struct mwifiex_ie_types_htcap *) pos; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + radio_type = mwifiex_band_to_radio_type( + priv->adapter->config_bands); + mwifiex_fill_cap_info(priv, radio_type, ht_cap); + + pos += sizeof(struct mwifiex_ie_types_htcap); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htcap); - ht_cap->ht_cap.ampdu_params_info - = IEEE80211_HT_MAX_AMPDU_64K; - ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; - pos += sizeof(struct mwifiex_ie_types_htcap); - cmd_append_size += - sizeof(struct mwifiex_ie_types_htcap); - } - { - ht_info = (struct mwifiex_ie_types_htinfo *) pos; - memset(ht_info, 0, - sizeof(struct mwifiex_ie_types_htinfo)); - ht_info->header.type = - cpu_to_le16(WLAN_EID_HT_INFORMATION); - ht_info->header.len = - cpu_to_le16(sizeof(struct ieee80211_ht_info)); - ht_info->ht_info.control_chan = - (u8) priv->curr_bss_params.bss_descriptor. - channel; - if (adapter->chan_offset) { - ht_info->ht_info.ht_param = - adapter->chan_offset; - ht_info->ht_info.ht_param |= + /* Fill HT INFORMATION */ + ht_info = (struct mwifiex_ie_types_htinfo *) pos; + memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); + ht_info->header.type = cpu_to_le16(WLAN_EID_HT_INFORMATION); + ht_info->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + + ht_info->ht_info.control_chan = + (u8) priv->curr_bss_params.bss_descriptor.channel; + if (adapter->chan_offset) { + ht_info->ht_info.ht_param = adapter->chan_offset; + ht_info->ht_info.ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; - } - ht_info->ht_info.operation_mode = - cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - ht_info->ht_info.basic_set[0] = 0xff; - pos += sizeof(struct mwifiex_ie_types_htinfo); - cmd_append_size += - sizeof(struct mwifiex_ie_types_htinfo); } + ht_info->ht_info.operation_mode = + cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + ht_info->ht_info.basic_set[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htinfo); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htinfo); } cmd->size = cpu_to_le16((u16) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 8a3f9598ad33..8a18bcc23b26 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1535,11 +1535,6 @@ done: return 0; } -static void mwifiex_free_bss_priv(struct cfg80211_bss *bss) -{ - kfree(bss->priv); -} - /* * This function handles the command response of scan. * @@ -1765,7 +1760,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, cap_info_bitmap, beacon_period, ie_buf, ie_len, rssi, GFP_KERNEL); *(u8 *)bss->priv = band; - bss->free_priv = mwifiex_free_bss_priv; + cfg80211_put_bss(bss); if (priv->media_connected && !memcmp(bssid, priv->curr_bss_params.bss_descriptor diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 27430512f7cd..5e1ef7e5da4f 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -126,6 +126,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, u16 rx_pkt_type; struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + if (!priv) + return -1; + local_rx_pd = (struct rxpd *) (skb->data); rx_pkt_type = local_rx_pd->rx_pkt_type; @@ -189,12 +192,11 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, (u8) local_rx_pd->rx_pkt_type, skb); - if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { - if (priv && (ret == -1)) - priv->stats.rx_dropped++; - + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) dev_kfree_skb_any(skb); - } + + if (ret) + priv->stats.rx_dropped++; return ret; } |