diff options
Diffstat (limited to 'drivers/net')
99 files changed, 3703 insertions, 1974 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 3a69804f4c16..d1ff3c246a12 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -86,29 +86,25 @@ static int ath_ahb_probe(struct platform_device *pdev) if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "no platform data specified\n"); - ret = -EINVAL; - goto err_out; + return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "no memory resource found\n"); - ret = -ENXIO; - goto err_out; + return -ENXIO; } - mem = ioremap_nocache(res->start, resource_size(res)); + mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (mem == NULL) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_out; + return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { dev_err(&pdev->dev, "no IRQ resource found\n"); - ret = -ENXIO; - goto err_iounmap; + return -ENXIO; } irq = res->start; @@ -116,8 +112,7 @@ static int ath_ahb_probe(struct platform_device *pdev) hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); - ret = -ENOMEM; - goto err_iounmap; + return -ENOMEM; } SET_IEEE80211_DEV(hw, &pdev->dev); @@ -156,9 +151,6 @@ static int ath_ahb_probe(struct platform_device *pdev) err_free_hw: ieee80211_free_hw(hw); platform_set_drvdata(pdev, NULL); - err_iounmap: - iounmap(mem); - err_out: return ret; } @@ -168,12 +160,10 @@ static int ath_ahb_remove(struct platform_device *pdev) if (hw) { struct ath_softc *sc = hw->priv; - void __iomem *mem = sc->mem; ath9k_deinit_device(sc); free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); - iounmap(mem); platform_set_drvdata(pdev, NULL); } diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h index f81e7fc60a36..467ccfae2cee 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h @@ -466,7 +466,7 @@ static const u32 ar5416Bank0[][2] = { }; static const u32 ar5416BB_RfGain[][3] = { - /* Addr 5G_HT20 5G_HT40 */ + /* Addr 5G 2G */ {0x00009a00, 0x00000000, 0x00000000}, {0x00009a04, 0x00000040, 0x00000040}, {0x00009a08, 0x00000080, 0x00000080}, @@ -546,12 +546,12 @@ static const u32 ar5416Bank2[][2] = { }; static const u32 ar5416Bank3[][3] = { - /* Addr 5G_HT20 5G_HT40 */ + /* Addr 5G 2G */ {0x000098f0, 0x01400018, 0x01c00018}, }; static const u32 ar5416Bank6[][3] = { - /* Addr 5G_HT20 5G_HT40 */ + /* Addr 5G 2G */ {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, @@ -588,7 +588,7 @@ static const u32 ar5416Bank6[][3] = { }; static const u32 ar5416Bank6TPC[][3] = { - /* Addr 5G_HT20 5G_HT40 */ + /* Addr 5G 2G */ {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 874186bfda41..fd69376ecc83 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -470,16 +470,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) { #define ATH_ALLOC_BANK(bank, size) do { \ - bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ - if (!bank) { \ - ath_err(common, "Cannot allocate RF banks\n"); \ - return -ENOMEM; \ - } \ + bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \ + if (!bank) \ + goto error; \ } while (0); struct ath_common *common = ath9k_hw_common(ah); - BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); + if (AR_SREV_9280_20_OR_LATER(ah)) + return 0; ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); @@ -492,35 +491,12 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) return 0; #undef ATH_ALLOC_BANK +error: + ath_err(common, "Cannot allocate RF banks\n"); + return -ENOMEM; } -/** - * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers - * @ah: atheros hardware struture - * For the external AR2133/AR5133 radios banks. - */ -static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah) -{ -#define ATH_FREE_BANK(bank) do { \ - kfree(bank); \ - bank = NULL; \ - } while (0); - - BUG_ON(AR_SREV_9280_20_OR_LATER(ah)); - - ATH_FREE_BANK(ah->analogBank0Data); - ATH_FREE_BANK(ah->analogBank1Data); - ATH_FREE_BANK(ah->analogBank2Data); - ATH_FREE_BANK(ah->analogBank3Data); - ATH_FREE_BANK(ah->analogBank6Data); - ATH_FREE_BANK(ah->analogBank6TPCData); - ATH_FREE_BANK(ah->analogBank7Data); - ATH_FREE_BANK(ah->bank6Temp); - -#undef ATH_FREE_BANK -} - /* * * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM * @ah: atheros hardware structure @@ -1380,7 +1356,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) conf->radar_inband = 8; } -void ar5008_hw_attach_phy_ops(struct ath_hw *ah) +int ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); static const u32 ar5416_cca_regs[6] = { @@ -1391,12 +1367,15 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) AR_PHY_CH1_EXT_CCA, AR_PHY_CH2_EXT_CCA }; + int ret; + + ret = ar5008_hw_rf_alloc_ext_banks(ah); + if (ret) + return ret; priv_ops->rf_set_freq = ar5008_hw_set_channel; priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate; - priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks; - priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks; priv_ops->set_rf_regs = ar5008_hw_set_rf_regs; priv_ops->set_channel_regs = ar5008_hw_set_channel_regs; priv_ops->init_bb = ar5008_hw_init_bb; @@ -1421,4 +1400,5 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) ar5008_hw_set_nf_limits(ah); ar5008_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs)); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h index ea4a230997ac..59524e1d4678 100644 --- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h @@ -460,7 +460,7 @@ static const u32 ar5416Common_9100[][2] = { }; static const u32 ar5416Bank6_9100[][3] = { - /* Addr 5G_HT20 5G_HT40 */ + /* Addr 5G 2G */ {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, @@ -497,7 +497,7 @@ static const u32 ar5416Bank6_9100[][3] = { }; static const u32 ar5416Bank6TPC_9100[][3] = { - /* Addr 5G_HT20 5G_HT40 */ + /* Addr 5G 2G */ {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, {0x0000989c, 0x00000000, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 648da3e885e9..54da026f058c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -102,7 +102,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns; u32 *data; - data = kmalloc(size, GFP_KERNEL); + data = devm_kzalloc(ah->dev, size, GFP_KERNEL); if (!data) return; @@ -409,22 +409,27 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah) } /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */ -void ar9002_hw_attach_ops(struct ath_hw *ah) +int ar9002_hw_attach_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); + int ret; priv_ops->init_mode_regs = ar9002_hw_init_mode_regs; priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs; ops->config_pci_powersave = ar9002_hw_configpcipowersave; - ar5008_hw_attach_phy_ops(ah); + ret = ar5008_hw_attach_phy_ops(ah); + if (ret) + return ret; + if (AR_SREV_9280_20_OR_LATER(ah)) ar9002_hw_attach_phy_ops(ah); ar9002_hw_attach_calib_ops(ah); ar9002_hw_attach_mac_ops(ah); + return 0; } void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 846dd7974eb8..f4003512d8d5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -555,14 +555,73 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); } +static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, + struct ath_spec_scan *param) +{ + u8 count; + + if (!param->enabled) { + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ENABLE); + return; + } + REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); + + if (param->short_repeat) + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + else + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + + /* on AR92xx, the highest bit of count will make the the chip send + * spectral samples endlessly. Check if this really was intended, + * and fix otherwise. + */ + count = param->count; + if (param->endless) + count = 0x80; + else if (count & 0x80) + count = 0x7f; + + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_COUNT, count); + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period); + + return; +} + +static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); + /* Activate spectral scan */ + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ACTIVE); +} + +static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* Poll for spectral scan complete */ + if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ACTIVE, + 0, AH_WAIT_TIMEOUT)) { + ath_err(common, "spectral scan wait failed\n"); + return; + } +} + void ar9002_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); priv_ops->set_rf_regs = NULL; - priv_ops->rf_alloc_ext_banks = NULL; - priv_ops->rf_free_ext_banks = NULL; priv_ops->rf_set_freq = ar9002_hw_set_channel; priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; priv_ops->olc_init = ar9002_olc_init; @@ -571,6 +630,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; + ops->spectral_scan_config = ar9002_hw_spectral_scan_config; + ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger; + ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait; ar9002_hw_set_nf_limits(ah); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 262e1e036fd7..db5ffada2217 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -744,6 +744,186 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; +static const u32 ar9300Modes_mixed_ob_db_tx_gain_table_2p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, + {0x0000a544, 0x52022470, 0x52022470, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x55022490, 0x55022490, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59022492, 0x59022492, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5d022692, 0x5d022692, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61022892, 0x61022892, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x65024890, 0x65024890, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x69024892, 0x69024892, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6e024c92, 0x6e024c92, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, + {0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x52822470, 0x52822470, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x55822490, 0x55822490, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59822492, 0x59822492, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5d822692, 0x5d822692, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61822892, 0x61822892, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x65824890, 0x65824890, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x69824892, 0x69824892, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, + {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, + {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, + {0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, + {0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, + {0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +static const u32 ar9300Modes_type5_tx_gain_table_2p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + static const u32 ar9300Common_rx_gain_table_2p2[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 8b0d8dcd7625..9221f32a322e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -32,7 +32,6 @@ struct coeff { enum ar9003_cal_types { IQ_MISMATCH_CAL = BIT(0), - TEMP_COMP_CAL = BIT(1), }; static void ar9003_hw_setup_calibration(struct ath_hw *ah, @@ -49,7 +48,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, */ REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, - currCal->calData->calCountMax); + currCal->calData->calCountMax); REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); ath_dbg(common, CALIBRATE, @@ -58,14 +57,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, /* Kick-off cal */ REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); break; - case TEMP_COMP_CAL: - REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, - AR_PHY_65NM_CH0_THERM_LOCAL, 1); - REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, - AR_PHY_65NM_CH0_THERM_START, 1); - - ath_dbg(common, CALIBRATE, - "starting Temperature Compensation Calibration\n"); + default: + ath_err(common, "Invalid calibration type\n"); break; } } @@ -323,6 +316,14 @@ static const struct ath9k_percal_data iq_cal_single_sample = { static void ar9003_hw_init_cal_settings(struct ath_hw *ah) { ah->iq_caldata.calData = &iq_cal_single_sample; + + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->enabled_cals |= TX_IQ_CAL; + if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah)) + ah->enabled_cals |= TX_IQ_ON_AGC_CAL; + } + + ah->supp_cals = IQ_MISMATCH_CAL; } /* @@ -959,22 +960,68 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); } +static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int i; + + if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah)) + return; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan)); + } +} + +static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) +{ + u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, + AR_PHY_CL_TAB_1, + AR_PHY_CL_TAB_2 }; + struct ath9k_hw_cal_data *caldata = ah->caldata; + bool txclcal_done = false; + int i, j; + + if (!caldata || !(ah->enabled_cals & TX_CL_CAL)) + return; + + txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_CLC_SUCCESS); + + if (caldata->done_txclcal_once) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->txchainmask & (1 << i))) + continue; + for (j = 0; j < MAX_CL_TAB_ENTRY; j++) + REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]), + caldata->tx_clcal[i][j]); + } + } else if (is_reusable && txclcal_done) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->txchainmask & (1 << i))) + continue; + for (j = 0; j < MAX_CL_TAB_ENTRY; j++) + caldata->tx_clcal[i][j] = + REG_READ(ah, CL_TAB_ENTRY(cl_idx[i])); + } + caldata->done_txclcal_once = true; + } +} + static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; - bool txiqcal_done = false, txclcal_done = false; + bool txiqcal_done = false; bool is_reusable = true, status = true; - bool run_rtt_cal = false, run_agc_cal; + bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_PKDET_CAL; - int i, j; - u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, - AR_PHY_CL_TAB_1, - AR_PHY_CL_TAB_2 }; if (rtt) { if (!ar9003_hw_rtt_restore(ah, chan)) @@ -1012,7 +1059,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, } } - if (!(ah->enabled_cals & TX_IQ_CAL)) + if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) || + !(ah->enabled_cals & TX_IQ_CAL)) goto skip_tx_iqcal; /* Do Tx IQ Calibration */ @@ -1032,21 +1080,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); txiqcal_done = run_agc_cal = true; - goto skip_tx_iqcal; - } else if (caldata && !caldata->done_txiqcal_once) + } else if (caldata && !caldata->done_txiqcal_once) { run_agc_cal = true; + sep_iq_cal = true; + } +skip_tx_iqcal: if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) ar9003_mci_init_cal_req(ah, &is_reusable); - if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) { + if (sep_iq_cal) { txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); udelay(5); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); } -skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, @@ -1057,14 +1106,8 @@ skip_tx_iqcal: status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->rxchainmask & (1 << i))) - continue; - ar9003_hw_manual_peak_cal(ah, i, - IS_CHAN_2GHZ(chan)); - } - } + + ar9003_hw_do_manual_peak_cal(ah, chan); } if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) @@ -1089,31 +1132,7 @@ skip_tx_iqcal: else if (caldata && caldata->done_txiqcal_once) ar9003_hw_tx_iq_cal_reload(ah); -#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) - if (caldata && (ah->enabled_cals & TX_CL_CAL)) { - txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_CLC_SUCCESS); - if (caldata->done_txclcal_once) { - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->txchainmask & (1 << i))) - continue; - for (j = 0; j < MAX_CL_TAB_ENTRY; j++) - REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]), - caldata->tx_clcal[i][j]); - } - } else if (is_reusable && txclcal_done) { - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->txchainmask & (1 << i))) - continue; - for (j = 0; j < MAX_CL_TAB_ENTRY; j++) - caldata->tx_clcal[i][j] = - REG_READ(ah, - CL_TAB_ENTRY(cl_idx[i])); - } - caldata->done_txclcal_once = true; - } - } -#undef CL_TAB_ENTRY + ar9003_hw_cl_cal_post_proc(ah, is_reusable); if (run_rtt_cal && caldata) { if (is_reusable) { @@ -1131,20 +1150,10 @@ skip_tx_iqcal: /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; - ah->supp_cals = IQ_MISMATCH_CAL; - - if (ah->supp_cals & IQ_MISMATCH_CAL) { - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); - } - if (ah->supp_cals & TEMP_COMP_CAL) { - INIT_CAL(&ah->tempCompCalData); - INSERT_CAL(ah, &ah->tempCompCalData); - ath_dbg(common, CALIBRATE, - "enabling Temperature Compensation Calibration\n"); - } + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); /* Initialize current pointer to first element in list */ ah->cal_list_curr = ah->cal_list; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 562186ca9b52..881e989ea470 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4586,14 +4586,14 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, return 0; } -static int ar9003_hw_power_control_override(struct ath_hw *ah, - int frequency, - int *correction, - int *voltage, int *temperature) +static void ar9003_hw_power_control_override(struct ath_hw *ah, + int frequency, + int *correction, + int *voltage, int *temperature) { - int tempSlope = 0; + int temp_slope = 0, temp_slope1 = 0, temp_slope2 = 0; struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - int f[8], t[8], i; + int f[8], t[8], t1[3], t2[3], i; REG_RMW(ah, AR_PHY_TPC_11_B0, (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), @@ -4624,38 +4624,108 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah, * enable temperature compensation * Need to use register names */ - if (frequency < 4000) - tempSlope = eep->modalHeader2G.tempSlope; - else if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) { - for (i = 0; i < 8; i++) { - t[i] = eep->base_ext1.tempslopextension[i]; - f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0); + if (frequency < 4000) { + temp_slope = eep->modalHeader2G.tempSlope; + } else { + if (AR_SREV_9550(ah)) { + t[0] = eep->base_ext1.tempslopextension[2]; + t1[0] = eep->base_ext1.tempslopextension[3]; + t2[0] = eep->base_ext1.tempslopextension[4]; + f[0] = 5180; + + t[1] = eep->modalHeader5G.tempSlope; + t1[1] = eep->base_ext1.tempslopextension[0]; + t2[1] = eep->base_ext1.tempslopextension[1]; + f[1] = 5500; + + t[2] = eep->base_ext1.tempslopextension[5]; + t1[2] = eep->base_ext1.tempslopextension[6]; + t2[2] = eep->base_ext1.tempslopextension[7]; + f[2] = 5785; + + temp_slope = ar9003_hw_power_interpolate(frequency, + f, t, 3); + temp_slope1 = ar9003_hw_power_interpolate(frequency, + f, t1, 3); + temp_slope2 = ar9003_hw_power_interpolate(frequency, + f, t2, 3); + + goto tempslope; } - tempSlope = ar9003_hw_power_interpolate((s32) frequency, - f, t, 8); - } else if (eep->base_ext2.tempSlopeLow != 0) { - t[0] = eep->base_ext2.tempSlopeLow; - f[0] = 5180; - t[1] = eep->modalHeader5G.tempSlope; - f[1] = 5500; - t[2] = eep->base_ext2.tempSlopeHigh; - f[2] = 5785; - tempSlope = ar9003_hw_power_interpolate((s32) frequency, - f, t, 3); - } else - tempSlope = eep->modalHeader5G.tempSlope; - REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope); + if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) { + for (i = 0; i < 8; i++) { + t[i] = eep->base_ext1.tempslopextension[i]; + f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0); + } + temp_slope = ar9003_hw_power_interpolate((s32) frequency, + f, t, 8); + } else if (eep->base_ext2.tempSlopeLow != 0) { + t[0] = eep->base_ext2.tempSlopeLow; + f[0] = 5180; + t[1] = eep->modalHeader5G.tempSlope; + f[1] = 5500; + t[2] = eep->base_ext2.tempSlopeHigh; + f[2] = 5785; + temp_slope = ar9003_hw_power_interpolate((s32) frequency, + f, t, 3); + } else { + temp_slope = eep->modalHeader5G.tempSlope; + } + } + +tempslope: + if (AR_SREV_9550(ah)) { + /* + * AR955x has tempSlope register for each chain. + * Check whether temp_compensation feature is enabled or not. + */ + if (eep->baseEepHeader.featureEnable & 0x1) { + if (frequency < 4000) { + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeLow); + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeHigh); + } else { + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope1); + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope2); + } + } else { + /* + * If temp compensation is not enabled, + * set all registers to 0. + */ + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, 0); + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, 0); + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, 0); + } + } else { + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, temp_slope); + } if (AR_SREV_9462_20(ah)) REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope); + AR_PHY_TPC_19_B1_ALPHA_THERM, temp_slope); REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, temperature[0]); - - return 0; } /* Apply the recorded correction values. */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 74fd3977feeb..de8a56c92e1a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -507,28 +507,59 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_mixed_ob_db_tx_gain_table); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_mixed_ob_db_tx_gain_table_2p2); +} + +static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) +{ + if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9485Modes_green_ob_db_tx_gain_1_1); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_ub124_tx_gain_table_1p0); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_type5_tx_gain_table); + else if (AR_SREV_9300_22(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_type5_tx_gain_table_2p2); } +static void ar9003_tx_gain_table_mode6(struct ath_hw *ah) +{ + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9485Modes_green_spur_ob_db_tx_gain_1_1); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_type6_tx_gain_table); +} + +typedef void (*ath_txgain_tab)(struct ath_hw *ah); + static void ar9003_tx_gain_table_apply(struct ath_hw *ah) { - switch (ar9003_hw_get_tx_gain_idx(ah)) { - case 0: - default: - ar9003_tx_gain_table_mode0(ah); - break; - case 1: - ar9003_tx_gain_table_mode1(ah); - break; - case 2: - ar9003_tx_gain_table_mode2(ah); - break; - case 3: - ar9003_tx_gain_table_mode3(ah); - break; - case 4: - ar9003_tx_gain_table_mode4(ah); - break; - } + static const ath_txgain_tab modes[] = { + ar9003_tx_gain_table_mode0, + ar9003_tx_gain_table_mode1, + ar9003_tx_gain_table_mode2, + ar9003_tx_gain_table_mode3, + ar9003_tx_gain_table_mode4, + ar9003_tx_gain_table_mode5, + ar9003_tx_gain_table_mode6, + }; + int idx = ar9003_hw_get_tx_gain_idx(ah); + + if (idx >= ARRAY_SIZE(modes)) + idx = 0; + + modes[idx](ah); } static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ce19c09fa8e8..bf119a5f865a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -68,7 +68,7 @@ static const int m2ThreshExt_off = 127; static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { u16 bMode, fracMode = 0, aModeRefSel = 0; - u32 freq, channelSel = 0, reg32 = 0; + u32 freq, chan_frac, div, channelSel = 0, reg32 = 0; struct chan_centers centers; int loadSynthChannel; @@ -77,9 +77,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) if (freq < 4800) { /* 2 GHz, fractional mode */ if (AR_SREV_9330(ah)) { - u32 chan_frac; - u32 div; - if (ah->is_clk_25mhz) div = 75; else @@ -89,34 +86,40 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) chan_frac = (((freq * 4) % div) * 0x20000) / div; channelSel = (channelSel << 17) | chan_frac; } else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) { - u32 chan_frac; - /* - * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0 + * freq_ref = 40 / (refdiva >> amoderefsel); + * where refdiva=1 and amoderefsel=0 * ndiv = ((chan_mhz * 4) / 3) / freq_ref; * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 */ channelSel = (freq * 4) / 120; chan_frac = (((freq * 4) % 120) * 0x20000) / 120; channelSel = (channelSel << 17) | chan_frac; - } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { + } else if (AR_SREV_9340(ah)) { if (ah->is_clk_25mhz) { - u32 chan_frac; - channelSel = (freq * 2) / 75; chan_frac = (((freq * 2) % 75) * 0x20000) / 75; channelSel = (channelSel << 17) | chan_frac; - } else + } else { channelSel = CHANSEL_2G(freq) >> 1; - } else + } + } else if (AR_SREV_9550(ah)) { + if (ah->is_clk_25mhz) + div = 75; + else + div = 120; + + channelSel = (freq * 4) / div; + chan_frac = (((freq * 4) % div) * 0x20000) / div; + channelSel = (channelSel << 17) | chan_frac; + } else { channelSel = CHANSEL_2G(freq); + } /* Set to 2G mode */ bMode = 1; } else { if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && ah->is_clk_25mhz) { - u32 chan_frac; - channelSel = freq / 75; chan_frac = ((freq % 75) * 0x20000) / 75; channelSel = (channelSel << 17) | chan_frac; @@ -1450,6 +1453,67 @@ set_rfmode: return 0; } +static void ar9003_hw_spectral_scan_config(struct ath_hw *ah, + struct ath_spec_scan *param) +{ + u8 count; + + if (!param->enabled) { + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ENABLE); + return; + } + + REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); + + /* on AR93xx and newer, count = 0 will make the the chip send + * spectral samples endlessly. Check if this really was intended, + * and fix otherwise. + */ + count = param->count; + if (param->endless) + count = 0; + else if (param->count == 0) + count = 1; + + if (param->short_repeat) + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + else + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_COUNT, count); + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period); + + return; +} + +static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah) +{ + /* Activate spectral scan */ + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ACTIVE); +} + +static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* Poll for spectral scan complete */ + if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ACTIVE, + 0, AH_WAIT_TIMEOUT)) { + ath_err(common, "spectral scan wait failed\n"); + return; + } +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1483,6 +1547,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv; + ops->spectral_scan_config = ar9003_hw_spectral_scan_config; + ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger; + ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait; ar9003_hw_set_nf_limits(ah); ar9003_hw_set_radar_conf(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 107956298488..e71774196c01 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -1028,7 +1028,7 @@ #define AR_PHY_TPC_5_B2 (AR_SM2_BASE + 0x208) #define AR_PHY_TPC_6_B2 (AR_SM2_BASE + 0x20c) #define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220) -#define AR_PHY_PDADC_TAB_2 (AR_SM2_BASE + 0x240) +#define AR_PHY_TPC_19_B2 (AR_SM2_BASE + 0x240) #define AR_PHY_TX_IQCAL_STATUS_B2 (AR_SM2_BASE + 0x48c) #define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i) (AR_SM2_BASE + 0x450 + ((_i) << 2)) diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index f69d292bdc02..25db9215985a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -1172,6 +1172,106 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, }; +static const u32 ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000}, + {0x0000a394, 0x00000444, 0x00000444, 0x00000404, 0x00000404}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x02000001, 0x02000001}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x05000003, 0x05000003}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0a000005, 0x0a000005}, + {0x0000a510, 0x16000220, 0x16000220, 0x0e000201, 0x0e000201}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000203, 0x11000203}, + {0x0000a518, 0x21002220, 0x21002220, 0x14000401, 0x14000401}, + {0x0000a51c, 0x27002223, 0x27002223, 0x18000403, 0x18000403}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000602, 0x1b000602}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000802, 0x1f000802}, + {0x0000a528, 0x34022225, 0x34022225, 0x21000620, 0x21000620}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x25000820, 0x25000820}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x29000822, 0x29000822}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2d000824, 0x2d000824}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x30000828, 0x30000828}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x3400082a, 0x3400082a}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38000849, 0x38000849}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b000a2c, 0x3b000a2c}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e000e2b, 0x3e000e2b}, + {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42000e2d, 0x42000e2d}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4500124a, 0x4500124a}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4900124c, 0x4900124c}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c00126c, 0x4c00126c}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x4f00128c, 0x4f00128c}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x52001290, 0x52001290}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x02800001, 0x02800001}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x05800003, 0x05800003}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0a800005, 0x0a800005}, + {0x0000a590, 0x16800220, 0x16800220, 0x0e800201, 0x0e800201}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800203, 0x11800203}, + {0x0000a598, 0x21820220, 0x21820220, 0x14800401, 0x14800401}, + {0x0000a59c, 0x27820223, 0x27820223, 0x18800403, 0x18800403}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800602, 0x1b800602}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800802, 0x1f800802}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x21800620, 0x21800620}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x25800820, 0x25800820}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x29800822, 0x29800822}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2d800824, 0x2d800824}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x30800828, 0x30800828}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x3480082a, 0x3480082a}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38800849, 0x38800849}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b800a2c, 0x3b800a2c}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e800e2b, 0x3e800e2b}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42800e2d, 0x42800e2d}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4580124a, 0x4580124a}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4980124c, 0x4980124c}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c80126c, 0x4c80126c}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x4f80128c, 0x4f80128c}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x52801290, 0x52801290}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404501, 0x01404501}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x01404501, 0x01404501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x03c0cf02, 0x03c0cf02}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03c0cf03, 0x03c0cf03}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04011004, 0x04011004}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x05419405, 0x05419405}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000}, + {0x00016044, 0x022492db, 0x022492db, 0x022492db, 0x022492db}, + {0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266}, + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, + {0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000}, + {0x00016444, 0x022492db, 0x022492db, 0x022492db, 0x022492db}, + {0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266}, +}; + static const u32 ar9340_1p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index a3710f3bb90c..712f415b8c08 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -260,6 +260,79 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, }; +static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, + {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, + {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203}, + {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401}, + {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403}, + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405}, + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604}, + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605}, + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04}, + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06}, + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24}, + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21}, + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20}, + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20}, + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a}, + {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a}, + {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a}, + {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, +}; + static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, @@ -450,6 +523,79 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 +static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, + {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, + {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x07000203, 0x07000203}, + {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401}, + {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403}, + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405}, + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x14000406, 0x14000406}, + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1800040a, 0x1800040a}, + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000460, 0x1c000460}, + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x22000463, 0x22000463}, + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x26000465, 0x26000465}, + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2e0006e0, 0x2e0006e0}, + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0}, + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0}, + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, + {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a}, + {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a}, + {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a}, + {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, +}; + static const u32 ar9485_1_1[][2] = { /* Addr allmodes */ {0x0000a580, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index df97f21c52dc..ccc5b6c99add 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -23,16 +23,16 @@ static const u32 ar955x_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, - {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a}, - {0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800}, - {0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a}, - {0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24647c00, 0x24647c00}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x01885f52, 0x01885f52}, + {0x00016104, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001}, {0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, - {0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, + {0x00016504, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001}, {0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, - {0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, + {0x00016904, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001}, {0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, }; @@ -69,15 +69,15 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, - {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, @@ -125,7 +125,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { {0x00016094, 0x00000000}, {0x000160a0, 0x0a108ffe}, {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, + {0x000160a8, 0x423c8100}, {0x000160b4, 0x92480080}, {0x000160c0, 0x006db6d0}, {0x000160c4, 0x6db6db60}, @@ -134,7 +134,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { {0x00016100, 0x11999601}, {0x00016108, 0x00080010}, {0x00016144, 0x02084080}, - {0x00016148, 0x000080c0}, + {0x00016148, 0x00008040}, {0x00016280, 0x01800804}, {0x00016284, 0x00038dc5}, {0x00016288, 0x00000000}, @@ -178,7 +178,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { {0x00016500, 0x11999601}, {0x00016508, 0x00080010}, {0x00016544, 0x02084080}, - {0x00016548, 0x000080c0}, + {0x00016548, 0x00008040}, {0x00016780, 0x00000000}, {0x00016784, 0x00000000}, {0x00016788, 0x00400705}, @@ -218,7 +218,7 @@ static const u32 ar955x_1p0_radio_core[][2] = { {0x00016900, 0x11999601}, {0x00016908, 0x00080010}, {0x00016944, 0x02084080}, - {0x00016948, 0x000080c0}, + {0x00016948, 0x00008040}, {0x00016b80, 0x00000000}, {0x00016b84, 0x00000000}, {0x00016b88, 0x00400705}, @@ -245,9 +245,9 @@ static const u32 ar955x_1p0_radio_core[][2] = { static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = { /* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, - {0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, - {0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, + {0x0000a2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa}, + {0x0000a2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000a2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0}, {0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, {0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da}, {0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000}, @@ -256,63 +256,63 @@ static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = { {0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006}, {0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a}, {0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c}, - {0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e}, - {0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064}, - {0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242}, - {0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229}, - {0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2}, - {0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203}, - {0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803}, - {0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881}, - {0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809}, - {0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814}, - {0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c}, - {0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e}, - {0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812}, - {0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884}, - {0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84}, - {0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69}, - {0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4}, - {0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3}, - {0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5}, - {0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced}, - {0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4}, - {0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4}, - {0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4}, - {0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4}, - {0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, - {0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, + {0x0000a518, 0x1700002b, 0x1700002b, 0x1700002b, 0x1700002b, 0x1600002b, 0x1600002b, 0x1700000e, 0x1700000e}, + {0x0000a51c, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1a00002d, 0x1a00002d, 0x1b000064, 0x1b000064}, + {0x0000a520, 0x20000031, 0x20000031, 0x1f000031, 0x1f000031, 0x1e000031, 0x1e000031, 0x1f000242, 0x1f000242}, + {0x0000a524, 0x24000051, 0x24000051, 0x23000051, 0x23000051, 0x23000051, 0x23000051, 0x23000229, 0x23000229}, + {0x0000a528, 0x27000071, 0x27000071, 0x27000071, 0x27000071, 0x26000071, 0x26000071, 0x270002a2, 0x270002a2}, + {0x0000a52c, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2c001203, 0x2c001203}, + {0x0000a530, 0x3000028c, 0x3000028c, 0x2f00028c, 0x2f00028c, 0x2e00028c, 0x2e00028c, 0x30001803, 0x30001803}, + {0x0000a534, 0x34000290, 0x34000290, 0x33000290, 0x33000290, 0x32000290, 0x32000290, 0x33000881, 0x33000881}, + {0x0000a538, 0x37000292, 0x37000292, 0x36000292, 0x36000292, 0x35000292, 0x35000292, 0x38001809, 0x38001809}, + {0x0000a53c, 0x3b02028d, 0x3b02028d, 0x3a02028d, 0x3a02028d, 0x3902028d, 0x3902028d, 0x3a000814, 0x3a000814}, + {0x0000a540, 0x3f020291, 0x3f020291, 0x3e020291, 0x3e020291, 0x3d020291, 0x3d020291, 0x3f001a0c, 0x3f001a0c}, + {0x0000a544, 0x44020490, 0x44020490, 0x43020490, 0x43020490, 0x42020490, 0x42020490, 0x43001a0e, 0x43001a0e}, + {0x0000a548, 0x48020492, 0x48020492, 0x47020492, 0x47020492, 0x46020492, 0x46020492, 0x46001812, 0x46001812}, + {0x0000a54c, 0x4c020692, 0x4c020692, 0x4b020692, 0x4b020692, 0x4a020692, 0x4a020692, 0x49001884, 0x49001884}, + {0x0000a550, 0x50020892, 0x50020892, 0x4f020892, 0x4f020892, 0x4e020892, 0x4e020892, 0x4d001e84, 0x4d001e84}, + {0x0000a554, 0x53040891, 0x53040891, 0x53040891, 0x53040891, 0x52040891, 0x52040891, 0x50001e69, 0x50001e69}, + {0x0000a558, 0x58040893, 0x58040893, 0x57040893, 0x57040893, 0x56040893, 0x56040893, 0x550006f4, 0x550006f4}, + {0x0000a55c, 0x5c0408b4, 0x5c0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x59000ad3, 0x59000ad3}, + {0x0000a560, 0x610408b6, 0x610408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e000ad5, 0x5e000ad5}, + {0x0000a564, 0x670408f6, 0x670408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x61001ced, 0x61001ced}, + {0x0000a568, 0x6a040cf6, 0x6a040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x660018d4, 0x660018d4}, + {0x0000a56c, 0x6d040d76, 0x6d040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x660018d4, 0x660018d4}, + {0x0000a570, 0x70060db6, 0x70060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x660018d4, 0x660018d4}, + {0x0000a574, 0x730a0df6, 0x730a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x660018d4, 0x660018d4}, + {0x0000a578, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4}, + {0x0000a57c, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000}, - {0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02}, - {0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04}, - {0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000}, - {0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000}, - {0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000}, - {0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000}, - {0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05}, - {0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06}, - {0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07}, - {0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07}, - {0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07}, - {0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07}, - {0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, - {0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, - {0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, + {0x0000a60c, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x03804000, 0x03804000}, + {0x0000a610, 0x04008b01, 0x04008b01, 0x04008b01, 0x04008b01, 0x03c08b01, 0x03c08b01, 0x0300ca02, 0x0300ca02}, + {0x0000a614, 0x05811403, 0x05811403, 0x05411303, 0x05411303, 0x05411303, 0x05411303, 0x00000e04, 0x00000e04}, + {0x0000a618, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000}, + {0x0000a61c, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000}, + {0x0000a620, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000}, + {0x0000a624, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000}, + {0x0000a628, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03804c05, 0x03804c05}, + {0x0000a62c, 0x06815604, 0x06815604, 0x06415504, 0x06415504, 0x06015504, 0x06015504, 0x0701de06, 0x0701de06}, + {0x0000a630, 0x07819a05, 0x07819a05, 0x07419905, 0x07419905, 0x07019805, 0x07019805, 0x07819c07, 0x07819c07}, + {0x0000a634, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07}, + {0x0000a638, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07}, + {0x0000a63c, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07}, + {0x0000b2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa}, + {0x0000b2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000b2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0}, {0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, - {0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, - {0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, - {0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, + {0x0000c2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa}, + {0x0000c2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000c2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0}, {0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, - {0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, + {0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, {0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84}, {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, - {0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, + {0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, - {0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, + {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, }; static const u32 ar955x_1p0_mac_core[][2] = { @@ -846,7 +846,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x0000a44c, 0x00000001}, {0x0000a450, 0x00010000}, {0x0000a458, 0x00000000}, - {0x0000a644, 0x3fad9d74}, + {0x0000a644, 0xbfad9d74}, {0x0000a648, 0x0048060a}, {0x0000a64c, 0x00003c37}, {0x0000a670, 0x03020100}, @@ -1277,7 +1277,7 @@ static const u32 ar955x_1p0_modes_fast_clock[][3] = { {0x0000801c, 0x148ec02b, 0x148ec057}, {0x00008318, 0x000044c0, 0x00008980}, {0x00009e00, 0x0372131c, 0x0372131c}, - {0x0000a230, 0x0000000b, 0x00000016}, + {0x0000a230, 0x0000400b, 0x00004016}, {0x0000a254, 0x00000898, 0x00001130}, }; diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index 6e1915aee712..28fd99203f64 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -685,6 +685,82 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = { #define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 +#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 + +static const u32 ar9580_1p0_type6_tx_gain_table[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + static const u32 ar9580_1p0_soc_preamble[][2] = { /* Addr allmodes */ {0x000040a4, 0x00a0c1c9}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 86e26a19efda..094a9322f092 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -109,14 +109,11 @@ struct ath_descdma { void *dd_desc; dma_addr_t dd_desc_paddr; u32 dd_desc_len; - struct ath_buf *dd_bufptr; }; int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head, const char *name, int nbuf, int ndesc, bool is_tx); -void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head); /***********/ /* RX / TX */ @@ -320,7 +317,6 @@ struct ath_rx { spinlock_t rxbuflock; struct list_head rxbuf; struct ath_descdma rxdma; - struct ath_buf *rx_bufptr; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; struct sk_buff *frag; @@ -345,7 +341,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); -void ath_tx_cleanup(struct ath_softc *sc); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); @@ -675,6 +670,23 @@ struct ath9k_vif_iter_data { int nadhocs; /* number of adhoc vifs */ }; +/* enum spectral_mode: + * + * @SPECTRAL_DISABLED: spectral mode is disabled + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with + * something else. + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples + * is performed manually. + * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels + * during a channel scan. + */ +enum spectral_mode { + SPECTRAL_DISABLED = 0, + SPECTRAL_BACKGROUND, + SPECTRAL_MANUAL, + SPECTRAL_CHANSCAN, +}; + struct ath_softc { struct ieee80211_hw *hw; struct device *dev; @@ -743,6 +755,10 @@ struct ath_softc { u8 ant_tx, ant_rx; struct dfs_pattern_detector *dfs_detector; u32 wow_enabled; + /* relay(fs) channel for spectral scan */ + struct rchan *rfs_chan_spec_scan; + enum spectral_mode spectral_mode; + int scanning; #ifdef CONFIG_PM_SLEEP atomic_t wow_got_bmiss_intr; @@ -751,6 +767,133 @@ struct ath_softc { #endif }; +#define SPECTRAL_SCAN_BITMASK 0x10 +/* Radar info packet format, used for DFS and spectral formats. */ +struct ath_radar_info { + u8 pulse_length_pri; + u8 pulse_length_ext; + u8 pulse_bw_info; +} __packed; + +/* The HT20 spectral data has 4 bytes of additional information at it's end. + * + * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: all bins max_magnitude[9:2] + * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]} + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) + */ +struct ath_ht20_mag_info { + u8 all_bins[3]; + u8 max_exp; +} __packed; + +#define SPECTRAL_HT20_NUM_BINS 56 + +/* WARNING: don't actually use this struct! MAC may vary the amount of + * data by -1/+2. This struct is for reference only. + */ +struct ath_ht20_fft_packet { + u8 data[SPECTRAL_HT20_NUM_BINS]; + struct ath_ht20_mag_info mag_info; + struct ath_radar_info radar_info; +} __packed; + +#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet)) + +/* Dynamic 20/40 mode: + * + * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: lower bins max_magnitude[9:2] + * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]} + * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: upper bins max_magnitude[9:2] + * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]} + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) + */ +struct ath_ht20_40_mag_info { + u8 lower_bins[3]; + u8 upper_bins[3]; + u8 max_exp; +} __packed; + +#define SPECTRAL_HT20_40_NUM_BINS 128 + +/* WARNING: don't actually use this struct! MAC may vary the amount of + * data. This struct is for reference only. + */ +struct ath_ht20_40_fft_packet { + u8 data[SPECTRAL_HT20_40_NUM_BINS]; + struct ath_ht20_40_mag_info mag_info; + struct ath_radar_info radar_info; +} __packed; + + +#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) + +/* grabs the max magnitude from the all/upper/lower bins */ +static inline u16 spectral_max_magnitude(u8 *bins) +{ + return (bins[0] & 0xc0) >> 6 | + (bins[1] & 0xff) << 2 | + (bins[2] & 0x03) << 10; +} + +/* return the max magnitude from the all/upper/lower bins */ +static inline u8 spectral_max_index(u8 *bins) +{ + s8 m = (bins[2] & 0xfc) >> 2; + + /* TODO: this still doesn't always report the right values ... */ + if (m > 32) + m |= 0xe0; + else + m &= ~0xe0; + + return m + 29; +} + +/* return the bitmap weight from the all/upper/lower bins */ +static inline u8 spectral_bitmap_weight(u8 *bins) +{ + return bins[0] & 0x3f; +} + +/* FFT sample format given to userspace via debugfs. + * + * Please keep the type/length at the front position and change + * other fields after adding another sample type + * + * TODO: this might need rework when switching to nl80211-based + * interface. + */ +enum ath_fft_sample_type { + ATH_FFT_SAMPLE_HT20 = 0, +}; + +struct fft_sample_tlv { + u8 type; /* see ath_fft_sample */ + u16 length; + /* type dependent data follows */ +} __packed; + +struct fft_sample_ht20 { + struct fft_sample_tlv tlv; + + u8 __alignment; + + u16 freq; + s8 rssi; + s8 noise; + + u16 max_magnitude; + u8 max_index; + u8 bitmap_weight; + + u64 tsf; + + u16 data[SPECTRAL_HT20_NUM_BINS]; +} __packed; + void ath9k_tasklet(unsigned long data); int ath_cabq_update(struct ath_softc *); @@ -773,6 +916,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); void ath9k_reload_chainmask_settings(struct ath_softc *sc); bool ath9k_uses_beacons(int type); +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); +int ath9k_spectral_scan_config(struct ieee80211_hw *hw, + enum spectral_mode spectral_mode); + #ifdef CONFIG_ATH9K_PCI int ath_pci_init(void); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 13ff9edc2401..75b504ba3b3f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/export.h> +#include <linux/relay.h> #include <asm/unaligned.h> #include "ath9k.h" @@ -966,6 +967,112 @@ static const struct file_operations fops_recv = { .llseek = default_llseek, }; +static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char *mode = ""; + unsigned int len; + + switch (sc->spectral_mode) { + case SPECTRAL_DISABLED: + mode = "disable"; + break; + case SPECTRAL_BACKGROUND: + mode = "background"; + break; + case SPECTRAL_CHANSCAN: + mode = "chanscan"; + break; + case SPECTRAL_MANUAL: + mode = "manual"; + break; + } + len = strlen(mode); + return simple_read_from_buffer(user_buf, count, ppos, mode, len); +} + +static ssize_t write_file_spec_scan_ctl(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (strncmp("trigger", buf, 7) == 0) { + ath9k_spectral_scan_trigger(sc->hw); + } else if (strncmp("background", buf, 9) == 0) { + ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); + ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); + } else if (strncmp("chanscan", buf, 8) == 0) { + ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); + ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); + } else if (strncmp("manual", buf, 6) == 0) { + ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); + ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); + } else if (strncmp("disable", buf, 7) == 0) { + ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); + ath_dbg(common, CONFIG, "spectral scan: disabled\n"); + } else { + return -EINVAL; + } + + return count; +} + +static const struct file_operations fops_spec_scan_ctl = { + .read = read_file_spec_scan_ctl, + .write = write_file_spec_scan_ctl, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static struct dentry *create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *buf_file; + + buf_file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + *is_global = 1; + return buf_file; +} + +static int remove_buf_file_handler(struct dentry *dentry) +{ + debugfs_remove(dentry); + + return 0; +} + +void ath_debug_send_fft_sample(struct ath_softc *sc, + struct fft_sample_tlv *fft_sample_tlv) +{ + if (!sc->rfs_chan_spec_scan) + return; + + relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, + fft_sample_tlv->length + sizeof(*fft_sample_tlv)); +} + +static struct rchan_callbacks rfs_spec_scan_cb = { + .create_buf_file = create_buf_file_handler, + .remove_buf_file = remove_buf_file_handler, +}; + + static ssize_t read_file_regidx(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1780,6 +1887,14 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_base_eeprom); debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_modal_eeprom); + sc->rfs_chan_spec_scan = relay_open("spectral_scan", + sc->debug.debugfs_phy, + 262144, 4, &rfs_spec_scan_cb, + NULL); + debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, + &fops_spec_scan_ctl); + #ifdef CONFIG_ATH9K_MAC_DEBUG debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_samps); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 375c3b46411e..b19bed7f74c2 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -23,6 +23,7 @@ struct ath_txq; struct ath_buf; +struct fft_sample_tlv; #ifdef CONFIG_ATH9K_DEBUGFS #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ @@ -323,6 +324,10 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); + +void ath_debug_send_fft_sample(struct ath_softc *sc, + struct fft_sample_tlv *fft_sample); + #else #define RX_STAT_INC(c) /* NOP */ diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 0f2b97f6b739..14b701140b49 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -101,22 +101,6 @@ static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah, ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan); } -static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) -{ - if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks) - return 0; - - return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah); -} - -static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) -{ - if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks) - return; - - ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah); -} - static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7cb787065913..caf0626eeaa5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -554,14 +554,6 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); - ecode = ath9k_hw_rf_alloc_ext_banks(ah); - if (ecode) { - ath_err(ath9k_hw_common(ah), - "Failed allocating banks for external radio\n"); - ath9k_hw_rf_free_ext_banks(ah); - return ecode; - } - if (ah->config.enable_ani) { ath9k_hw_ani_setup(ah); ath9k_hw_ani_init(ah); @@ -570,12 +562,13 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return 0; } -static void ath9k_hw_attach_ops(struct ath_hw *ah) +static int ath9k_hw_attach_ops(struct ath_hw *ah) { - if (AR_SREV_9300_20_OR_LATER(ah)) - ar9003_hw_attach_ops(ah); - else - ar9002_hw_attach_ops(ah); + if (!AR_SREV_9300_20_OR_LATER(ah)) + return ar9002_hw_attach_ops(ah); + + ar9003_hw_attach_ops(ah); + return 0; } /* Called for all hardware families */ @@ -611,7 +604,9 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_defaults(ah); ath9k_hw_init_config(ah); - ath9k_hw_attach_ops(ah); + r = ath9k_hw_attach_ops(ah); + if (r) + return r; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { ath_err(common, "Couldn't wakeup chip\n"); @@ -1153,12 +1148,9 @@ void ath9k_hw_deinit(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); if (common->state < ATH_HW_INITIALIZED) - goto free_hw; + return; ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - -free_hw: - ath9k_hw_rf_free_ext_banks(ah); } EXPORT_SYMBOL(ath9k_hw_deinit); @@ -2576,12 +2568,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) rx_chainmask >>= 1; } - if (AR_SREV_9300_20_OR_LATER(ah)) { - ah->enabled_cals |= TX_IQ_CAL; - if (AR_SREV_9485_OR_LATER(ah)) - ah->enabled_cals |= TX_IQ_ON_AGC_CAL; - } - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE)) pCap->hw_caps |= ATH9K_HW_CAP_MCI; @@ -2590,7 +2576,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_RTT; } - if (AR_SREV_9280_20_OR_LATER(ah)) { pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | ATH9K_HW_WOW_PATTERN_MATCH_EXACT; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7f1a8e91c908..d32ebf7a2414 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -397,6 +397,7 @@ enum ath9k_int { #define MAX_RTT_TABLE_ENTRY 6 #define MAX_IQCAL_MEASUREMENT 8 #define MAX_CL_TAB_ENTRY 16 +#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) struct ath9k_hw_cal_data { u16 channel; @@ -604,8 +605,6 @@ struct ath_hw_radar_conf { * * @rf_set_freq: change frequency * @spur_mitigate_freq: spur mitigation - * @rf_alloc_ext_banks: - * @rf_free_ext_banks: * @set_rf_regs: * @compute_pll_control: compute the PLL control value to use for * AR_RTC_PLL_CONTROL for a given channel @@ -630,8 +629,6 @@ struct ath_hw_private_ops { struct ath9k_channel *chan); void (*spur_mitigate_freq)(struct ath_hw *ah, struct ath9k_channel *chan); - int (*rf_alloc_ext_banks)(struct ath_hw *ah); - void (*rf_free_ext_banks)(struct ath_hw *ah); bool (*set_rf_regs)(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex); @@ -661,6 +658,37 @@ struct ath_hw_private_ops { }; /** + * struct ath_spec_scan - parameters for Atheros spectral scan + * + * @enabled: enable/disable spectral scan + * @short_repeat: controls whether the chip is in spectral scan mode + * for 4 usec (enabled) or 204 usec (disabled) + * @count: number of scan results requested. There are special meanings + * in some chip revisions: + * AR92xx: highest bit set (>=128) for endless mode + * (spectral scan won't stopped until explicitly disabled) + * AR9300 and newer: 0 for endless mode + * @endless: true if endless mode is intended. Otherwise, count value is + * corrected to the next possible value. + * @period: time duration between successive spectral scan entry points + * (period*256*Tclk). Tclk = ath_common->clockrate + * @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS + * + * Note: Tclk = 40MHz or 44MHz depending upon operating mode. + * Typically it's 44MHz in 2/5GHz on later chips, but there's + * a "fast clock" check for this in 5GHz. + * + */ +struct ath_spec_scan { + bool enabled; + bool short_repeat; + bool endless; + u8 count; + u8 period; + u8 fft_period; +}; + +/** * struct ath_hw_ops - callbacks used by hardware code and driver code * * This structure contains callbacks designed to to be used internally by @@ -668,6 +696,10 @@ struct ath_hw_private_ops { * * @config_pci_powersave: * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC + * + * @spectral_scan_config: set parameters for spectral scan and enable/disable it + * @spectral_scan_trigger: trigger a spectral scan run + * @spectral_scan_wait: wait for a spectral scan run to finish */ struct ath_hw_ops { void (*config_pci_powersave)(struct ath_hw *ah, @@ -688,6 +720,10 @@ struct ath_hw_ops { void (*antdiv_comb_conf_set)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable); + void (*spectral_scan_config)(struct ath_hw *ah, + struct ath_spec_scan *param); + void (*spectral_scan_trigger)(struct ath_hw *ah); + void (*spectral_scan_wait)(struct ath_hw *ah); }; struct ath_nf_limits { @@ -710,6 +746,7 @@ enum ath_cal_list { struct ath_hw { struct ath_ops reg_ops; + struct device *dev; struct ieee80211_hw *hw; struct ath_common common; struct ath9k_hw_version hw_version; @@ -771,7 +808,6 @@ struct ath_hw { struct ath9k_cal_list iq_caldata; struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcdc_caldata; - struct ath9k_cal_list tempCompCalData; struct ath9k_cal_list *cal_list; struct ath9k_cal_list *cal_list_last; struct ath9k_cal_list *cal_list_curr; @@ -1068,14 +1104,14 @@ bool ar9003_paprd_is_done(struct ath_hw *ah); bool ar9003_is_paprd_enabled(struct ath_hw *ah); /* Hardware family op attach helpers */ -void ar5008_hw_attach_phy_ops(struct ath_hw *ah); +int ar5008_hw_attach_phy_ops(struct ath_hw *ah); void ar9002_hw_attach_phy_ops(struct ath_hw *ah); void ar9003_hw_attach_phy_ops(struct ath_hw *ah); void ar9002_hw_attach_calib_ops(struct ath_hw *ah); void ar9003_hw_attach_calib_ops(struct ath_hw *ah); -void ar9002_hw_attach_ops(struct ath_hw *ah); +int ar9002_hw_attach_ops(struct ath_hw *ah); void ar9003_hw_attach_ops(struct ath_hw *ah); void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 315d6593e18e..4b1abc7da98c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/ath9k_platform.h> #include <linux/module.h> +#include <linux/relay.h> #include "ath9k.h" @@ -334,7 +335,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct ath_common *common = ath9k_hw_common(sc->sc_ah); u8 *ds; struct ath_buf *bf; - int i, bsize, error, desc_len; + int i, bsize, desc_len; ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", name, nbuf, ndesc); @@ -350,8 +351,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, if ((desc_len % 4) != 0) { ath_err(common, "ath_desc not DWORD aligned\n"); BUG_ON((desc_len % 4) != 0); - error = -ENOMEM; - goto fail; + return -ENOMEM; } dd->dd_desc_len = desc_len * nbuf * ndesc; @@ -375,12 +375,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } /* allocate descriptors */ - dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, - &dd->dd_desc_paddr, GFP_KERNEL); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } + dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); + if (!dd->dd_desc) + return -ENOMEM; + ds = (u8 *) dd->dd_desc; ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", name, ds, (u32) dd->dd_desc_len, @@ -388,12 +387,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, /* allocate buffers */ bsize = sizeof(struct ath_buf) * nbuf; - bf = kzalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - dd->dd_bufptr = bf; + bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); + if (!bf) + return -ENOMEM; for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { bf->bf_desc = ds; @@ -419,12 +415,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, list_add_tail(&bf->list, head); } return 0; -fail2: - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; } static int ath9k_init_queues(struct ath_softc *sc) @@ -454,11 +444,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) ATH9K_NUM_CHANNELS); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - channels = kmemdup(ath9k_2ghz_chantable, + channels = devm_kzalloc(sc->dev, sizeof(ath9k_2ghz_chantable), GFP_KERNEL); if (!channels) return -ENOMEM; + memcpy(channels, ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable)); sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; sc->sbands[IEEE80211_BAND_2GHZ].n_channels = @@ -469,14 +461,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) } if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - channels = kmemdup(ath9k_5ghz_chantable, + channels = devm_kzalloc(sc->dev, sizeof(ath9k_5ghz_chantable), GFP_KERNEL); - if (!channels) { - if (sc->sbands[IEEE80211_BAND_2GHZ].channels) - kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); + if (!channels) return -ENOMEM; - } + memcpy(channels, ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable)); sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; sc->sbands[IEEE80211_BAND_5GHZ].n_channels = @@ -562,10 +553,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, int ret = 0, i; int csz = 0; - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL); if (!ah) return -ENOMEM; + ah->dev = sc->dev; ah->hw = sc->hw; ah->hw_version.devid = devid; ah->reg_ops.read = ath9k_ioread32; @@ -633,7 +625,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (pdata && pdata->eeprom_name) { ret = ath9k_eeprom_request(sc, pdata->eeprom_name); if (ret) - goto err_eeprom; + return ret; } /* Initializes the hardware for all supported chipsets */ @@ -673,10 +665,6 @@ err_queues: ath9k_hw_deinit(ah); err_hw: ath9k_eeprom_release(sc); -err_eeprom: - kfree(ah); - sc->sc_ah = NULL; - return ret; } @@ -841,8 +829,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, /* Bring up device */ error = ath9k_init_softc(devid, sc, bus_ops); - if (error != 0) - goto error_init; + if (error) + return error; ah = sc->sc_ah; common = ath9k_hw_common(ah); @@ -852,19 +840,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, error = ath_regd_init(&common->regulatory, sc->hw->wiphy, ath9k_reg_notifier); if (error) - goto error_regd; + goto deinit; reg = &common->regulatory; /* Setup TX DMA */ error = ath_tx_init(sc, ATH_TXBUF); if (error != 0) - goto error_tx; + goto deinit; /* Setup RX DMA */ error = ath_rx_init(sc, ATH_RXBUF); if (error != 0) - goto error_rx; + goto deinit; ath9k_init_txpower_limits(sc); @@ -878,19 +866,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) - goto error_register; + goto rx_cleanup; error = ath9k_init_debug(ah); if (error) { ath_err(common, "Unable to create debugfs files\n"); - goto error_world; + goto unregister; } /* Handle world regulatory */ if (!ath_is_world_regd(reg)) { error = regulatory_hint(hw->wiphy, reg->alpha2); if (error) - goto error_world; + goto unregister; } ath_init_leds(sc); @@ -898,17 +886,12 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, return 0; -error_world: +unregister: ieee80211_unregister_hw(hw); -error_register: +rx_cleanup: ath_rx_cleanup(sc); -error_rx: - ath_tx_cleanup(sc); -error_tx: - /* Nothing */ -error_regd: +deinit: ath9k_deinit_softc(sc); -error_init: return error; } @@ -920,12 +903,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc) { int i = 0; - if (sc->sbands[IEEE80211_BAND_2GHZ].channels) - kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); - - if (sc->sbands[IEEE80211_BAND_5GHZ].channels) - kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); - ath9k_deinit_btcoex(sc); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) @@ -937,8 +914,11 @@ static void ath9k_deinit_softc(struct ath_softc *sc) sc->dfs_detector->exit(sc->dfs_detector); ath9k_eeprom_release(sc); - kfree(sc->sc_ah); - sc->sc_ah = NULL; + + if (sc->rfs_chan_spec_scan) { + relay_close(sc->rfs_chan_spec_scan); + sc->rfs_chan_spec_scan = NULL; + } } void ath9k_deinit_device(struct ath_softc *sc) @@ -954,22 +934,9 @@ void ath9k_deinit_device(struct ath_softc *sc) ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); - ath_tx_cleanup(sc); ath9k_deinit_softc(sc); } -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - /************************/ /* Module Hooks */ /************************/ diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 4a745e68dd94..1ff817061ebc 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -226,7 +226,8 @@ enum ath9k_phyerr { ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35, ATH9K_PHYERR_HT_RATE_ILLEGAL = 36, - ATH9K_PHYERR_MAX = 37, + ATH9K_PHYERR_SPECTRAL = 38, + ATH9K_PHYERR_MAX = 39, }; struct ath_desc { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e1fa70596e61..32417fd4bf5a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1075,6 +1075,86 @@ static void ath9k_disable_ps(struct ath_softc *sc) ath_dbg(common, PS, "PowerSave disabled\n"); } +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 rxfilter; + + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); + return; + } + + ath9k_ps_wakeup(sc); + rxfilter = ath9k_hw_getrxfilter(ah); + ath9k_hw_setrxfilter(ah, rxfilter | + ATH9K_RX_FILTER_PHYRADAR | + ATH9K_RX_FILTER_PHYERR); + + /* TODO: usually this should not be neccesary, but for some reason + * (or in some mode?) the trigger must be called after the + * configuration, otherwise the register will have its values reset + * (on my ar9220 to value 0x01002310) + */ + ath9k_spectral_scan_config(hw, sc->spectral_mode); + ath9k_hw_ops(ah)->spectral_scan_trigger(ah); + ath9k_ps_restore(sc); +} + +int ath9k_spectral_scan_config(struct ieee80211_hw *hw, + enum spectral_mode spectral_mode) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_spec_scan param; + + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); + return -1; + } + + /* NOTE: this will generate a few samples ... + * + * TODO: review default parameters, and/or define an interface to set + * them. + */ + param.enabled = 1; + param.short_repeat = true; + param.count = 8; + param.endless = false; + param.period = 0xFF; + param.fft_period = 0xF; + + switch (spectral_mode) { + case SPECTRAL_DISABLED: + param.enabled = 0; + break; + case SPECTRAL_BACKGROUND: + /* send endless samples. + * TODO: is this really useful for "background"? + */ + param.endless = 1; + break; + case SPECTRAL_CHANSCAN: + break; + case SPECTRAL_MANUAL: + break; + default: + return -1; + } + + ath9k_ps_wakeup(sc); + ath9k_hw_ops(ah)->spectral_scan_config(ah, ¶m); + ath9k_ps_restore(sc); + + sc->spectral_mode = spectral_mode; + + return 0; +} + static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; @@ -1188,6 +1268,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) */ if (old_pos >= 0) ath_update_survey_nf(sc, old_pos); + + /* perform spectral scan if requested. */ + if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN) + ath9k_spectral_scan_trigger(hw); + } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -2240,6 +2325,19 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) } #endif +static void ath9k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + sc->scanning = 1; +} + +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + sc->scanning = 0; +} struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, @@ -2286,4 +2384,6 @@ struct ieee80211_ops ath9k_ops = { .sta_add_debugfs = ath9k_sta_add_debugfs, .sta_remove_debugfs = ath9k_sta_remove_debugfs, #endif + .sw_scan_start = ath9k_sw_scan_start, + .sw_scan_complete = ath9k_sw_scan_complete, }; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 5c02702f21e7..d2074334ec9b 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -438,7 +438,7 @@ int ath_mci_setup(struct ath_softc *sc) struct ath_mci_buf *buf = &mci->sched_buf; int ret; - buf->bf_addr = dma_alloc_coherent(sc->dev, + buf->bf_addr = dmam_alloc_coherent(sc->dev, ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, &buf->bf_paddr, GFP_KERNEL); @@ -477,11 +477,6 @@ void ath_mci_cleanup(struct ath_softc *sc) struct ath_mci_coex *mci = &sc->mci_coex; struct ath_mci_buf *buf = &mci->sched_buf; - if (buf->bf_addr) - dma_free_coherent(sc->dev, - ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, - buf->bf_addr, buf->bf_paddr); - ar9003_mci_cleanup(ah); ath_dbg(common, MCI, "MCI De-Initialized\n"); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 7ae73fbd9136..0e0d39583837 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -147,7 +147,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - void __iomem *mem; struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; @@ -155,19 +154,19 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) int ret = 0; char hw_name[64]; - if (pci_enable_device(pdev)) + if (pcim_enable_device(pdev)) return -EIO; ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { pr_err("32-bit DMA not available\n"); - goto err_dma; + return ret; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { pr_err("32-bit DMA consistent DMA enable failed\n"); - goto err_dma; + return ret; } /* @@ -203,25 +202,16 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - ret = pci_request_region(pdev, 0, "ath9k"); + ret = pcim_iomap_regions(pdev, BIT(0), "ath9k"); if (ret) { dev_err(&pdev->dev, "PCI memory region reserve error\n"); - ret = -ENODEV; - goto err_region; - } - - mem = pci_iomap(pdev, 0, 0); - if (!mem) { - pr_err("PCI memory map error\n") ; - ret = -EIO; - goto err_iomap; + return -ENODEV; } hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (!hw) { dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); - ret = -ENOMEM; - goto err_alloc_hw; + return -ENOMEM; } SET_IEEE80211_DEV(hw, &pdev->dev); @@ -230,7 +220,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc = hw->priv; sc->hw = hw; sc->dev = &pdev->dev; - sc->mem = mem; + sc->mem = pcim_iomap_table(pdev)[0]; /* Will be cleared in ath9k_start() */ set_bit(SC_OP_INVALID, &sc->sc_flags); @@ -251,7 +241,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", - hw_name, (unsigned long)mem, pdev->irq); + hw_name, (unsigned long)sc->mem, pdev->irq); return 0; @@ -259,14 +249,6 @@ err_init: free_irq(sc->irq, sc); err_irq: ieee80211_free_hw(hw); -err_alloc_hw: - pci_iounmap(pdev, mem); -err_iomap: - pci_release_region(pdev, 0); -err_region: - /* Nothing */ -err_dma: - pci_disable_device(pdev); return ret; } @@ -274,17 +256,12 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; - void __iomem *mem = sc->mem; if (!is_ath9k_unloaded) sc->sc_ah->ah_flags |= AH_UNPLUGGED; ath9k_deinit_device(sc); free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); - - pci_iounmap(pdev, mem); - pci_disable_device(pdev); - pci_release_region(pdev, 0); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index d4df98a938bf..45f2d475ac1a 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -15,6 +15,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/relay.h> #include "ath9k.h" #include "ar9003_mac.h" @@ -180,11 +181,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) bf->bf_mpdu = NULL; } } - - INIT_LIST_HEAD(&sc->rx.rxbuf); - - kfree(sc->rx.rx_bufptr); - sc->rx.rx_bufptr = NULL; } static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) @@ -211,12 +207,11 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) ah->caps.rx_hp_qdepth); size = sizeof(struct ath_buf) * nbufs; - bf = kzalloc(size, GFP_KERNEL); + bf = devm_kzalloc(sc->dev, size, GFP_KERNEL); if (!bf) return -ENOMEM; INIT_LIST_HEAD(&sc->rx.rxbuf); - sc->rx.rx_bufptr = bf; for (i = 0; i < nbufs; i++, bf++) { skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); @@ -363,9 +358,6 @@ void ath_rx_cleanup(struct ath_softc *sc) bf->bf_mpdu = NULL; } } - - if (sc->rx.rxdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); } } @@ -1034,6 +1026,108 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common, rxs->flag &= ~RX_FLAG_DECRYPTED; } +static s8 fix_rssi_inv_only(u8 rssi_val) +{ + if (rssi_val == 128) + rssi_val = 0; + return (s8) rssi_val; +} + + +static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf) +{ +#ifdef CONFIG_ATH_DEBUG + struct ath_hw *ah = sc->sc_ah; + u8 bins[SPECTRAL_HT20_NUM_BINS]; + u8 *vdata = (u8 *)hdr; + struct fft_sample_ht20 fft_sample; + struct ath_radar_info *radar_info; + struct ath_ht20_mag_info *mag_info; + int len = rs->rs_datalen; + int i, dc_pos; + + /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer + * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT + * yet, but this is supposed to be possible as well. + */ + if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && + rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && + rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) + return; + + /* Variation in the data length is possible and will be fixed later. + * Note that we only support HT20 for now. + * + * TODO: add HT20_40 support as well. + */ + if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || + (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) + return; + + /* check if spectral scan bit is set. This does not have to be checked + * if received through a SPECTRAL phy error, but shouldn't hurt. + */ + radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) + return; + + fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; + fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv); + + fft_sample.freq = ah->curchan->chan->center_freq; + fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); + fft_sample.noise = ah->noise; + + switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { + case 0: + /* length correct, nothing to do. */ + memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); + break; + case -1: + /* first byte missing, duplicate it. */ + memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); + bins[0] = vdata[0]; + break; + case 2: + /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ + memcpy(bins, vdata, 30); + bins[30] = vdata[31]; + memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); + break; + case 1: + /* MAC added 2 extra bytes AND first byte is missing. */ + bins[0] = vdata[0]; + memcpy(&bins[0], vdata, 30); + bins[31] = vdata[31]; + memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); + break; + default: + return; + } + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + dc_pos = SPECTRAL_HT20_NUM_BINS / 2; + bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; + + /* mag data is at the end of the frame, in front of radar_info */ + mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; + + /* Apply exponent and grab further auxiliary information. */ + for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) + fft_sample.data[i] = bins[i] << mag_info->max_exp; + + fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins); + fft_sample.max_index = spectral_max_index(mag_info->all_bins); + fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); + fft_sample.tsf = tsf; + + ath_debug_send_fft_sample(sc, &fft_sample.tlv); +#endif +} + int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; @@ -1131,6 +1225,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; + if ((rs.rs_status & ATH9K_RXERR_PHY)) + ath_process_fft(sc, hdr, &rs, rxs->mactime); + retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, rxs, &decrypt_error); if (retval) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index ad3c82c09177..5929850649f0 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -789,6 +789,7 @@ #define AR_SREV_REVISION_9271_11 1 #define AR_SREV_VERSION_9300 0x1c0 #define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */ +#define AR_SREV_REVISION_9300_22 3 #define AR_SREV_VERSION_9330 0x200 #define AR_SREV_REVISION_9330_10 0 #define AR_SREV_REVISION_9330_11 1 @@ -869,6 +870,9 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) #define AR_SREV_9300_20_OR_LATER(_ah) \ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300) +#define AR_SREV_9300_22(_ah) \ + (AR_SREV_9300(ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22)) #define AR_SREV_9330(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330)) @@ -884,9 +888,6 @@ #define AR_SREV_9485(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) -#define AR_SREV_9485_10(_ah) \ - (AR_SREV_9485(_ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10)) #define AR_SREV_9485_11(_ah) \ (AR_SREV_9485(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 90e48a0fafe5..ca4a0341294f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2361,8 +2361,8 @@ static int ath_txstatus_setup(struct ath_softc *sc, int size) u8 txs_len = sc->sc_ah->caps.txs_len; dd->dd_desc_len = size * txs_len; - dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, - &dd->dd_desc_paddr, GFP_KERNEL); + dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); if (!dd->dd_desc) return -ENOMEM; @@ -2382,14 +2382,6 @@ static int ath_tx_edma_init(struct ath_softc *sc) return err; } -static void ath_tx_edma_cleanup(struct ath_softc *sc) -{ - struct ath_descdma *dd = &sc->txsdma; - - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); -} - int ath_tx_init(struct ath_softc *sc, int nbufs) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -2402,7 +2394,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) if (error != 0) { ath_err(common, "Failed to allocate tx descriptors: %d\n", error); - goto err; + return error; } error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, @@ -2410,36 +2402,17 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) if (error != 0) { ath_err(common, "Failed to allocate beacon descriptors: %d\n", error); - goto err; + return error; } INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) error = ath_tx_edma_init(sc); - if (error) - goto err; - } - -err: - if (error != 0) - ath_tx_cleanup(sc); return error; } -void ath_tx_cleanup(struct ath_softc *sc) -{ - if (sc->beacon.bdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); - - if (sc->tx.txdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) - ath_tx_edma_cleanup(sc); -} - void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 2df17f1e49ef..25599741cd8a 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -85,20 +85,14 @@ enum carl9170_device_state { CARL9170_STARTED, }; -#define CARL9170_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define CARL9170_TX_USER_RATE_TRIES 3 -#define WME_AC_BE 2 -#define WME_AC_BK 3 -#define WME_AC_VI 1 -#define WME_AC_VO 0 - #define TID_TO_WME_AC(_tid) \ - ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ - (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ - (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ - WME_AC_VO) + ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \ + IEEE80211_AC_VO) #define SEQ_DIFF(_start, _seq) \ (((_start) - (_seq)) & 0x0fff) @@ -290,6 +284,7 @@ struct ar9170 { unsigned int rx_size; unsigned int tx_seq_table; bool ba_filter; + bool disable_offload_fw; } fw; /* interface configuration combinations */ @@ -493,8 +488,8 @@ struct carl9170_sta_info { bool sleeping; atomic_t pending_frames; unsigned int ampdu_max_len; - struct carl9170_sta_tid __rcu *agg[CARL9170_NUM_TID]; - struct carl9170_ba_stats stats[CARL9170_NUM_TID]; + struct carl9170_sta_tid __rcu *agg[IEEE80211_NUM_TIDS]; + struct carl9170_ba_stats stats[IEEE80211_NUM_TIDS]; }; struct carl9170_tx_info { diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index aaebecd19e59..6e76179f1a79 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -215,6 +215,24 @@ static int carl9170_fw_tx_sequence(struct ar9170 *ar) return 0; } +static void carl9170_fw_set_if_combinations(struct ar9170 *ar, + u16 if_comb_types) +{ + if (ar->fw.vif_num < 2) + return; + + ar->if_comb_limits[0].max = ar->fw.vif_num; + ar->if_comb_limits[0].types = if_comb_types; + + ar->if_combs[0].num_different_channels = 1; + ar->if_combs[0].max_interfaces = ar->fw.vif_num; + ar->if_combs[0].limits = ar->if_comb_limits; + ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits); + + ar->hw->wiphy->iface_combinations = ar->if_combs; + ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs); +} + static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) { const struct carl9170fw_otus_desc *otus_desc; @@ -264,7 +282,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) if (!SUPP(CARL9170FW_COMMAND_CAM)) { dev_info(&ar->udev->dev, "crypto offloading is disabled " "by firmware.\n"); - ar->disable_offload = true; + ar->fw.disable_offload_fw = true; } if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM)) @@ -341,20 +359,15 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) } } - ar->if_comb_limits[0].max = ar->fw.vif_num; - ar->if_comb_limits[0].types = if_comb_types; - - ar->if_combs[0].num_different_channels = 1; - ar->if_combs[0].max_interfaces = ar->fw.vif_num; - ar->if_combs[0].limits = ar->if_comb_limits; - ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits); - - ar->hw->wiphy->iface_combinations = ar->if_combs; - ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs); + carl9170_fw_set_if_combinations(ar, if_comb_types); ar->hw->wiphy->interface_modes |= if_comb_types; - ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* As IBSS Encryption is software-based, IBSS RSN is supported. */ + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS; #undef SUPPORTED return carl9170_fw_tx_sequence(ar); diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index 9443c802b25b..9111d4ffc1b3 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -156,6 +156,14 @@ struct carl9170_psm { } __packed; #define CARL9170_PSM_SIZE 4 +/* + * Note: If a bit in rx_filter is set, then it + * means that the particular frames which matches + * the condition are FILTERED/REMOVED/DISCARDED! + * (This is can be a bit confusing, especially + * because someone people think it's the exact + * opposite way, so watch out!) + */ struct carl9170_rx_filter_cmd { __le32 rx_filter; } __packed; diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index fa834c1460f0..0db874abde50 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -384,7 +384,7 @@ #define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xd84) #define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xd88) -#define AR9170_MAC_BCN_LENGTH_MAX 256 +#define AR9170_MAC_BCN_LENGTH_MAX (512 - 32) #define AR9170_MAC_REG_BCN_STATUS (AR9170_MAC_REG_BASE + 0xd8c) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index aaa2699e5a8c..ef82751722e0 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -358,8 +358,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw) ar->ps.last_action = jiffies; ar->ps.last_slept = jiffies; ar->erp_mode = CARL9170_ERP_AUTO; - ar->rx_software_decryption = false; - ar->disable_offload = false; + + /* Set "disable hw crypto offload" whenever the module parameter + * nohwcrypt is true or if the firmware does not support it. + */ + ar->disable_offload = modparam_nohwcrypt | + ar->fw.disable_offload_fw; + ar->rx_software_decryption = ar->disable_offload; for (i = 0; i < ar->hw->queues; i++) { ar->queue_stop_timeout[i] = jiffies; @@ -565,12 +570,28 @@ static int carl9170_init_interface(struct ar9170 *ar, memcpy(common->macaddr, vif->addr, ETH_ALEN); - if (modparam_nohwcrypt || - ((vif->type != NL80211_IFTYPE_STATION) && - (vif->type != NL80211_IFTYPE_AP))) { - ar->rx_software_decryption = true; - ar->disable_offload = true; - } + /* We have to fall back to software crypto, whenever + * the user choose to participates in an IBSS. HW + * offload for IBSS RSN is not supported by this driver. + * + * NOTE: If the previous main interface has already + * disabled hw crypto offload, we have to keep this + * previous disable_offload setting as it was. + * Altough ideally, we should notify mac80211 and tell + * it to forget about any HW crypto offload for now. + */ + ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) && + (vif->type != NL80211_IFTYPE_AP)); + + /* While the driver supports HW offload in a single + * P2P client configuration, it doesn't support HW + * offload in the favourit, concurrent P2P GO+CLIENT + * configuration. Hence, HW offload will always be + * disabled for P2P. + */ + ar->disable_offload |= vif->p2p; + + ar->rx_software_decryption = ar->disable_offload; err = carl9170_set_operating_mode(ar); return err; @@ -580,7 +601,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv; - struct ieee80211_vif *main_vif; + struct ieee80211_vif *main_vif, *old_main = NULL; struct ar9170 *ar = hw->priv; int vif_id = -1, err = 0; @@ -602,6 +623,15 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, goto init; } + /* Because the AR9170 HW's MAC doesn't provide full support for + * multiple, independent interfaces [of different operation modes]. + * We have to select ONE main interface [main mode of HW], but we + * can have multiple slaves [AKA: entry in the ACK-table]. + * + * The first (from HEAD/TOP) interface in the ar->vif_list is + * always the main intf. All following intfs in this list + * are considered to be slave intfs. + */ main_vif = carl9170_get_main_vif(ar); if (main_vif) { @@ -610,6 +640,18 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_STATION) break; + /* P2P GO [master] use-case + * Because the P2P GO station is selected dynamically + * by all participating peers of a WIFI Direct network, + * the driver has be able to change the main interface + * operating mode on the fly. + */ + if (main_vif->p2p && vif->p2p && + vif->type == NL80211_IFTYPE_AP) { + old_main = main_vif; + break; + } + err = -EBUSY; rcu_read_unlock(); @@ -648,14 +690,41 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, vif_priv->id = vif_id; vif_priv->enable_beacon = false; ar->vifs++; - list_add_tail_rcu(&vif_priv->list, &ar->vif_list); + if (old_main) { + /* We end up in here, if the main interface is being replaced. + * Put the new main interface at the HEAD of the list and the + * previous inteface will automatically become second in line. + */ + list_add_rcu(&vif_priv->list, &ar->vif_list); + } else { + /* Add new inteface. If the list is empty, it will become the + * main inteface, otherwise it will be slave. + */ + list_add_tail_rcu(&vif_priv->list, &ar->vif_list); + } rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif); init: - if (carl9170_get_main_vif(ar) == vif) { + main_vif = carl9170_get_main_vif(ar); + + if (main_vif == vif) { rcu_assign_pointer(ar->beacon_iter, vif_priv); rcu_read_unlock(); + if (old_main) { + struct carl9170_vif_info *old_main_priv = + (void *) old_main->drv_priv; + /* downgrade old main intf to slave intf. + * NOTE: We are no longer under rcu_read_lock. + * But we are still holding ar->mutex, so the + * vif data [id, addr] is safe. + */ + err = carl9170_mod_virtual_mac(ar, old_main_priv->id, + old_main->addr); + if (err) + goto unlock; + } + err = carl9170_init_interface(ar, vif); if (err) goto unlock; @@ -1112,9 +1181,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (ar->disable_offload || !vif) return -EOPNOTSUPP; - /* - * We have to fall back to software encryption, whenever - * the user choose to participates in an IBSS or is connected + /* Fall back to software encryption whenever the driver is connected * to more than one network. * * This is very unfortunate, because some machines cannot handle @@ -1263,7 +1330,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, return 0; } - for (i = 0; i < CARL9170_NUM_TID; i++) + for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) RCU_INIT_POINTER(sta_info->agg[i], NULL); sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); @@ -1287,7 +1354,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, sta_info->ht_sta = false; rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { + for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) { struct carl9170_sta_tid *tid_info; tid_info = rcu_dereference(sta_info->agg[i]); @@ -1807,10 +1874,6 @@ void *carl9170_alloc(size_t priv_size) for (i = 0; i < ARRAY_SIZE(ar->noise); i++) ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - - /* As IBSS Encryption is software-based, IBSS RSN is supported. */ - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; return ar; err_nomem: diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index ef4ec0da6e49..9c0b150d5b8e 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1520,35 +1520,92 @@ void carl9170_tx_scheduler(struct ar9170 *ar) carl9170_tx(ar); } -int carl9170_update_beacon(struct ar9170 *ar, const bool submit) +/* caller has to take rcu_read_lock */ +static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar) { - struct sk_buff *skb = NULL; struct carl9170_vif_info *cvif; + int i = 1; + + /* The AR9170 hardware has no fancy beacon queue or some + * other scheduling mechanism. So, the driver has to make + * due by setting the two beacon timers (pretbtt and tbtt) + * once and then swapping the beacon address in the HW's + * register file each time the pretbtt fires. + */ + + cvif = rcu_dereference(ar->beacon_iter); + if (ar->vifs > 0 && cvif) { + do { + list_for_each_entry_continue_rcu(cvif, &ar->vif_list, + list) { + if (cvif->active && cvif->enable_beacon) + goto out; + } + } while (ar->beacon_enabled && i--); + } + +out: + rcu_assign_pointer(ar->beacon_iter, cvif); + return cvif; +} + +static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb, + u32 *ht1, u32 *plcp) +{ struct ieee80211_tx_info *txinfo; struct ieee80211_tx_rate *rate; - __le32 *data, *old = NULL; - unsigned int plcp, power, chains; - u32 word, ht1, off, addr, len; - int i = 0, err = 0; + unsigned int power, chains; + bool ht_rate; - rcu_read_lock(); - cvif = rcu_dereference(ar->beacon_iter); -retry: - if (ar->vifs == 0 || !cvif) - goto out_unlock; + txinfo = IEEE80211_SKB_CB(skb); + rate = &txinfo->control.rates[0]; + ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS); + carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains); - list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) { - if (cvif->active && cvif->enable_beacon) - goto found; + *ht1 = AR9170_MAC_BCN_HT1_TX_ANT0; + if (chains == AR9170_TX_PHY_TXCHAIN_2) + *ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1; + SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7); + SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power); + SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains); + + if (ht_rate) { + *ht1 |= AR9170_MAC_BCN_HT1_HT_EN; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + *plcp |= AR9170_MAC_BCN_HT2_SGI; + + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { + *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED; + *plcp |= AR9170_MAC_BCN_HT2_BW40; + } else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) { + *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP; + *plcp |= AR9170_MAC_BCN_HT2_BW40; + } + + SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN); + } else { + if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M) + *plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; + else + *plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010; } - if (!ar->beacon_enabled || i++) - goto out_unlock; + return ht_rate; +} - goto retry; +int carl9170_update_beacon(struct ar9170 *ar, const bool submit) +{ + struct sk_buff *skb = NULL; + struct carl9170_vif_info *cvif; + __le32 *data, *old = NULL; + u32 word, ht1, plcp, off, addr, len; + int i = 0, err = 0; + bool ht_rate; -found: - rcu_assign_pointer(ar->beacon_iter, cvif); + rcu_read_lock(); + cvif = carl9170_pick_beaconing_vif(ar); + if (!cvif) + goto out_unlock; skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif), NULL, NULL); @@ -1558,7 +1615,6 @@ found: goto err_free; } - txinfo = IEEE80211_SKB_CB(skb); spin_lock_bh(&ar->beacon_lock); data = (__le32 *)skb->data; if (cvif->beacon) @@ -1588,43 +1644,14 @@ found: goto err_unlock; } - ht1 = AR9170_MAC_BCN_HT1_TX_ANT0; - rate = &txinfo->control.rates[0]; - carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains); - if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) { - if (plcp <= AR9170_TX_PHY_RATE_CCK_11M) - plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; - else - plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010; - } else { - ht1 |= AR9170_MAC_BCN_HT1_HT_EN; - if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - plcp |= AR9170_MAC_BCN_HT2_SGI; - - if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { - ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED; - plcp |= AR9170_MAC_BCN_HT2_BW40; - } - if (rate->flags & IEEE80211_TX_RC_DUP_DATA) { - ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP; - plcp |= AR9170_MAC_BCN_HT2_BW40; - } - - SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN); - } - - SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7); - SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power); - SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains); - if (chains == AR9170_TX_PHY_TXCHAIN_2) - ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1; + ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp); carl9170_async_regwrite_begin(ar); carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1); - if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) - carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp); - else + if (ht_rate) carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp); + else + carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp); for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { /* diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index 2ec3e9191e4d..2282847d4bb8 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 12 -#define CARL9170FW_VERSION_MONTH 7 -#define CARL9170FW_VERSION_DAY 7 -#define CARL9170FW_VERSION_GIT "1.9.6" +#define CARL9170FW_VERSION_MONTH 12 +#define CARL9170FW_VERSION_DAY 15 +#define CARL9170FW_VERSION_GIT "1.9.7" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index be35a2f99b1c..11fd1c735589 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -15,8 +15,6 @@ */ /* ****************** SDIO CARD Interface Functions **************************/ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/types.h> #include <linux/netdevice.h> #include <linux/export.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index d33e5598611b..d92d373733d7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -14,8 +14,6 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/types.h> #include <linux/netdevice.h> #include <linux/mmc/sdio.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index fd672bf53867..a2f32fb990fa 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -39,6 +39,7 @@ #define BRCMF_C_GET_BSSID 23 #define BRCMF_C_GET_SSID 25 #define BRCMF_C_SET_SSID 26 +#define BRCMF_C_TERMINATED 28 #define BRCMF_C_GET_CHANNEL 29 #define BRCMF_C_SET_CHANNEL 30 #define BRCMF_C_GET_SRL 31 @@ -480,36 +481,14 @@ struct brcmf_pub { unsigned long drv_version; /* Version of dongle-resident driver */ u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ - /* Additional stats for the bus level */ - /* Multicast data packets sent to dongle */ unsigned long tx_multicast; - /* Packets flushed due to unscheduled sendup thread */ - unsigned long rx_flushed; - /* Number of times dpc scheduled by watchdog timer */ - unsigned long wd_dpc_sched; - - /* Number of flow control pkts recvd */ - unsigned long fc_packets; - - /* Last error return */ - int bcmerror; - - /* Last error from dongle */ - int dongle_error; - - /* Suspend disable flag flag */ - int suspend_disable_flag; /* "1" to disable all extra powersaving - during suspend */ - int in_suspend; /* flag set to 1 when early suspend called */ - int dtim_skip; /* dtim skip , default 0 means wake each dtim */ struct brcmf_if *iflist[BRCMF_MAX_IFS]; struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; - u8 macvalue[ETH_ALEN]; atomic_t pend_8021x_cnt; wait_queue_head_t pend_8021x_wait; @@ -519,11 +498,6 @@ struct brcmf_pub { #endif }; -struct bcmevent_name { - uint event; - const char *name; -}; - struct brcmf_if_event { u8 ifidx; u8 action; @@ -557,13 +531,6 @@ struct brcmf_if { u8 mac_addr[ETH_ALEN]; }; -static inline s32 brcmf_ndev_bssidx(struct net_device *ndev) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - return ifp->bssidx; -} - -extern const struct bcmevent_name bcmevent_names[]; extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); @@ -576,6 +543,10 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len); +/* Remove any protocol-specific data header. */ +extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, + struct sk_buff *rxp); + extern int brcmf_net_attach(struct brcmf_if *ifp); extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, char *name, u8 *mac_addr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index dd38b78a9726..64c38f4226a3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -130,31 +130,18 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len) * interface functions from common layer */ -/* Remove any protocol-specific data header. */ -extern int brcmf_proto_hdrpull(struct device *dev, int *ifidx, - struct sk_buff *rxp); - extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec); /* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void brcmf_rx_frame(struct device *dev, u8 ifidx, - struct sk_buff_head *rxlist); -static inline void brcmf_rx_packet(struct device *dev, int ifidx, - struct sk_buff *pkt) -{ - struct sk_buff_head q; - - skb_queue_head_init(&q); - skb_queue_tail(&q, pkt); - brcmf_rx_frame(dev, ifidx, &q); -} +extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist); /* Indication from bus module regarding presence/insertion of dongle. */ extern int brcmf_attach(uint bus_hdrlen, struct device *dev); /* Indication from bus module regarding removal/absence of dongle */ extern void brcmf_detach(struct device *dev); - +/* Indication from bus module that dongle should be reset */ +extern void brcmf_dev_reset(struct device *dev); /* Indication from bus module to change flow-control state */ extern void brcmf_txflowblock(struct device *dev, bool state); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index 83923553f1ac..bb454cdab29d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -19,8 +19,6 @@ * For certain dcmd codes, the dongle interprets string data from the host. ******************************************************************************/ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/types.h> #include <linux/netdevice.h> @@ -94,8 +92,6 @@ struct brcmf_proto_bdc_header { struct brcmf_proto { u16 reqid; - u8 pending; - u32 lastcmd; u8 bus_header[BUS_HEADER_LEN]; struct brcmf_proto_cdc_dcmd msg; unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; @@ -107,7 +103,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) int len = le32_to_cpu(prot->msg.len) + sizeof(struct brcmf_proto_cdc_dcmd); - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CDC, "Enter\n"); /* NOTE : cdc->msg.len holds the desired length of the buffer to be * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area @@ -125,7 +121,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) int ret; struct brcmf_proto *prot = drvr->prot; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CDC, "Enter\n"); len += sizeof(struct brcmf_proto_cdc_dcmd); do { ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg, @@ -147,20 +143,7 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, int ret = 0, retries = 0; u32 id, flags; - brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == BRCMF_C_GET_VAR && buf) { - if (!strcmp((char *)buf, "bcmerrorstr")) { - strncpy((char *)buf, "bcm_error", - BCME_STRLEN); - goto done; - } else if (!strcmp((char *)buf, "bcmerror")) { - *(int *)buf = drvr->dongle_error; - goto done; - } - } + brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); @@ -210,11 +193,8 @@ retry: } /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) { + if (flags & CDC_DCMD_ERROR) ret = le32_to_cpu(msg->status); - /* Cache error from dongle */ - drvr->dongle_error = ret; - } done: return ret; @@ -228,8 +208,7 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, int ret = 0; u32 flags, id; - brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); + brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); @@ -262,11 +241,8 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, } /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) { + if (flags & CDC_DCMD_ERROR) ret = le32_to_cpu(msg->status); - /* Cache error from dongle */ - drvr->dongle_error = ret; - } done: return ret; @@ -287,7 +263,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, { struct brcmf_proto_bdc_header *h; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CDC, "Enter\n"); /* Push BDC header used to convey priority for buses that don't */ @@ -305,14 +281,12 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, BDC_SET_IF_IDX(h, ifidx); } -int brcmf_proto_hdrpull(struct device *dev, int *ifidx, +int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, struct sk_buff *pktbuf) { struct brcmf_proto_bdc_header *h; - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pub *drvr = bus_if->drvr; - brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CDC, "Enter\n"); /* Pop BDC header used to convey priority for buses that don't */ @@ -338,7 +312,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx, } if (h->flags & BDC_FLAG_SUM_GOOD) { - brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n", + brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n", brcmf_ifname(drvr, *ifidx), h->flags); pkt_set_sum_good(pktbuf, true); } @@ -348,6 +322,8 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx, skb_pull(pktbuf, BDC_HEADER_LEN); skb_pull(pktbuf, h->data_offset << 2); + if (pktbuf->len == 0) + return -ENODATA; return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index f8b52e5b941a..4544342a0428 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -14,8 +14,6 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/kernel.h> #include <linux/string.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index f2ab01cd7966..bc013cbe06f6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -18,21 +18,26 @@ #define _BRCMF_DBG_H_ /* message levels */ -#define BRCMF_TRACE_VAL 0x0002 -#define BRCMF_INFO_VAL 0x0004 -#define BRCMF_DATA_VAL 0x0008 -#define BRCMF_CTL_VAL 0x0010 -#define BRCMF_TIMER_VAL 0x0020 -#define BRCMF_HDRS_VAL 0x0040 -#define BRCMF_BYTES_VAL 0x0080 -#define BRCMF_INTR_VAL 0x0100 -#define BRCMF_GLOM_VAL 0x0200 -#define BRCMF_EVENT_VAL 0x0400 -#define BRCMF_BTA_VAL 0x0800 -#define BRCMF_FIL_VAL 0x1000 -#define BRCMF_USB_VAL 0x2000 -#define BRCMF_SCAN_VAL 0x4000 -#define BRCMF_CONN_VAL 0x8000 +#define BRCMF_TRACE_VAL 0x00000002 +#define BRCMF_INFO_VAL 0x00000004 +#define BRCMF_DATA_VAL 0x00000008 +#define BRCMF_CTL_VAL 0x00000010 +#define BRCMF_TIMER_VAL 0x00000020 +#define BRCMF_HDRS_VAL 0x00000040 +#define BRCMF_BYTES_VAL 0x00000080 +#define BRCMF_INTR_VAL 0x00000100 +#define BRCMF_GLOM_VAL 0x00000200 +#define BRCMF_EVENT_VAL 0x00000400 +#define BRCMF_BTA_VAL 0x00000800 +#define BRCMF_FIL_VAL 0x00001000 +#define BRCMF_USB_VAL 0x00002000 +#define BRCMF_SCAN_VAL 0x00004000 +#define BRCMF_CONN_VAL 0x00008000 +#define BRCMF_CDC_VAL 0x00010000 + +/* set default print format */ +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Macro for error messages. net_ratelimit() is used when driver * debugging is not selected. When debugging the driver error diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 74a616b4de8e..e3326a58bdb1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -14,8 +14,6 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/kernel.h> #include <linux/etherdevice.h> #include <linux/module.h> @@ -162,28 +160,31 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev) schedule_work(&ifp->multicast_work); } -static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { int ret; struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; + struct ethhdr *eh; brcmf_dbg(TRACE, "Enter\n"); - /* Reject if down */ - if (!drvr->bus_if->drvr_up || - (drvr->bus_if->state != BRCMF_BUS_DATA)) { - brcmf_err("xmit rejected drvup=%d state=%d\n", - drvr->bus_if->drvr_up, - drvr->bus_if->state); + /* Can the device send data? */ + if (drvr->bus_if->state != BRCMF_BUS_DATA) { + brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state); netif_stop_queue(ndev); - return -ENODEV; + dev_kfree_skb(skb); + ret = -ENODEV; + goto done; } if (!drvr->iflist[ifp->idx]) { brcmf_err("bad ifidx %d\n", ifp->idx); netif_stop_queue(ndev); - return -ENODEV; + dev_kfree_skb(skb); + ret = -ENODEV; + goto done; } /* Make sure there's enough room for any header */ @@ -204,17 +205,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) } } - /* Update multicast statistic */ - if (skb->len >= ETH_ALEN) { - u8 *pktdata = (u8 *)(skb->data); - struct ethhdr *eh = (struct ethhdr *)pktdata; - - if (is_multicast_ether_addr(eh->h_dest)) - drvr->tx_multicast++; - if (ntohs(eh->h_proto) == ETH_P_PAE) - atomic_inc(&drvr->pend_8021x_cnt); + /* validate length for ether packet */ + if (skb->len < sizeof(*eh)) { + ret = -EINVAL; + dev_kfree_skb(skb); + goto done; } + /* handle ethernet header */ + eh = (struct ethhdr *)(skb->data); + if (is_multicast_ether_addr(eh->h_dest)) + drvr->tx_multicast++; + if (ntohs(eh->h_proto) == ETH_P_PAE) + atomic_inc(&drvr->pend_8021x_cnt); + /* If the protocol uses a data header, apply it */ brcmf_proto_hdrpush(drvr, ifp->idx, skb); @@ -228,7 +232,7 @@ done: drvr->bus_if->dstats.tx_packets++; /* Return ok: we always eat the packet */ - return 0; + return NETDEV_TX_OK; } void brcmf_txflowblock(struct device *dev, bool state) @@ -250,8 +254,7 @@ void brcmf_txflowblock(struct device *dev, bool state) } } -void brcmf_rx_frame(struct device *dev, u8 ifidx, - struct sk_buff_head *skb_list) +void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) { unsigned char *eth; uint len; @@ -259,12 +262,24 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx, struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; + u8 ifidx; + int ret; brcmf_dbg(TRACE, "Enter\n"); skb_queue_walk_safe(skb_list, skb, pnext) { skb_unlink(skb, skb_list); + /* process and remove protocol-specific header + */ + ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); + if (ret < 0) { + if (ret != -ENODATA) + bus_if->dstats.rx_errors++; + brcmu_pkt_buf_free_skb(skb); + continue; + } + /* Get the protocol, maintain skb around eth_type_trans() * The main reason for this hack is for the limitation of * Linux 2.4 where 'eth_type_trans' uses the @@ -328,13 +343,13 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx, void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) { - uint ifidx; + u8 ifidx; struct ethhdr *eh; u16 type; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; - brcmf_proto_hdrpull(dev, &ifidx, txp); + brcmf_proto_hdrpull(drvr, &ifidx, txp); eh = (struct ethhdr *)(txp->data); type = ntohs(eh->h_proto); @@ -450,7 +465,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) sprintf(info.version, "%lu", drvr->drv_version); if (copy_to_user(uaddr, &info, sizeof(info))) return -EFAULT; - brcmf_dbg(CTL, "given %*s, returning %s\n", + brcmf_dbg(TRACE, "given %*s, returning %s\n", (int)sizeof(drvname), drvname, info.driver); break; @@ -570,14 +585,9 @@ static int brcmf_netdev_open(struct net_device *ndev) /* Get current TOE mode from dongle */ if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) - drvr->iflist[ifp->idx]->ndev->features |= - NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_IP_CSUM; else - drvr->iflist[ifp->idx]->ndev->features &= - ~NETIF_F_IP_CSUM; - - /* make sure RF is ready for work */ - brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); + ndev->features &= ~NETIF_F_IP_CSUM; /* Allow transmit calls */ netif_start_queue(ndev); @@ -845,6 +855,17 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr) } } +void brcmf_dev_reset(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + + if (drvr == NULL) + return; + + brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); +} + void brcmf_detach(struct device *dev) { int i; @@ -866,9 +887,8 @@ void brcmf_detach(struct device *dev) brcmf_bus_detach(drvr); - if (drvr->prot) { + if (drvr->prot) brcmf_proto_detach(drvr); - } brcmf_debugfs_detach(drvr); bus_if->drvr = NULL; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index cf857f1edf8c..7fef9b5ba003 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -14,8 +14,6 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/types.h> #include <linux/kernel.h> #include <linux/kthread.h> @@ -1169,7 +1167,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) int errcode; u8 doff, sfdoff; - int ifidx = 0; bool usechain = bus->use_rxchain; struct brcmf_sdio_read rd_new; @@ -1388,13 +1385,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) skb_unlink(pfirst, &bus->glom); brcmu_pkt_buf_free_skb(pfirst); continue; - } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, - &ifidx, pfirst) != 0) { - brcmf_err("rx protocol error\n"); - bus->sdiodev->bus_if->dstats.rx_errors++; - skb_unlink(pfirst, &bus->glom); - brcmu_pkt_buf_free_skb(pfirst); - continue; } brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), @@ -1407,7 +1397,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } /* sent any remaining packets up */ if (bus->glom.qlen) - brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom); + brcmf_rx_frames(bus->sdiodev->dev, &bus->glom); bus->sdcnt.rxglomframes++; bus->sdcnt.rxglompkts += bus->glom.qlen; @@ -1558,10 +1548,10 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) { struct sk_buff *pkt; /* Packet for event or data frames */ + struct sk_buff_head pktlist; /* needed for bus interface */ u16 pad; /* Number of pad bytes to read */ uint rxleft = 0; /* Remaining number of frames allowed */ int sdret; /* Return code from calls */ - int ifidx = 0; uint rxcount = 0; /* Total frames read */ struct brcmf_sdio_read *rd = &bus->cur_read, rd_new; u8 head_read = 0; @@ -1760,15 +1750,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) if (pkt->len == 0) { brcmu_pkt_buf_free_skb(pkt); continue; - } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx, - pkt) != 0) { - brcmf_err("rx protocol error\n"); - brcmu_pkt_buf_free_skb(pkt); - bus->sdiodev->bus_if->dstats.rx_errors++; - continue; } - brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); + skb_queue_head_init(&pktlist); + skb_queue_tail(&pktlist, pkt); + brcmf_rx_frames(bus->sdiodev->dev, &pktlist); } rxcount = maxframes - rxleft; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index b1bb46c49799..14be2d5530ce 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -15,8 +15,6 @@ */ /* ***** SDIO interface chip backplane handle functions ***** */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/types.h> #include <linux/netdevice.h> #include <linux/mmc/card.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 914c56fe6c5f..e15630cc3889 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -443,14 +443,15 @@ static void brcmf_usb_rx_complete(struct urb *urb) struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; struct brcmf_usbdev_info *devinfo = req->devinfo; struct sk_buff *skb; - int ifidx = 0; + struct sk_buff_head skbq; brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); brcmf_usb_del_fromq(devinfo, req); skb = req->skb; req->skb = NULL; - if (urb->status == 0) { + /* zero lenght packets indicate usb "failure". Do not refill */ + if (urb->status == 0 && urb->actual_length) { devinfo->bus_pub.bus->dstats.rx_packets++; } else { devinfo->bus_pub.bus->dstats.rx_errors++; @@ -460,13 +461,10 @@ static void brcmf_usb_rx_complete(struct urb *urb) } if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { + skb_queue_head_init(&skbq); + skb_queue_tail(&skbq, skb); skb_put(skb, urb->actual_length); - if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { - brcmf_err("rx protocol error\n"); - brcmu_pkt_buf_free_skb(skb); - devinfo->bus_pub.bus->dstats.rx_errors++; - } else - brcmf_rx_packet(devinfo->dev, ifidx, skb); + brcmf_rx_frames(devinfo->dev, &skbq); brcmf_usb_rx_refill(devinfo, req); } else { brcmu_pkt_buf_free_skb(skb); @@ -1520,10 +1518,23 @@ static void brcmf_release_fw(struct list_head *q) } } +static int brcmf_usb_reset_device(struct device *dev, void *notused) +{ + /* device past is the usb interface so we + * need to use parent here. + */ + brcmf_dev_reset(dev->parent); + return 0; +} void brcmf_usb_exit(void) { + struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver; + int ret; + brcmf_dbg(USB, "Enter\n"); + ret = driver_for_each_device(drv, NULL, NULL, + brcmf_usb_reset_device); usb_deregister(&brcmf_usbdrvr); brcmf_release_fw(&fw_image_list); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 1261a9b84e04..730da84edb01 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -16,8 +16,6 @@ /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/kernel.h> #include <linux/etherdevice.h> #include <net/cfg80211.h> @@ -2011,67 +2009,6 @@ done: return err; } -static s32 -brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, - const u8 *addr, - const struct cfg80211_bitrate_mask *mask) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - struct brcm_rateset_le rateset_le; - s32 rate; - s32 val; - s32 err_bg; - s32 err_a; - u32 legacy; - s32 err = 0; - - brcmf_dbg(TRACE, "Enter\n"); - if (!check_vif_up(ifp->vif)) - return -EIO; - - /* addr param is always NULL. ignore it */ - /* Get current rateset */ - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET, - &rateset_le, sizeof(rateset_le)); - if (err) { - brcmf_err("could not get current rateset (%d)\n", err); - goto done; - } - - legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF); - if (!legacy) - legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy & - 0xFFFF); - - val = wl_g_rates[legacy - 1].bitrate * 100000; - - if (val < le32_to_cpu(rateset_le.count)) - /* Select rate by rateset index */ - rate = rateset_le.rates[val] & 0x7f; - else - /* Specified rate in bps */ - rate = val / 500000; - - brcmf_dbg(CONN, "rate %d mbps\n", rate / 2); - - /* - * - * Set rate override, - * Since the is a/b/g-blind, both a/bg_rate are enforced. - */ - err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate); - err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate); - if (err_bg && err_a) { - brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg, - err_a); - err = err_bg | err_a; - } - -done: - brcmf_dbg(TRACE, "Exit\n"); - return err; -} - static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct brcmf_bss_info_le *bi) { @@ -3703,7 +3640,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_default_key = brcmf_cfg80211_config_default_key, .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, - .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, .connect = brcmf_cfg80211_connect, .disconnect = brcmf_cfg80211_disconnect, .suspend = brcmf_cfg80211_suspend, @@ -4329,9 +4265,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) } static s32 -brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) +brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) { - struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; __le32 roamtrigger[2]; __le32 roam_delta[2]; @@ -4382,10 +4317,9 @@ dongle_rom_out: } static s32 -brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, +brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time, s32 scan_unassoc_time, s32 scan_passive_time) { - struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, @@ -4455,6 +4389,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) { struct net_device *ndev; struct wireless_dev *wdev; + struct brcmf_if *ifp; s32 power_mode; s32 err = 0; @@ -4463,35 +4398,34 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) ndev = cfg_to_ndev(cfg); wdev = ndev->ieee80211_ptr; + ifp = netdev_priv(ndev); - brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, - WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); + /* make sure RF is ready for work */ + brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); + + brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME, + WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM, - power_mode); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode); if (err) goto default_conf_out; brcmf_dbg(INFO, "power save set to %s\n", (power_mode ? "enabled" : "disabled")); - err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1), - WL_BEACON_TIMEOUT); + err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT); if (err) goto default_conf_out; err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, NULL, NULL); - if (err && err != -EINPROGRESS) + if (err) goto default_conf_out; err = brcmf_dongle_probecap(cfg); if (err) goto default_conf_out; - /* -EINPROGRESS: Call commit handler */ - -default_conf_out: - cfg->dongle_up = true; +default_conf_out: return err; @@ -4500,8 +4434,6 @@ default_conf_out: static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp) { set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); - if (ifp->idx) - return 0; return brcmf_config_dongle(ifp->drvr->config); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 1de94f30564f..1585cc5bf866 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -961,7 +961,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, /* if acked then clear bit and free packet */ if ((bindex < AMPDU_TX_BA_MAX_WSIZE) && isset(bitmap, bindex)) { - ini->tx_in_transit--; ini->txretry[index] = 0; /* @@ -990,7 +989,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, if (retry && (ini->txretry[index] < (int)retry_limit)) { int ret; ini->txretry[index]++; - ini->tx_in_transit--; ret = brcms_c_txfifo(wlc, queue, p); /* * We shouldn't be out of space in the DMA @@ -1000,7 +998,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, WARN_ONCE(ret, "queue %d out of txds\n", queue); } else { /* Retry timeout */ - ini->tx_in_transit--; ieee80211_tx_info_clear_status(tx_info); tx_info->status.ampdu_ack_len = 0; tx_info->status.ampdu_len = 1; @@ -1009,8 +1006,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_TXH_LEN); brcms_dbg_ht(wlc->hw->d11core, - "BA Timeout, seq %d, in_transit %d\n", - seq, ini->tx_in_transit); + "BA Timeout, seq %d\n", + seq); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index f0fc8cd4d5df..7fc49ca3f597 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -362,8 +362,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return -EOPNOTSUPP; } + spin_lock_bh(&wl->lock); + memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr)); wl->mute_tx = false; brcms_c_mute(wl->wlc, false); + spin_unlock_bh(&wl->lock); return 0; } @@ -1409,9 +1412,10 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) #endif t->ms = ms; t->periodic = (bool) periodic; - t->set = true; - - atomic_inc(&t->wl->callbacks); + if (!t->set) { + t->set = true; + atomic_inc(&t->wl->callbacks); + } ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 17594de4199e..c26992a60e6c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -2473,6 +2473,7 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx) { static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr; if (mute_tx) { /* suspend tx fifos */ @@ -2482,8 +2483,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx) brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO); /* zero the address match register so we do not send ACKs */ - brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, - null_ether_addr); + brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr); } else { /* resume tx fifos */ brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO); @@ -2492,8 +2492,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx) brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO); /* Restore address */ - brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, - wlc_hw->etheraddr); + brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr); } wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0); @@ -7633,7 +7632,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) uint n = 0; uint bound_limit = bound ? RXBND : -1; - bool morepending; + bool morepending = false; skb_queue_head_init(&recv_frames); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/scb.h b/drivers/net/wireless/brcm80211/brcmsmac/scb.h index 51c79c7239b7..3a3d73699f83 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/scb.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/scb.h @@ -36,7 +36,6 @@ /* structure to store per-tid state for the ampdu initiator */ struct scb_ampdu_tid_ini { - u8 tx_in_transit; /* number of pending mpdus in transit in driver */ u8 tid; /* initiator tid for easy lookup */ /* tx retry count; indexed by seq modulo */ u8 txretry[AMPDU_TX_BA_MAX_WSIZE]; diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index d604b4036a76..3d76a3f595b7 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3474,6 +3474,7 @@ struct ieee80211_ops il3945_mac_ops = { .sta_add = il3945_mac_sta_add, .sta_remove = il_mac_sta_remove, .tx_last_beacon = il_mac_tx_last_beacon, + .flush = il_mac_flush, }; static int @@ -3548,7 +3549,8 @@ il3945_setup_mac(struct il_priv *il) hw->vif_data_size = sizeof(struct il_vif_priv); /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT; + hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); @@ -3557,6 +3559,8 @@ il3945_setup_mac(struct il_priv *il) WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2; diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 6a86ed45835d..10fc2493f415 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -5712,8 +5712,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) 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; - + IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; if (il->cfg->sku & IL_SKU_N) hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | @@ -6308,6 +6308,7 @@ const struct ieee80211_ops il4965_mac_ops = { .sta_remove = il_mac_sta_remove, .channel_switch = il4965_mac_channel_switch, .tx_last_beacon = il_mac_tx_last_beacon, + .flush = il_mac_flush, }; static int diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 7e16d10a7f14..56b80219d695 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4707,6 +4707,42 @@ out: } EXPORT_SYMBOL(il_mac_change_interface); +void +il_mac_flush(struct ieee80211_hw *hw, bool drop) +{ + struct il_priv *il = hw->priv; + unsigned long timeout = jiffies + msecs_to_jiffies(500); + int i; + + mutex_lock(&il->mutex); + D_MAC80211("enter\n"); + + if (il->txq == NULL) + goto out; + + for (i = 0; i < il->hw_params.max_txq_num; i++) { + struct il_queue *q; + + if (i == il->cmd_queue) + continue; + + q = &il->txq[i].q; + if (q->read_ptr == q->write_ptr) + continue; + + if (time_after(jiffies, timeout)) { + IL_ERR("Failed to flush queue %d\n", q->id); + break; + } + + msleep(20); + } +out: + D_MAC80211("leave\n"); + mutex_unlock(&il->mutex); +} +EXPORT_SYMBOL(il_mac_flush); + /* * On every watchdog tick we check (latest) time stamp. If it does not * change during timeout period and queue is not empty we reset firmware. diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index a9a569f432fb..37fe553b25e0 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1723,6 +1723,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype newtype, bool newp2p); +void il_mac_flush(struct ieee80211_hw *hw, bool drop); int il_alloc_txq_mem(struct il_priv *il); void il_free_txq_mem(struct il_priv *il); diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 71ab76b2b39d..0ca99c13f7f2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -3695,7 +3695,7 @@ struct iwl_bt_uart_msg { u8 frame5; u8 frame6; u8 frame7; -} __attribute__((packed)); +} __packed; struct iwl_bt_coex_profile_notif { struct iwl_bt_uart_msg last_bt_uart_msg; @@ -3703,7 +3703,7 @@ struct iwl_bt_coex_profile_notif { u8 bt_traffic_load; /* 0 .. 3? */ u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */ u8 reserved; -} __attribute__((packed)); +} __packed; #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS 0 #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK 0x1 @@ -3752,7 +3752,7 @@ enum bt_coex_prio_table_priorities { struct iwl_bt_coex_prio_table_cmd { u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; -} __attribute__((packed)); +} __packed; #define IWL_BT_COEX_ENV_CLOSE 0 #define IWL_BT_COEX_ENV_OPEN 1 @@ -3764,7 +3764,7 @@ struct iwl_bt_coex_prot_env_cmd { u8 action; /* 0 = closed, 1 = open */ u8 type; /* 0 .. 15 */ u8 reserved[2]; -} __attribute__((packed)); +} __packed; /* * REPLY_D3_CONFIG diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 5b9533eef54d..72c74af38138 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -157,7 +157,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, sram = priv->dbgfs_sram_offset & ~0x3; /* read the first u32 from sram */ - val = iwl_read_targ_mem(priv->trans, sram); + val = iwl_trans_read_mem32(priv->trans, sram); for (; len; len--) { /* put the address at the start of every line */ @@ -176,7 +176,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, if (++offset == 4) { sram += 4; offset = 0; - val = iwl_read_targ_mem(priv->trans, sram); + val = iwl_trans_read_mem32(priv->trans, sram); } /* put in extra spaces and split lines for human readability */ diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c index bf479f709091..844a17f99a18 100644 --- a/drivers/net/wireless/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/iwlwifi/dvm/led.c @@ -69,7 +69,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { /* Set led register off */ void iwlagn_led_enable(struct iwl_priv *priv) { - iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON); + iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); } /* diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 02fdcea76b21..0353e1c0670d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -206,7 +206,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, #ifdef CONFIG_PM_SLEEP if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && - priv->trans->ops->wowlan_suspend && + priv->trans->ops->d3_suspend && + priv->trans->ops->d3_resume && device_can_wakeup(priv->trans->dev)) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | @@ -426,7 +427,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, if (ret) goto error; - iwl_trans_wowlan_suspend(priv->trans); + iwl_trans_d3_suspend(priv->trans); goto out; @@ -459,11 +460,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) base = priv->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { spin_lock_irqsave(&priv->trans->reg_lock, flags); - ret = iwl_grab_nic_access_silent(priv->trans); - if (likely(ret == 0)) { + if (iwl_trans_grab_nic_access(priv->trans, true)) { iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(priv->trans); + iwl_trans_release_nic_access(priv->trans); + ret = 0; } spin_unlock_irqrestore(&priv->trans->reg_lock, flags); @@ -479,7 +480,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) } if (priv->wowlan_sram) - _iwl_read_targ_mem_dwords( + iwl_trans_read_mem( priv->trans, 0x800000, priv->wowlan_sram, img->sec[IWL_UCODE_SECTION_DATA].len / 4); @@ -520,9 +521,6 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - 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, control->sta, skb)) ieee80211_free_txskb(hw, skb); } diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index faa05932efae..a64f361e341c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -354,7 +354,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, /* Make sure device is powered up for SRAM reads */ spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); - if (unlikely(!iwl_grab_nic_access(priv->trans))) { + if (!iwl_trans_grab_nic_access(priv->trans, false)) { spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); return; } @@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, } } /* Allow device to power down */ - iwl_release_nic_access(priv->trans); + iwl_trans_release_nic_access(priv->trans); spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); } @@ -408,7 +408,8 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) base = priv->device_pointers.log_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read)); + iwl_trans_read_mem_bytes(priv->trans, base, + &read, sizeof(read)); capacity = read.capacity; mode = read.mode; num_wraps = read.wrap_counter; @@ -1627,7 +1628,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) } /*TODO: Update dbgfs with ISR error stats obtained below */ - iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table)); + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); @@ -1717,7 +1718,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, /* Make sure device is powered up for SRAM reads */ spin_lock_irqsave(&trans->reg_lock, reg_flags); - if (unlikely(!iwl_grab_nic_access(trans))) + if (!iwl_trans_grab_nic_access(trans, false)) goto out_unlock; /* Set starting address; reads will auto-increment */ @@ -1756,7 +1757,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, } /* Allow device to power down */ - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); out_unlock: spin_unlock_irqrestore(&trans->reg_lock, reg_flags); return pos; @@ -1835,10 +1836,10 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, } /* event log header */ - capacity = iwl_read_targ_mem(trans, base); - mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32))); + capacity = iwl_trans_read_mem32(trans, base); + mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32))); + num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32))); + next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32))); if (capacity > logsize) { IWL_ERR(priv, "Log capacity %d is bogus, limit to %d " diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index eb864433e59d..b28cfc8553d7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c @@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) } iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); spin_lock_irqsave(&priv->trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(priv->trans))) - iwl_release_nic_access(priv->trans); + if (iwl_trans_grab_nic_access(priv->trans, false)) + iwl_trans_release_nic_access(priv->trans); spin_unlock_irqrestore(&priv->trans->reg_lock, flags); /* Reschedule the ct_kill timer to occur in diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index da21328ca8ed..b0aad71c12a0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -231,13 +231,11 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv, memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); if (info->flags & IEEE80211_TX_CTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); break; case WLAN_CIPHER_SUITE_TKIP: tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); - IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n"); break; case WLAN_CIPHER_SUITE_WEP104: @@ -355,8 +353,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, } } - IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); - if (sta) sta_priv = (void *)sta->drv_priv; @@ -472,6 +468,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, WARN_ON_ONCE(is_agg && priv->queue_to_mac80211[txq_id] != info->hw_queue); + IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid, + txq_id, seq_number); + if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id)) goto drop_unlock_sta; @@ -541,9 +540,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, spin_lock_bh(&priv->sta_lock); tid_data = &priv->tid_data[sta_id][tid]; - txq_id = priv->tid_data[sta_id][tid].agg.txq_id; + txq_id = tid_data->agg.txq_id; - switch (priv->tid_data[sta_id][tid].agg.state) { + switch (tid_data->agg.state) { case IWL_EMPTYING_HW_QUEUE_ADDBA: /* * This can happen if the peer stops aggregation @@ -563,9 +562,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, case IWL_AGG_ON: break; default: - IWL_WARN(priv, "Stopping AGG while state not ON " - "or starting for %d on %d (%d)\n", sta_id, tid, - priv->tid_data[sta_id][tid].agg.state); + IWL_WARN(priv, + "Stopping AGG while state not ON or starting for %d on %d (%d)\n", + sta_id, tid, tid_data->agg.state); spin_unlock_bh(&priv->sta_lock); return 0; } @@ -578,12 +577,11 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, "stopping AGG on STA/TID %d/%d but hwq %d not used\n", sta_id, tid, txq_id); } else if (tid_data->agg.ssn != tid_data->next_reclaimed) { - IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " - "next_recl = %d\n", + IWL_DEBUG_TX_QUEUES(priv, + "Can't proceed: ssn %d, next_recl = %d\n", tid_data->agg.ssn, tid_data->next_reclaimed); - priv->tid_data[sta_id][tid].agg.state = - IWL_EMPTYING_HW_QUEUE_DELBA; + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA; spin_unlock_bh(&priv->sta_lock); return 0; } @@ -591,8 +589,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", tid_data->agg.ssn); turn_off: - agg_state = priv->tid_data[sta_id][tid].agg.state; - priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; + agg_state = tid_data->agg.state; + tid_data->agg.state = IWL_AGG_OFF; spin_unlock_bh(&priv->sta_lock); @@ -954,12 +952,6 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, if (status & (AGG_TX_STATE_FEW_BYTES_MSK | AGG_TX_STATE_ABORT_MSK)) continue; - - IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), " - "try-count (0x%08x)\n", - iwl_get_agg_tx_fail_reason(fstatus), - fstatus & AGG_TX_STATUS_MSK, - fstatus & AGG_TX_TRY_MSK); } } @@ -1213,16 +1205,27 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, freed++; } - WARN_ON(!is_agg && freed != 1); + if (!is_agg && freed != 1) + IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed); /* * An offchannel frame can be send only on the AUX queue, where * there is no aggregation (and reordering) so it only is single * skb is expected to be processed. */ - WARN_ON(is_offchannel_skb && freed != 1); + if (is_offchannel_skb && freed != 1) + IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed); } + IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id, + iwl_get_tx_fail_reason(status), status); + + IWL_DEBUG_TX_REPLY(priv, + "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n", + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame, SEQ_TO_INDEX(sequence), ssn, + le16_to_cpu(tx_resp->seq_ctl)); + iwl_check_abort_status(priv, tx_resp->frame_count, status); spin_unlock(&priv->sta_lock); diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index c6467e5554f5..ebec13a3329f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -286,89 +286,6 @@ static int iwl_alive_notify(struct iwl_priv *priv) return iwl_send_calib_results(priv); } - -/** - * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, - * 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_sec_sparse(struct iwl_priv *priv, - const struct fw_desc *fw_desc) -{ - __le32 *image = (__le32 *)fw_desc->data; - u32 len = fw_desc->len; - u32 val; - u32 i; - - IWL_DEBUG_FW(priv, "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(priv->trans, HBUS_TARG_MEM_RADDR, - i + fw_desc->offset); - val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) - return -EIO; - } - - return 0; -} - -static void iwl_print_mismatch_sec(struct iwl_priv *priv, - const struct fw_desc *fw_desc) -{ - __le32 *image = (__le32 *)fw_desc->data; - u32 len = fw_desc->len; - u32 val; - u32 offs; - int errors = 0; - - IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); - - iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR, - fw_desc->offset); - - for (offs = 0; - offs < len && errors < 20; - offs += sizeof(u32), image++) { - /* read data comes through single port, auto-incr addr */ - val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - offs, val, le32_to_cpu(*image)); - errors++; - } - } -} - -/** - * iwl_verify_ucode - determine which instruction image is in SRAM, - * and verify its contents - */ -static int iwl_verify_ucode(struct iwl_priv *priv, - enum iwl_ucode_type ucode_type) -{ - const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type); - - if (!img) { - IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type); - return -EINVAL; - } - - if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) { - IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n"); - return 0; - } - - IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - - iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]); - return -EIO; -} - struct iwl_alive_data { bool valid; u8 subtype; @@ -426,7 +343,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, alive_cmd, ARRAY_SIZE(alive_cmd), iwl_alive_fn, &alive_data); - ret = iwl_trans_start_fw(priv->trans, fw); + ret = iwl_trans_start_fw(priv->trans, fw, false); if (ret) { priv->cur_ucode = old_type; iwl_remove_notification(&priv->notif_wait, &alive_wait); @@ -450,18 +367,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, return -EIO; } - /* - * This step takes a long time (60-80ms!!) and - * WoWLAN image should be loaded quickly, so - * skip it for WoWLAN. - */ if (ucode_type != IWL_UCODE_WOWLAN) { - ret = iwl_verify_ucode(priv, ucode_type); - if (ret) { - priv->cur_ucode = old_type; - return ret; - } - /* delay a bit to give rfkill time to run */ msleep(5); } diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 34a5287dfc2f..b419a1efac0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -381,8 +381,8 @@ /* LED */ #define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) -#define CSR_LED_REG_TRUN_ON (0x78) -#define CSR_LED_REG_TRUN_OFF (0x38) +#define CSR_LED_REG_TURN_ON (0x60) +#define CSR_LED_REG_TURN_OFF (0x20) /* ANA_PLL */ #define CSR50_ANA_PLL_CFG_VAL (0x00880300) diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index ec48563d3c6a..c646a90b725e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -225,6 +225,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) #define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) +#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c) +#define FH_RSCSR_CHNL0_RDPTR FW_RSCSR_CHNL0_RXDCB_RDPTR_REG /** * Rx Config/Status Registers (RCSR) @@ -257,6 +259,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) #define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) +#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR (FH_MEM_RCSR_CHNL0 + 0x8) +#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (FH_MEM_RCSR_CHNL0 + 0x10) #define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */ #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index cdaff9572059..bff3ac96c00b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -35,12 +35,12 @@ #define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) +void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) { iwl_write32(trans, reg, iwl_read32(trans, reg) | mask); } -static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) +void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) { iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask); } @@ -99,86 +99,16 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, } EXPORT_SYMBOL_GPL(iwl_poll_bit); -int iwl_grab_nic_access_silent(struct iwl_trans *trans) -{ - int ret; - - lockdep_assert_held(&trans->reg_lock); - - /* this bit wakes up the NIC */ - __iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* - * These bits say the device is running, and should keep running for - * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), - * but they do not indicate that embedded SRAM is restored yet; - * 3945 and 4965 have volatile SRAM, and must save/restore contents - * to/from host DRAM when sleeping/waking for power-saving. - * Each direction takes approximately 1/4 millisecond; with this - * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a - * series of register accesses are expected (e.g. reading Event Log), - * to keep device from sleeping. - * - * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that - * SRAM is okay/restored. We don't check that here because this call - * is just for hardware register access; but GP1 MAC_SLEEP check is a - * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). - * - * 5000 series and later (including 1000 series) have non-volatile SRAM, - * and do not save/restore SRAM when power cycling. - */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); - if (ret < 0) { - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); - return -EIO; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent); - -bool iwl_grab_nic_access(struct iwl_trans *trans) -{ - int ret = iwl_grab_nic_access_silent(trans); - if (unlikely(ret)) { - u32 val = iwl_read32(trans, CSR_GP_CNTRL); - WARN_ONCE(1, "Timeout waiting for hardware access " - "(CSR_GP_CNTRL 0x%08x)\n", val); - return false; - } - - return true; -} -EXPORT_SYMBOL_GPL(iwl_grab_nic_access); - -void iwl_release_nic_access(struct iwl_trans *trans) -{ - lockdep_assert_held(&trans->reg_lock); - __iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - /* - * Above we read the CSR_GP_CNTRL register, which will flush - * any previous writes, but we need the write that clears the - * MAC_ACCESS_REQ bit to be performed before any other writes - * scheduled on different CPUs (after we drop reg_lock). - */ - mmiowb(); -} -EXPORT_SYMBOL_GPL(iwl_release_nic_access); - u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) { - u32 value; + u32 value = 0x5a5a5a5a; unsigned long flags; spin_lock_irqsave(&trans->reg_lock, flags); - iwl_grab_nic_access(trans); - value = iwl_read32(trans, reg); - iwl_release_nic_access(trans); + if (iwl_trans_grab_nic_access(trans, false)) { + value = iwl_read32(trans, reg); + iwl_trans_release_nic_access(trans); + } spin_unlock_irqrestore(&trans->reg_lock, flags); return value; @@ -190,9 +120,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) unsigned long flags; spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { + if (iwl_trans_grab_nic_access(trans, false)) { iwl_write32(trans, reg, value); - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); } spin_unlock_irqrestore(&trans->reg_lock, flags); } @@ -230,12 +160,13 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) { unsigned long flags; - u32 val; + u32 val = 0x5a5a5a5a; spin_lock_irqsave(&trans->reg_lock, flags); - iwl_grab_nic_access(trans); - val = __iwl_read_prph(trans, ofs); - iwl_release_nic_access(trans); + if (iwl_trans_grab_nic_access(trans, false)) { + val = __iwl_read_prph(trans, ofs); + iwl_trans_release_nic_access(trans); + } spin_unlock_irqrestore(&trans->reg_lock, flags); return val; } @@ -246,9 +177,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) unsigned long flags; spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { + if (iwl_trans_grab_nic_access(trans, false)) { __iwl_write_prph(trans, ofs, val); - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); } spin_unlock_irqrestore(&trans->reg_lock, flags); } @@ -259,10 +190,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) unsigned long flags; spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { + if (iwl_trans_grab_nic_access(trans, false)) { __iwl_write_prph(trans, ofs, __iwl_read_prph(trans, ofs) | mask); - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); } spin_unlock_irqrestore(&trans->reg_lock, flags); } @@ -274,10 +205,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, unsigned long flags; spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { + if (iwl_trans_grab_nic_access(trans, false)) { __iwl_write_prph(trans, ofs, (__iwl_read_prph(trans, ofs) & mask) | bits); - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); } spin_unlock_irqrestore(&trans->reg_lock, flags); } @@ -289,66 +220,11 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) u32 val; spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { + if (iwl_trans_grab_nic_access(trans, false)) { val = __iwl_read_prph(trans, ofs); __iwl_write_prph(trans, ofs, (val & ~mask)); - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); } spin_unlock_irqrestore(&trans->reg_lock, flags); } EXPORT_SYMBOL_GPL(iwl_clear_bits_prph); - -void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr, - void *buf, int dwords) -{ - unsigned long flags; - int offs; - u32 *vals = buf; - - spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { - iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); - for (offs = 0; offs < dwords; offs++) - vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(trans); - } - spin_unlock_irqrestore(&trans->reg_lock, flags); -} -EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords); - -u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr) -{ - u32 value; - - _iwl_read_targ_mem_dwords(trans, addr, &value, 1); - - return value; -} -EXPORT_SYMBOL_GPL(iwl_read_targ_mem); - -int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr, - const void *buf, int dwords) -{ - unsigned long flags; - int offs, result = 0; - const u32 *vals = buf; - - spin_lock_irqsave(&trans->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans))) { - iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); - for (offs = 0; offs < dwords; offs++) - iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]); - iwl_release_nic_access(trans); - } else - result = -EBUSY; - spin_unlock_irqrestore(&trans->reg_lock, flags); - - return result; -} -EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords); - -int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val) -{ - return _iwl_write_targ_mem_dwords(trans, addr, &val, 1); -} -EXPORT_SYMBOL_GPL(iwl_write_targ_mem); diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 48dc753e3742..dc478068596b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -53,6 +53,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs) void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); +void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask); +void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask); void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); @@ -61,10 +63,6 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout); -int iwl_grab_nic_access_silent(struct iwl_trans *trans); -bool iwl_grab_nic_access(struct iwl_trans *trans); -void iwl_release_nic_access(struct iwl_trans *trans); - u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); @@ -76,19 +74,4 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, u32 bits, u32 mask); void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); -void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr, - void *buf, int dwords); - -#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize) \ - do { \ - BUILD_BUG_ON((bufsize) % sizeof(u32)); \ - _iwl_read_targ_mem_dwords(trans, addr, buf, \ - (bufsize) / sizeof(u32));\ - } while (0) - -int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr, - const void *buf, int dwords); - -u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr); -int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c index 81e8c7126d72..1a226114fe73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-test.c +++ b/drivers/net/wireless/iwlwifi/iwl-test.c @@ -467,18 +467,20 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size) if (IWL_ABS_PRPH_START <= addr && addr < IWL_ABS_PRPH_START + PRPH_END) { spin_lock_irqsave(&trans->reg_lock, flags); - iwl_grab_nic_access(trans); + if (!iwl_trans_grab_nic_access(trans, false)) { + spin_unlock_irqrestore(&trans->reg_lock, flags); + return -EIO; + } iwl_write32(trans, HBUS_TARG_PRPH_RADDR, addr | (3 << 24)); for (i = 0; i < size; i += 4) *(u32 *)(tst->mem.addr + i) = iwl_read32(trans, HBUS_TARG_PRPH_RDAT); - iwl_release_nic_access(trans); + iwl_trans_release_nic_access(trans); spin_unlock_irqrestore(&trans->reg_lock, flags); } else { /* target memory (SRAM) */ - _iwl_read_targ_mem_dwords(trans, addr, - tst->mem.addr, - tst->mem.size / 4); + iwl_trans_read_mem(trans, addr, tst->mem.addr, + tst->mem.size / 4); } tst->mem.nchunks = @@ -501,28 +503,31 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr, if (IWL_ABS_PRPH_START <= addr && addr < IWL_ABS_PRPH_START + PRPH_END) { - /* Periphery writes can be 1-3 bytes long, or DWORDs */ - if (size < 4) { - memcpy(&val, buf, size); - spin_lock_irqsave(&trans->reg_lock, flags); - iwl_grab_nic_access(trans); - iwl_write32(trans, HBUS_TARG_PRPH_WADDR, - (addr & 0x0000FFFF) | - ((size - 1) << 24)); - iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); - iwl_release_nic_access(trans); - /* needed after consecutive writes w/o read */ - mmiowb(); + /* Periphery writes can be 1-3 bytes long, or DWORDs */ + if (size < 4) { + memcpy(&val, buf, size); + spin_lock_irqsave(&trans->reg_lock, flags); + if (!iwl_trans_grab_nic_access(trans, false)) { spin_unlock_irqrestore(&trans->reg_lock, flags); - } else { - if (size % 4) - return -EINVAL; - for (i = 0; i < size; i += 4) - iwl_write_prph(trans, addr+i, - *(u32 *)(buf+i)); + return -EIO; } + iwl_write32(trans, HBUS_TARG_PRPH_WADDR, + (addr & 0x0000FFFF) | + ((size - 1) << 24)); + iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); + iwl_trans_release_nic_access(trans); + /* needed after consecutive writes w/o read */ + mmiowb(); + spin_unlock_irqrestore(&trans->reg_lock, flags); + } else { + if (size % 4) + return -EINVAL; + for (i = 0; i < size; i += 4) + iwl_write_prph(trans, addr+i, + *(u32 *)(buf+i)); + } } else if (iwl_test_valid_hw_addr(tst, addr)) { - _iwl_write_targ_mem_dwords(trans, addr, buf, size / 4); + iwl_trans_write_mem(trans, addr, buf, size / 4); } else { return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index b76532e238c1..0f85eb305878 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -308,6 +308,16 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) #define IWL_FRAME_LIMIT 64 /** + * enum iwl_wowlan_status - WoWLAN image/device status + * @IWL_D3_STATUS_ALIVE: firmware is still running after resume + * @IWL_D3_STATUS_RESET: device was reset while suspended + */ +enum iwl_d3_status { + IWL_D3_STATUS_ALIVE, + IWL_D3_STATUS_RESET, +}; + +/** * struct iwl_trans_config - transport configuration * * @op_mode: pointer to the upper layer. @@ -321,6 +331,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) * @n_no_reclaim_cmds: # of commands in list * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs, * if unset 4k will be the RX buffer size + * @bc_table_dword: set to true if the BC table expects the byte count to be + * in DWORD (as opposed to bytes) * @queue_watchdog_timeout: time (in ms) after which queues * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries @@ -335,6 +347,7 @@ struct iwl_trans_config { int n_no_reclaim_cmds; bool rx_buf_size_8k; + bool bc_table_dword; unsigned int queue_watchdog_timeout; const char **command_names; }; @@ -360,9 +373,12 @@ struct iwl_trans; * May sleep * @stop_device:stops the whole device (embedded CPU put to reset) * May sleep - * @wowlan_suspend: put the device into the correct mode for WoWLAN during + * @d3_suspend: put the device into the correct mode for WoWLAN during * suspend. This is optional, if not implemented WoWLAN will not be * supported. This callback may sleep. + * @d3_resume: resume the device after WoWLAN, enabling the opmode to + * talk to the WoWLAN image to get its status. This is optional, if not + * implemented WoWLAN will not be supported. This callback may sleep. * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted. * If RFkill is asserted in the middle of a SYNC host command, it must * return -ERFKILL straight away. @@ -387,20 +403,27 @@ struct iwl_trans; * @read32: read a u32 register at offset ofs from the BAR * @read_prph: read a DWORD from a periphery register * @write_prph: write a DWORD to a periphery register + * @read_mem: read device's SRAM in DWORD + * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory + * will be zeroed. * @configure: configure parameters required by the transport layer from * the op_mode. May be called several times before start_fw, can't be * called after that. * @set_pmi: set the power pmi state + * @grab_nic_access: wake the NIC to be able to access non-HBUS regs + * @release_nic_access: let the NIC go to sleep */ struct iwl_trans_ops { int (*start_hw)(struct iwl_trans *iwl_trans); void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); - int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); + int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, + bool run_in_rfkill); void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); void (*stop_device)(struct iwl_trans *trans); - void (*wowlan_suspend)(struct iwl_trans *trans); + void (*d3_suspend)(struct iwl_trans *trans); + int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status); int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); @@ -424,9 +447,15 @@ struct iwl_trans_ops { u32 (*read32)(struct iwl_trans *trans, u32 ofs); u32 (*read_prph)(struct iwl_trans *trans, u32 ofs); void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val); + int (*read_mem)(struct iwl_trans *trans, u32 addr, + void *buf, int dwords); + int (*write_mem)(struct iwl_trans *trans, u32 addr, + void *buf, int dwords); void (*configure)(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg); void (*set_pmi)(struct iwl_trans *trans, bool state); + bool (*grab_nic_access)(struct iwl_trans *trans, bool silent); + void (*release_nic_access)(struct iwl_trans *trans); }; /** @@ -528,13 +557,14 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr) } static inline int iwl_trans_start_fw(struct iwl_trans *trans, - const struct fw_img *fw) + const struct fw_img *fw, + bool run_in_rfkill) { might_sleep(); WARN_ON_ONCE(!trans->rx_mpdu_cmd); - return trans->ops->start_fw(trans, fw); + return trans->ops->start_fw(trans, fw, run_in_rfkill); } static inline void iwl_trans_stop_device(struct iwl_trans *trans) @@ -546,10 +576,17 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) trans->state = IWL_TRANS_NO_FW; } -static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans) +static inline void iwl_trans_d3_suspend(struct iwl_trans *trans) +{ + might_sleep(); + trans->ops->d3_suspend(trans); +} + +static inline int iwl_trans_d3_resume(struct iwl_trans *trans, + enum iwl_d3_status *status) { might_sleep(); - trans->ops->wowlan_suspend(trans); + return trans->ops->d3_resume(trans, status); } static inline int iwl_trans_send_cmd(struct iwl_trans *trans, @@ -636,7 +673,7 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, - struct dentry *dir) + struct dentry *dir) { return trans->ops->dbgfs_register(trans, dir); } @@ -679,11 +716,57 @@ static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, return trans->ops->write_prph(trans, ofs, val); } +static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, + void *buf, int dwords) +{ + return trans->ops->read_mem(trans, addr, buf, dwords); +} + +#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ + do { \ + if (__builtin_constant_p(bufsize)) \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\ + } while (0) + +static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr) +{ + u32 value; + + if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1))) + return 0xa5a5a5a5; + + return value; +} + +static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, + void *buf, int dwords) +{ + return trans->ops->write_mem(trans, addr, buf, dwords); +} + +static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr, + u32 val) +{ + return iwl_trans_write_mem(trans, addr, &val, 1); +} + static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) { trans->ops->set_pmi(trans, state); } +#define iwl_trans_grab_nic_access(trans, silent) \ + __cond_lock(nic_access, \ + likely((trans)->ops->grab_nic_access(trans, silent))) + +static inline void __releases(nic_access) +iwl_trans_release_nic_access(struct iwl_trans *trans) +{ + trans->ops->release_nic_access(trans); + __release(nic_access); +} + /***************************************************** * driver (transport) register/unregister functions ******************************************************/ diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index d91d2e8c62f5..20735a008cab 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -222,8 +222,6 @@ struct iwl_txq { * @rx_replenish: work that will be called when buffers need to be allocated * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area - * @irq - the irq number for the device - * @irq_requested: true when the irq has been requested * @scd_base_addr: scheduler sram base address in SRAM * @scd_bc_tbls: pointer to the byte count table of the scheduler * @kw: keep warm address @@ -234,6 +232,7 @@ struct iwl_txq { * @status - transport specific status flags * @cmd_queue - command queue number * @rx_buf_size_8k: 8 kB RX buffer size + * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @rx_page_order: page order for receive buffer size * @wd_timeout: queue watchdog timeout (jiffies) */ @@ -249,11 +248,9 @@ struct iwl_trans_pcie { int ict_index; u32 inta; bool use_ict; - bool irq_requested; struct tasklet_struct irq_tasklet; struct isr_statistics isr_stats; - unsigned int irq; spinlock_t irq_lock; u32 inta_mask; u32 scd_base_addr; @@ -279,6 +276,7 @@ struct iwl_trans_pcie { u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; bool rx_buf_size_8k; + bool bc_table_dword; u32 rx_page_order; const char **command_names; @@ -359,6 +357,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, int handler_status); void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); +void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); + /***************************************************** * Error handling ******************************************************/ diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index dad4c4aad91f..96013030fcc7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -436,7 +436,7 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans) err_rb_stts: dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, rxq->bd, rxq->bd_dma); - memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd_dma = 0; rxq->bd = NULL; err_bd: return -ENOMEM; @@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) /* Stop Rx DMA */ iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + /* reset and flush pointers */ + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0); + iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0); + iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0); /* Reset driver's Rx queue write index */ iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); @@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - int i, err; unsigned long flags; @@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) rxq->read = rxq->write = 0; rxq->write_actual = 0; rxq->free_count = 0; + memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); spin_unlock_irqrestore(&rxq->lock, flags); iwl_pcie_rx_replenish(trans); @@ -545,13 +549,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) return; } + cancel_work_sync(&trans_pcie->rx_replenish); + spin_lock_irqsave(&rxq->lock, flags); iwl_pcie_rxq_free_rbs(trans); spin_unlock_irqrestore(&rxq->lock, flags); dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, rxq->bd, rxq->bd_dma); - memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd_dma = 0; rxq->bd = NULL; if (rxq->rb_stts) @@ -560,7 +566,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) rxq->rb_stts, rxq->rb_stts_dma); else IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); - memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); + rxq->rb_stts_dma = 0; rxq->rb_stts = NULL; } diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 35708b959ad6..c57641eb83d5 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -75,21 +75,16 @@ #include "iwl-agn-hw.h" #include "internal.h" -static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans) +static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) { -/* - * (for documentation purposes) - * to set power to V_AUX, do: - - if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) - iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - */ - - iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); + if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) + iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + else + iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); } /* PCI registers */ @@ -259,7 +254,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans) spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - iwl_pcie_set_pwr_vmain(trans); + iwl_pcie_set_pwr(trans, false); iwl_op_mode_nic_config(trans->op_mode); @@ -435,7 +430,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, } static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, - const struct fw_img *fw) + const struct fw_img *fw, bool run_in_rfkill) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; @@ -454,7 +449,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* If platform's RF_KILL switch is NOT set to KILL */ hw_rfkill = iwl_is_rfkill_set(trans); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); - if (hw_rfkill) + if (hw_rfkill && !run_in_rfkill) return -ERFKILL; iwl_write32(trans, CSR_INT, 0xFFFFFFFF); @@ -534,12 +529,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) iwl_enable_rfkill_int(trans); - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(trans_pcie->irq); - tasklet_kill(&trans_pcie->irq_tasklet); - - cancel_work_sync(&trans_pcie->rx_replenish); - /* stop and reset the on-board processor */ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); @@ -551,46 +540,87 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) clear_bit(STATUS_RFKILL, &trans_pcie->status); } -static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) +static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) { /* let the ucode operate on its own */ iwl_write32(trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); iwl_disable_interrupts(trans); + iwl_pcie_disable_ict(trans); + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* + * reset TX queues -- some of their registers reset during S3 + * so if we don't reset everything here the D3 image would try + * to execute some invalid memory upon resume + */ + iwl_trans_pcie_tx_reset(trans); + + iwl_pcie_set_pwr(trans, true); } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) +static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, + enum iwl_d3_status *status) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int err; - bool hw_rfkill; + u32 val; + int ret; - trans_pcie->inta_mask = CSR_INI_SET_MASK; + iwl_pcie_set_pwr(trans, false); - if (!trans_pcie->irq_requested) { - tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) - iwl_pcie_tasklet, (unsigned long)trans); + val = iwl_read32(trans, CSR_RESET); + if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { + *status = IWL_D3_STATUS_RESET; + return 0; + } - iwl_pcie_alloc_ict(trans); + /* + * Also enables interrupts - none will happen as the device doesn't + * know we're waking it up, only when the opmode actually tells it + * after this call. + */ + iwl_pcie_reset_ict(trans); - err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict, - IRQF_SHARED, DRV_NAME, trans); - if (err) { - IWL_ERR(trans, "Error allocating IRQ %d\n", - trans_pcie->irq); - goto error; - } + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - trans_pcie->irq_requested = true; + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (ret) { + IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); + return ret; } + iwl_trans_pcie_tx_reset(trans); + + ret = iwl_pcie_rx_init(trans); + if (ret) { + IWL_ERR(trans, "Failed to resume the device (RX reset)\n"); + return ret; + } + + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); + + *status = IWL_D3_STATUS_ALIVE; + return 0; +} + +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) +{ + bool hw_rfkill; + int err; + err = iwl_pcie_prepare_card_hw(trans); if (err) { IWL_ERR(trans, "Error while preparing HW: %d\n", err); - goto err_free_irq; + return err; } iwl_pcie_apm_init(trans); @@ -601,15 +631,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) hw_rfkill = iwl_is_rfkill_set(trans); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); - return err; - -err_free_irq: - trans_pcie->irq_requested = false; - free_irq(trans_pcie->irq, trans); -error: - iwl_pcie_free_ict(trans); - tasklet_kill(&trans_pcie->irq_tasklet); - return err; + return 0; } static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, @@ -703,19 +725,21 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, msecs_to_jiffies(trans_cfg->queue_watchdog_timeout); trans_pcie->command_names = trans_cfg->command_names; + trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; } void iwl_trans_pcie_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + synchronize_irq(trans_pcie->pci_dev->irq); + tasklet_kill(&trans_pcie->irq_tasklet); + iwl_pcie_tx_free(trans); iwl_pcie_rx_free(trans); - if (trans_pcie->irq_requested == true) { - free_irq(trans_pcie->irq, trans); - iwl_pcie_free_ict(trans); - } + free_irq(trans_pcie->pci_dev->irq, trans); + iwl_pcie_free_ict(trans); pci_disable_msi(trans_pcie->pci_dev); iounmap(trans_pcie->hw_base); @@ -751,13 +775,112 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) hw_rfkill = iwl_is_rfkill_set(trans); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); - if (!hw_rfkill) - iwl_enable_interrupts(trans); - return 0; } #endif /* CONFIG_PM_SLEEP */ +static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) +{ + int ret; + + lockdep_assert_held(&trans->reg_lock); + + /* this bit wakes up the NIC */ + __iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + if (unlikely(ret < 0)) { + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + if (!silent) { + u32 val = iwl_read32(trans, CSR_GP_CNTRL); + WARN_ONCE(1, + "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", + val); + return false; + } + } + + return true; +} + +static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) +{ + lockdep_assert_held(&trans->reg_lock); + __iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + /* + * Above we read the CSR_GP_CNTRL register, which will flush + * any previous writes, but we need the write that clears the + * MAC_ACCESS_REQ bit to be performed before any other writes + * scheduled on different CPUs (after we drop reg_lock). + */ + mmiowb(); +} + +static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, + void *buf, int dwords) +{ + unsigned long flags; + int offs, ret = 0; + u32 *vals = buf; + + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { + iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); + for (offs = 0; offs < dwords; offs++) + vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + iwl_trans_release_nic_access(trans); + } else { + ret = -EBUSY; + } + spin_unlock_irqrestore(&trans->reg_lock, flags); + return ret; +} + +static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, + void *buf, int dwords) +{ + unsigned long flags; + int offs, ret = 0; + u32 *vals = buf; + + spin_lock_irqsave(&trans->reg_lock, flags); + if (iwl_trans_grab_nic_access(trans, false)) { + iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); + for (offs = 0; offs < dwords; offs++) + iwl_write32(trans, HBUS_TARG_MEM_WDAT, + vals ? vals[offs] : 0); + iwl_trans_release_nic_access(trans); + } else { + ret = -EBUSY; + } + spin_unlock_irqrestore(&trans->reg_lock, flags); + return ret; +} + #define IWL_FLUSH_WAIT_MS 2000 static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) @@ -767,6 +890,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) struct iwl_queue *q; int cnt; unsigned long now = jiffies; + u32 scd_sram_addr; + u8 buf[16]; int ret = 0; /* waiting for all the tx frames complete might take a while */ @@ -780,11 +905,50 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans) msleep(1); if (q->read_ptr != q->write_ptr) { - IWL_ERR(trans, "fail to flush all tx fifo queues\n"); + IWL_ERR(trans, + "fail to flush all tx fifo queues Q %d\n", cnt); ret = -ETIMEDOUT; break; } } + + if (!ret) + return 0; + + IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", + txq->q.read_ptr, txq->q.write_ptr); + + scd_sram_addr = trans_pcie->scd_base_addr + + SCD_TX_STTS_QUEUE_OFFSET(txq->q.id); + iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); + + iwl_print_hex_error(trans, buf, sizeof(buf)); + + for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++) + IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt, + iwl_read_direct32(trans, FH_TX_TRB_REG(cnt))); + + for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { + u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt)); + u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; + bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); + u32 tbl_dw = + iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr + + SCD_TRANS_TBL_OFFSET_QUEUE(cnt)); + + if (cnt & 0x1) + tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; + else + tbl_dw = tbl_dw & 0x0000FFFF; + + IWL_ERR(trans, + "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", + cnt, active ? "" : "in", fifo, tbl_dw, + iwl_read_prph(trans, + SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1), + iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); + } + return ret; } @@ -1212,7 +1376,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { .start_fw = iwl_trans_pcie_start_fw, .stop_device = iwl_trans_pcie_stop_device, - .wowlan_suspend = iwl_trans_pcie_wowlan_suspend, + .d3_suspend = iwl_trans_pcie_d3_suspend, + .d3_resume = iwl_trans_pcie_d3_resume, .send_cmd = iwl_trans_pcie_send_hcmd, @@ -1235,8 +1400,12 @@ static const struct iwl_trans_ops trans_ops_pcie = { .read32 = iwl_trans_pcie_read32, .read_prph = iwl_trans_pcie_read_prph, .write_prph = iwl_trans_pcie_write_prph, + .read_mem = iwl_trans_pcie_read_mem, + .write_mem = iwl_trans_pcie_write_mem, .configure = iwl_trans_pcie_configure, .set_pmi = iwl_trans_pcie_set_pmi, + .grab_nic_access = iwl_trans_pcie_grab_nic_access, + .release_nic_access = iwl_trans_pcie_release_nic_access }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, @@ -1318,7 +1487,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } trans->dev = &pdev->dev; - trans_pcie->irq = pdev->irq; trans_pcie->pci_dev = pdev; trans->hw_rev = iwl_read32(trans, CSR_HW_REV); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; @@ -1344,8 +1512,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, if (!trans->dev_cmd_pool) goto out_pci_disable_msi; + trans_pcie->inta_mask = CSR_INI_SET_MASK; + + tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) + iwl_pcie_tasklet, (unsigned long)trans); + + if (iwl_pcie_alloc_ict(trans)) + goto out_free_cmd_pool; + + err = request_irq(pdev->irq, iwl_pcie_isr_ict, + IRQF_SHARED, DRV_NAME, trans); + if (err) { + IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); + goto out_free_ict; + } + return trans; +out_free_ict: + iwl_pcie_free_ict(trans); +out_free_cmd_pool: + kmem_cache_destroy(trans->dev_cmd_pool); out_pci_disable_msi: pci_disable_msi(pdev); out_pci_release_regions: diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 6c5b867c353a..a93f06762b96 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -160,7 +160,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", txq->q.read_ptr, txq->q.write_ptr); - iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); + iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); iwl_print_hex_error(trans, buf, sizeof(buf)); @@ -173,9 +173,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); u32 tbl_dw = - iwl_read_targ_mem(trans, - trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE(i)); + iwl_trans_read_mem32(trans, + trans_pcie->scd_base_addr + + SCD_TRANS_TBL_OFFSET_QUEUE(i)); if (i & 0x1) tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; @@ -237,7 +237,10 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, break; } - bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); + if (trans_pcie->bc_table_dword) + len = DIV_ROUND_UP(len, 4); + + bc_ent = cpu_to_le16(len | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; @@ -306,6 +309,9 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) return; } + IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, + txq->q.write_ptr); + iwl_write_direct32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); @@ -612,7 +618,7 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) if (txq->q.n_bd) { dma_free_coherent(dev, sizeof(struct iwl_tfd) * txq->q.n_bd, txq->tfds, txq->q.dma_addr); - memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); + txq->q.dma_addr = 0; } kfree(txq->entries); @@ -638,9 +644,11 @@ static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask) void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 a; + int nq = trans->cfg->base_params->num_of_queues; int chan; u32 reg_val; + int clear_dwords = (SCD_TRANS_TBL_OFFSET_QUEUE(nq) - + SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(u32); /* make sure all queue are not stopped/used */ memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); @@ -652,20 +660,10 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) WARN_ON(scd_base_addr != 0 && scd_base_addr != trans_pcie->scd_base_addr); - a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; - /* reset conext data memory */ - for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; - a += 4) - iwl_write_targ_mem(trans, a, 0); - /* reset tx status memory */ - for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; - a += 4) - iwl_write_targ_mem(trans, a, 0); - for (; a < trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE( - trans->cfg->base_params->num_of_queues); - a += 4) - iwl_write_targ_mem(trans, a, 0); + /* reset context data, TX status and translation data */ + iwl_trans_write_mem(trans, trans_pcie->scd_base_addr + + SCD_CONTEXT_MEM_LOWER_BOUND, + NULL, clear_dwords); iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, trans_pcie->scd_bc_tbls.dma >> 10); @@ -697,6 +695,29 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } +void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int txq_id; + + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; + txq_id++) { + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + + iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + iwl_pcie_txq_unmap(trans, txq_id); + txq->q.read_ptr = 0; + txq->q.write_ptr = 0; + } + + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, + trans_pcie->kw.dma >> 4); + + iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr); +} + /* * iwl_pcie_tx_stop - Stop all Tx DMA channels */ @@ -1002,14 +1023,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, tbl_dw_addr = trans_pcie->scd_base_addr + SCD_TRANS_TBL_OFFSET_QUEUE(txq_id); - tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr); + tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr); if (txq_id & 0x1) tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); else tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); - iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw); + iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw); return 0; } @@ -1068,9 +1089,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); /* Set up Tx window size and frame limit for this queue */ - iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + + iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0); - iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + + iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | @@ -1101,8 +1122,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) iwl_pcie_txq_set_inactive(trans, txq_id); - _iwl_write_targ_mem_dwords(trans, stts_addr, - zero_val, ARRAY_SIZE(zero_val)); + iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, + ARRAY_SIZE(zero_val)); iwl_pcie_txq_unmap(trans, txq_id); @@ -1642,10 +1663,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); - IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", - le16_to_cpu(dev_cmd->hdr.sequence)); - IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); - /* Set up entry for this TFD in Tx byte-count array */ iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b6e2caa024a7..b73e497fe770 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -363,6 +363,8 @@ struct mac80211_hwsim_data { /* difference between this hw's clock and the real clock, in usecs */ s64 tsf_offset; s64 bcn_delta; + /* absolute beacon transmission time. Used to cover up "tx" delay. */ + u64 abs_bcn_ts; }; @@ -410,15 +412,19 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +static inline u64 mac80211_hwsim_get_tsf_raw(void) +{ + return ktime_to_us(ktime_get_real()); +} + static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) { - struct timeval tv = ktime_to_timeval(ktime_get_real()); - u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec; + u64 now = mac80211_hwsim_get_tsf_raw(); return cpu_to_le64(now + data->tsf_offset); } static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif) { struct mac80211_hwsim_data *data = hw->priv; return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); @@ -705,7 +711,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rx_status rx_status; - struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); + u64 now; memset(&rx_status, 0, sizeof(rx_status)); rx_status.flag |= RX_FLAG_MACTIME_START; @@ -731,11 +737,23 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, secpath_reset(skb); nf_reset(skb); + /* + * Get absolute mactime here so all HWs RX at the "same time", and + * absolute TX time for beacon mactime so the timestamp matches. + * Giving beacons a different mactime than non-beacons looks messy, but + * it helps the Toffset be exact and a ~10us mactime discrepancy + * probably doesn't really matter. + */ + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + now = data->abs_bcn_ts; + else + now = mac80211_hwsim_get_tsf_raw(); + /* Copy skb to all enabled radios that are on the current frequency */ spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { struct sk_buff *nskb; - struct ieee80211_mgmt *mgmt; struct tx_iter_data tx_iter_data = { .receive = false, .channel = chan, @@ -787,17 +805,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, if (mac80211_hwsim_addr_match(data2, hdr->addr1)) ack = true; - /* set bcn timestamp relative to receiver mactime */ - rx_status.mactime = - le64_to_cpu(__mac80211_hwsim_get_tsf(data2)); - mgmt = (struct ieee80211_mgmt *) nskb->data; - if (ieee80211_is_beacon(mgmt->frame_control) || - ieee80211_is_probe_resp(mgmt->frame_control)) - mgmt->u.beacon.timestamp = cpu_to_le64( - rx_status.mactime + - (data->tsf_offset - data2->tsf_offset) + - 24 * 8 * 10 / txrate->bitrate); - + rx_status.mactime = now + data2->tsf_offset; #if 0 /* * Don't enable this code by default as the OUI 00:00:00 @@ -987,7 +995,11 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct ieee80211_vif *vif) { - struct ieee80211_hw *hw = arg; + struct mac80211_hwsim_data *data = arg; + struct ieee80211_hw *hw = data->hw; + struct ieee80211_tx_info *info; + struct ieee80211_rate *txrate; + struct ieee80211_mgmt *mgmt; struct sk_buff *skb; hwsim_check_magic(vif); @@ -1000,6 +1012,15 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, skb = ieee80211_beacon_get(hw, vif); if (skb == NULL) return; + info = IEEE80211_SKB_CB(skb); + txrate = ieee80211_get_tx_rate(hw, info); + + mgmt = (struct ieee80211_mgmt *) skb->data; + /* fake header transmission time */ + data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw(); + mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts + + data->tsf_offset + + 24 * 8 * 10 / txrate->bitrate); mac80211_hwsim_tx_frame(hw, skb, rcu_dereference(vif->chanctx_conf)->def.chan); @@ -1020,7 +1041,7 @@ mac80211_hwsim_beacon(struct hrtimer *timer) ieee80211_iterate_active_interfaces_atomic( hw, IEEE80211_IFACE_ITER_NORMAL, - mac80211_hwsim_beacon_tx, hw); + mac80211_hwsim_beacon_tx, data); /* beacon at new TBTT + beacon interval */ if (data->bcn_delta) { diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 245a371f1a43..9cd6216c61e6 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -53,7 +53,9 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, sizeof(sband->ht_cap.mcs)); if (priv->bss_mode == NL80211_IFTYPE_STATION || - sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && + (priv->adapter->sec_chan_offset != + IEEE80211_HT_PARAM_CHA_SEC_NONE))) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 68d52cfc1ebd..af8fe6352eed 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -278,14 +278,16 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; case -1: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", __func__, ret); adapter->dbg.num_tx_host_to_card_failure++; mwifiex_write_data_complete(adapter, skb_aggr, 1, ret); return 0; case -EINPROGRESS: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; break; case 0: mwifiex_write_data_complete(adapter, skb_aggr, 1, ret); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a838ddecd91a..dc0c2ddd5d48 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1325,6 +1325,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, } mwifiex_set_ht_params(priv, bss_cfg, params); + mwifiex_set_wmm_params(priv, bss_cfg, params); if (params->inactivity_timeout > 0) { /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ @@ -2259,6 +2260,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index e9357d87d327..e8a569aaa2e8 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -26,6 +26,7 @@ #include <linux/wait.h> #include <linux/timer.h> #include <linux/ieee80211.h> +#include <net/mac80211.h> #define MWIFIEX_MAX_BSS_NUM (3) @@ -58,6 +59,8 @@ #define MWIFIEX_RTS_MAX_VALUE (2347) #define MWIFIEX_FRAG_MIN_VALUE (256) #define MWIFIEX_FRAG_MAX_VALUE (2346) +#define MWIFIEX_WMM_VERSION 0x01 +#define MWIFIEX_WMM_SUBTYPE 0x01 #define MWIFIEX_RETRY_LIMIT 14 #define MWIFIEX_SDIO_BLOCK_SIZE 256 @@ -126,4 +129,19 @@ enum mwifiex_wmm_ac_e { WMM_AC_VI, WMM_AC_VO } __packed; + +struct ieee_types_wmm_ac_parameters { + u8 aci_aifsn_bitmap; + u8 ecw_bitmap; + __le16 tx_op_limit; +} __packed; + +struct mwifiex_types_wmm_info { + u8 oui[4]; + u8 subtype; + u8 version; + u8 qos_info; + u8 reserved; + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS]; +} __packed; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 4dc8e2e9a889..41c85dd78084 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1131,12 +1131,6 @@ struct ieee_types_vendor_header { u8 version; } __packed; -struct ieee_types_wmm_ac_parameters { - u8 aci_aifsn_bitmap; - u8 ecw_bitmap; - __le16 tx_op_limit; -} __packed; - struct ieee_types_wmm_parameter { /* * WMM Parameter IE - Vendor Specific Header: @@ -1186,6 +1180,11 @@ struct mwifiex_ie_types_htcap { struct ieee80211_ht_cap ht_cap; } __packed; +struct mwifiex_ie_types_wmmcap { + struct mwifiex_ie_types_header header; + struct mwifiex_types_wmm_info wmm_info; +} __packed; + struct mwifiex_ie_types_htinfo { struct mwifiex_ie_types_header header; struct ieee80211_ht_operation ht_oper; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 39f03ce5a5b1..e00b8060aff7 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -591,6 +591,12 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) return -1; } } + + if (adapter->if_ops.init_fw_port) { + if (adapter->if_ops.init_fw_port(adapter)) + return -1; + } + for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 4e31c6013ebe..6095b3e53f4e 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -20,7 +20,6 @@ #ifndef _MWIFIEX_IOCTL_H_ #define _MWIFIEX_IOCTL_H_ -#include <net/mac80211.h> #include <net/lib80211.h> enum { @@ -107,6 +106,8 @@ struct mwifiex_uap_bss_param { u8 rates[MWIFIEX_SUPPORTED_RATES]; u32 sta_ao_timer; u32 ps_sta_ao_timer; + u8 qos_info; + struct mwifiex_types_wmm_info wmm_info; }; enum { diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 88664ae667ba..3c7cabeddf76 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -969,6 +969,16 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, priv->adapter->config_bands); mwifiex_fill_cap_info(priv, radio_type, ht_cap); + if (adapter->sec_chan_offset == + IEEE80211_HT_PARAM_CHA_SEC_NONE) { + u16 tmp_ht_cap; + + tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); + tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; + ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); + } + pos += sizeof(struct mwifiex_ie_types_htcap); cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 1b3cfc821940..51044e3ea89b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -599,8 +599,10 @@ struct mwifiex_if_ops { int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*init_fw_port) (struct mwifiex_adapter *); int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); void (*card_reset) (struct mwifiex_adapter *); + int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); }; struct mwifiex_adapter { @@ -890,6 +892,10 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv, struct cfg80211_ap_settings *params); void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_ap_settings *params); +void +mwifiex_set_wmm_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); /* * This function checks if the queuing is RA based or not. diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 13fbc4eb1595..3da89b456c13 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -39,17 +39,20 @@ static struct semaphore add_remove_card_sem; static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter); static int mwifiex_pcie_resume(struct pci_dev *pdev); -/* - * This function is called after skb allocation to update - * "skb->cb" with physical address of data pointer. - */ -static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb) +static int +mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, + int size, int flags) { - phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); - - *buf_pa = (phys_addr_t)virt_to_phys(skb->data); + struct pcie_service_card *card = adapter->card; + dma_addr_t buf_pa; - return buf_pa; + buf_pa = pci_map_single(card->dev, skb->data, size, flags); + if (pci_dma_mapping_error(card->dev, buf_pa)) { + dev_err(adapter->dev, "failed to map pci memory!\n"); + return -1; + } + memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t)); + return 0; } /* @@ -60,8 +63,8 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) u32 *cookie_addr; struct pcie_service_card *card = adapter->card; - if (card->sleep_cookie) { - cookie_addr = (u32 *)card->sleep_cookie->data; + if (card->sleep_cookie_vbase) { + cookie_addr = (u32 *)card->sleep_cookie_vbase; dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n", *cookie_addr); if (*cookie_addr == FW_AWAKE_COOKIE) @@ -366,9 +369,7 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter) static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - struct sk_buff *skb; int i; - phys_addr_t *buf_pa; /* * driver maintaines the write pointer and firmware maintaines the read @@ -384,16 +385,18 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) MWIFIEX_MAX_TXRX_BD; dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", card->txbd_ring_size); - card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL); + card->txbd_ring_vbase = pci_alloc_consistent(card->dev, + card->txbd_ring_size, + &card->txbd_ring_pbase); if (!card->txbd_ring_vbase) { - dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n"); + dev_err(adapter->dev, + "allocate consistent memory (%d bytes) failed!\n", + card->txbd_ring_size); return -ENOMEM; } - card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase); - dev_dbg(adapter->dev, "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n", - card->txbd_ring_vbase, (u32)card->txbd_ring_pbase, + card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase, (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size); for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { @@ -402,24 +405,9 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) (sizeof(struct mwifiex_pcie_buf_desc) * i)); - /* Allocate buffer here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); - if (!skb) { - dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n"); - kfree(card->txbd_ring_vbase); - return -ENOMEM; - } - buf_pa = mwifiex_update_sk_buff_pa(skb); - - skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); - dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, " - "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", - skb, skb->data, (u32)*buf_pa, - (u32)(((u64)*buf_pa >> 32)), skb->len); - - card->tx_buf_list[i] = skb; - card->txbd_ring[i]->paddr = *buf_pa; - card->txbd_ring[i]->len = (u16)skb->len; + card->tx_buf_list[i] = NULL; + card->txbd_ring[i]->paddr = 0; + card->txbd_ring[i]->len = 0; card->txbd_ring[i]->flags = 0; } @@ -429,11 +417,16 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; int i; for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - if (card->tx_buf_list[i]) - dev_kfree_skb_any(card->tx_buf_list[i]); + if (card->tx_buf_list[i]) { + skb = card->tx_buf_list[i]; + pci_unmap_single(card->dev, card->txbd_ring[i]->paddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } card->tx_buf_list[i] = NULL; card->txbd_ring[i]->paddr = 0; card->txbd_ring[i]->len = 0; @@ -441,11 +434,15 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) card->txbd_ring[i] = NULL; } - kfree(card->txbd_ring_vbase); + if (card->txbd_ring_vbase) + pci_free_consistent(card->dev, card->txbd_ring_size, + card->txbd_ring_vbase, + card->txbd_ring_pbase); card->txbd_ring_size = 0; card->txbd_wrptr = 0; card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; card->txbd_ring_vbase = NULL; + card->txbd_ring_pbase = 0; return 0; } @@ -458,7 +455,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; struct sk_buff *skb; int i; - phys_addr_t *buf_pa; + dma_addr_t buf_pa; /* * driver maintaines the read pointer and firmware maintaines the write @@ -472,13 +469,15 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) MWIFIEX_MAX_TXRX_BD; dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", card->rxbd_ring_size); - card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL); + card->rxbd_ring_vbase = pci_alloc_consistent(card->dev, + card->rxbd_ring_size, + &card->rxbd_ring_pbase); if (!card->rxbd_ring_vbase) { - dev_err(adapter->dev, "Unable to allocate buffer for " - "rxbd_ring.\n"); + dev_err(adapter->dev, + "allocate consistent memory (%d bytes) failed!\n", + card->rxbd_ring_size); return -ENOMEM; } - card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase); dev_dbg(adapter->dev, "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n", @@ -500,16 +499,20 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) kfree(card->rxbd_ring_vbase); return -ENOMEM; } - buf_pa = mwifiex_update_sk_buff_pa(skb); - skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); + if (mwifiex_map_pci_memory(adapter, skb, + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, " "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", - skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), + skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), skb->len); card->rx_buf_list[i] = skb; - card->rxbd_ring[i]->paddr = *buf_pa; + card->rxbd_ring[i]->paddr = buf_pa; card->rxbd_ring[i]->len = (u16)skb->len; card->rxbd_ring[i]->flags = 0; } @@ -523,11 +526,17 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; int i; for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - if (card->rx_buf_list[i]) - dev_kfree_skb_any(card->rx_buf_list[i]); + if (card->rx_buf_list[i]) { + skb = card->rx_buf_list[i]; + pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr , + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + } card->rx_buf_list[i] = NULL; card->rxbd_ring[i]->paddr = 0; card->rxbd_ring[i]->len = 0; @@ -535,11 +544,15 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) card->rxbd_ring[i] = NULL; } - kfree(card->rxbd_ring_vbase); + if (card->rxbd_ring_vbase) + pci_free_consistent(card->dev, card->rxbd_ring_size, + card->rxbd_ring_vbase, + card->rxbd_ring_pbase); card->rxbd_ring_size = 0; card->rxbd_wrptr = 0; card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; card->rxbd_ring_vbase = NULL; + card->rxbd_ring_pbase = 0; return 0; } @@ -552,7 +565,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; struct sk_buff *skb; int i; - phys_addr_t *buf_pa; + dma_addr_t buf_pa; /* * driver maintaines the read pointer and firmware maintaines the write @@ -566,13 +579,15 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) MWIFIEX_MAX_EVT_BD; dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", card->evtbd_ring_size); - card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL); + card->evtbd_ring_vbase = pci_alloc_consistent(card->dev, + card->evtbd_ring_size, + &card->evtbd_ring_pbase); if (!card->evtbd_ring_vbase) { dev_err(adapter->dev, - "Unable to allocate buffer. Terminating download\n"); + "allocate consistent memory (%d bytes) failed!\n", + card->evtbd_ring_size); return -ENOMEM; } - card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase); dev_dbg(adapter->dev, "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n", @@ -594,16 +609,20 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) kfree(card->evtbd_ring_vbase); return -ENOMEM; } - buf_pa = mwifiex_update_sk_buff_pa(skb); skb_put(skb, MAX_EVENT_SIZE); + if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, " "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", - skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), + skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32), skb->len); card->evt_buf_list[i] = skb; - card->evtbd_ring[i]->paddr = *buf_pa; + card->evtbd_ring[i]->paddr = buf_pa; card->evtbd_ring[i]->len = (u16)skb->len; card->evtbd_ring[i]->flags = 0; } @@ -617,11 +636,16 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; int i; for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { - if (card->evt_buf_list[i]) - dev_kfree_skb_any(card->evt_buf_list[i]); + if (card->evt_buf_list[i]) { + skb = card->evt_buf_list[i]; + pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr, + MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + } card->evt_buf_list[i] = NULL; card->evtbd_ring[i]->paddr = 0; card->evtbd_ring[i]->len = 0; @@ -629,11 +653,15 @@ static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) card->evtbd_ring[i] = NULL; } - kfree(card->evtbd_ring_vbase); + if (card->evtbd_ring_vbase) + pci_free_consistent(card->dev, card->evtbd_ring_size, + card->evtbd_ring_vbase, + card->evtbd_ring_pbase); card->evtbd_wrptr = 0; card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; card->evtbd_ring_size = 0; card->evtbd_ring_vbase = NULL; + card->evtbd_ring_pbase = 0; return 0; } @@ -653,21 +681,12 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) "Unable to allocate skb for command response data.\n"); return -ENOMEM; } - mwifiex_update_sk_buff_pa(skb); skb_put(skb, MWIFIEX_UPLD_SIZE); - card->cmdrsp_buf = skb; + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; - skb = NULL; - /* Allocate memory for sending command to firmware */ - skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for command data.\n"); - return -ENOMEM; - } - mwifiex_update_sk_buff_pa(skb); - skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER); - card->cmd_buf = skb; + card->cmdrsp_buf = skb; return 0; } @@ -678,18 +697,26 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) { struct pcie_service_card *card; + dma_addr_t buf_pa; if (!adapter) return 0; card = adapter->card; - if (card && card->cmdrsp_buf) + if (card && card->cmdrsp_buf) { + MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb_any(card->cmdrsp_buf); + } - if (card && card->cmd_buf) + if (card && card->cmd_buf) { + MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER, + PCI_DMA_TODEVICE); dev_kfree_skb_any(card->cmd_buf); - + } return 0; } @@ -698,27 +725,19 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) */ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) { - struct sk_buff *skb; struct pcie_service_card *card = adapter->card; - /* Allocate memory for sleep cookie */ - skb = dev_alloc_skb(sizeof(u32)); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for sleep cookie!\n"); + card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32), + &card->sleep_cookie_pbase); + if (!card->sleep_cookie_vbase) { + dev_err(adapter->dev, "pci_alloc_consistent failed!\n"); return -ENOMEM; } - mwifiex_update_sk_buff_pa(skb); - skb_put(skb, sizeof(u32)); - /* Init val of Sleep Cookie */ - *(u32 *)skb->data = FW_AWAKE_COOKIE; + *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE; dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n", - *((u32 *)skb->data)); - - /* Save the sleep cookie */ - card->sleep_cookie = skb; + *((u32 *)card->sleep_cookie_vbase)); return 0; } @@ -735,24 +754,57 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter) card = adapter->card; - if (card && card->sleep_cookie) { - dev_kfree_skb_any(card->sleep_cookie); - card->sleep_cookie = NULL; + if (card && card->sleep_cookie_vbase) { + pci_free_consistent(card->dev, sizeof(u32), + card->sleep_cookie_vbase, + card->sleep_cookie_pbase); + card->sleep_cookie_vbase = NULL; } return 0; } +/* This function flushes the TX buffer descriptor ring + * This function defined as handler is also called while cleaning TXRX + * during disconnect/ bss stop. + */ +static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + u32 rdptr; + + /* Read the TX ring read pointer set by firmware */ + if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { + dev_err(adapter->dev, + "Flush TXBD: failed to read REG_TXBD_RDPTR\n"); + return -1; + } + + if (!mwifiex_pcie_txbd_empty(card, rdptr)) { + card->txbd_flush = 1; + /* write pointer already set at last send + * send dnld-rdy intr again, wait for completion. + */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DNLD_RDY)) { + dev_err(adapter->dev, + "failed to assert dnld-rdy interrupt.\n"); + return -1; + } + } + return 0; +} + /* - * This function sends data buffer to device + * This function unmaps and frees downloaded data buffer */ -static int -mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) +static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) { + const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD; + struct sk_buff *skb; + dma_addr_t buf_pa; + u32 wrdoneidx, rdptr, unmap_count = 0; struct pcie_service_card *card = adapter->card; - u32 wrindx, rdptr; - phys_addr_t *buf_pa; - __le16 *tmp; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); @@ -760,34 +812,112 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) /* Read the TX ring read pointer set by firmware */ if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { dev_err(adapter->dev, - "SEND DATA: failed to read REG_TXBD_RDPTR\n"); + "SEND COMP: failed to read REG_TXBD_RDPTR\n"); return -1; } - wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; + dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n", + card->txbd_rdptr, rdptr); - dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr, - card->txbd_wrptr); - if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != - (rdptr & MWIFIEX_TXBD_MASK)) || - ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != - (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { - struct sk_buff *skb_data; + /* free from previous txbd_rdptr to current txbd_rdptr */ + while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) != + (rdptr & MWIFIEX_TXBD_MASK)) || + ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK; + + skb = card->tx_buf_list[wrdoneidx]; + if (skb) { + dev_dbg(adapter->dev, + "SEND COMP: Detach skb %p at txbd_rdidx=%d\n", + skb, wrdoneidx); + MWIFIEX_SKB_PACB(skb, &buf_pa); + pci_unmap_single(card->dev, buf_pa, skb->len, + PCI_DMA_TODEVICE); + + unmap_count++; + + if (card->txbd_flush) + mwifiex_write_data_complete(adapter, skb, 0, + -1); + else + mwifiex_write_data_complete(adapter, skb, 0, 0); + } + + card->tx_buf_list[wrdoneidx] = NULL; + card->txbd_ring[wrdoneidx]->paddr = 0; + card->rxbd_ring[wrdoneidx]->len = 0; + card->rxbd_ring[wrdoneidx]->flags = 0; + card->txbd_rdptr++; + + if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs) + card->txbd_rdptr = ((card->txbd_rdptr & + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); + } + + if (unmap_count) + adapter->data_sent = false; + + if (card->txbd_flush) { + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == + (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) && + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) + card->txbd_flush = 0; + else + mwifiex_clean_pcie_ring_buf(adapter); + } + + return 0; +} + +/* This function sends data buffer to device. First 4 bytes of payload + * are filled with payload length and payload type. Then this payload + * is mapped to PCI device memory. Tx ring pointers are advanced accordingly. + * Download ready interrupt to FW is deffered if Tx ring is not full and + * additional payload can be accomodated. + */ +static int +mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + struct pcie_service_card *card = adapter->card; + u32 wrindx; + int ret; + dma_addr_t buf_pa; + __le16 *tmp; + + if (!(skb->data && skb->len)) { + dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n", + __func__, skb->data, skb->len); + return -1; + } + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); + + dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", + card->txbd_rdptr, card->txbd_wrptr); + if (mwifiex_pcie_txbd_not_full(card)) { u8 *payload; adapter->data_sent = true; - skb_data = card->tx_buf_list[wrindx]; - memcpy(skb_data->data, skb->data, skb->len); - payload = skb_data->data; + payload = skb->data; tmp = (__le16 *)&payload[0]; *tmp = cpu_to_le16((u16)skb->len); tmp = (__le16 *)&payload[2]; *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA); - skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len); - skb_trim(skb_data, skb->len); - buf_pa = MWIFIEX_SKB_PACB(skb_data); - card->txbd_ring[wrindx]->paddr = *buf_pa; - card->txbd_ring[wrindx]->len = (u16)skb_data->len; + + if (mwifiex_map_pci_memory(adapter, skb, skb->len , + PCI_DMA_TODEVICE)) + return -1; + + wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; + MWIFIEX_SKB_PACB(skb, &buf_pa); + card->tx_buf_list[wrindx] = skb; + card->txbd_ring[wrindx]->paddr = buf_pa; + card->txbd_ring[wrindx]->len = (u16)skb->len; card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | MWIFIEX_BD_FLAG_LAST_DESC; @@ -802,19 +932,28 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) card->txbd_wrptr)) { dev_err(adapter->dev, "SEND DATA: failed to write REG_TXBD_WRPTR\n"); - return 0; + ret = -1; + goto done_unmap; } - - /* Send the TX ready interrupt */ - if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, - CPU_INTR_DNLD_RDY)) { - dev_err(adapter->dev, - "SEND DATA: failed to assert door-bell intr\n"); - return -1; + if ((mwifiex_pcie_txbd_not_full(card)) && + tx_param->next_pkt_len) { + /* have more packets and TxBD still can hold more */ + dev_dbg(adapter->dev, + "SEND DATA: delay dnld-rdy interrupt.\n"); + adapter->data_sent = false; + } else { + /* Send the TX ready interrupt */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DNLD_RDY)) { + dev_err(adapter->dev, + "SEND DATA: failed to assert dnld-rdy interrupt.\n"); + ret = -1; + goto done_unmap; + } } dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: " "%#x> and sent packet to firmware successfully\n", - rdptr, card->txbd_wrptr); + card->txbd_rdptr, card->txbd_wrptr); } else { dev_dbg(adapter->dev, "info: TX Ring full, can't send packets to fw\n"); @@ -827,7 +966,15 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -EBUSY; } - return 0; + return -EINPROGRESS; +done_unmap: + MWIFIEX_SKB_PACB(skb, &buf_pa); + pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE); + card->tx_buf_list[wrindx] = NULL; + card->txbd_ring[wrindx]->paddr = 0; + card->txbd_ring[wrindx]->len = 0; + card->txbd_ring[wrindx]->flags = 0; + return ret; } /* @@ -838,9 +985,13 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; u32 wrptr, rd_index; + dma_addr_t buf_pa; int ret = 0; struct sk_buff *skb_tmp = NULL; + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); + /* Read the RX ring Write pointer set by firmware */ if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { dev_err(adapter->dev, @@ -848,6 +999,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) ret = -1; goto done; } + card->rxbd_wrptr = wrptr; while (((wrptr & MWIFIEX_RXBD_MASK) != (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || @@ -855,27 +1007,50 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { struct sk_buff *skb_data; u16 rx_len; + __le16 pkt_len; rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; skb_data = card->rx_buf_list[rd_index]; + MWIFIEX_SKB_PACB(skb_data, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE); + card->rx_buf_list[rd_index] = NULL; + /* Get data length from interface header - - first byte is len, second byte is type */ - rx_len = *((u16 *)skb_data->data); + * first 2 bytes for len, next 2 bytes is for type + */ + pkt_len = *((__le16 *)skb_data->data); + rx_len = le16_to_cpu(pkt_len); + skb_put(skb_data, rx_len); dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); - skb_tmp = dev_alloc_skb(rx_len); + skb_pull(skb_data, INTF_HEADER_LEN); + mwifiex_handle_rx_packet(adapter, skb_data); + + skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); if (!skb_tmp) { - dev_dbg(adapter->dev, - "info: Failed to alloc skb for RX\n"); - ret = -EBUSY; - goto done; + dev_err(adapter->dev, + "Unable to allocate skb.\n"); + return -ENOMEM; } - skb_put(skb_tmp, rx_len); + if (mwifiex_map_pci_memory(adapter, skb_tmp, + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); + + dev_dbg(adapter->dev, + "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n", + skb_tmp, rd_index); + card->rx_buf_list[rd_index] = skb_tmp; + card->rxbd_ring[rd_index]->paddr = buf_pa; + card->rxbd_ring[rd_index]->len = skb_tmp->len; + card->rxbd_ring[rd_index]->flags = 0; - memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len); if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == MWIFIEX_MAX_TXRX_BD) { card->rxbd_rdptr = ((card->rxbd_rdptr & @@ -903,12 +1078,10 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) } dev_dbg(adapter->dev, "info: RECV DATA: Rcvd packet from fw successfully\n"); - mwifiex_handle_rx_packet(adapter, skb_tmp); + card->rxbd_wrptr = wrptr; } done: - if (ret && skb_tmp) - dev_kfree_skb_any(skb_tmp); return ret; } @@ -918,32 +1091,41 @@ done: static int mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) { - phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); + dma_addr_t buf_pa; + struct pcie_service_card *card = adapter->card; - if (!(skb->data && skb->len && *buf_pa)) { + if (!(skb->data && skb->len)) { dev_err(adapter->dev, - "Invalid parameter in %s <%p, %#x:%x, %x>\n", - __func__, skb->data, skb->len, - (u32)*buf_pa, (u32)((u64)*buf_pa >> 32)); + "Invalid parameter in %s <%p. len %d>\n", + __func__, skb->data, skb->len); return -1; } + if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); + /* Write the lower 32bits of the physical address to scratch * register 0 */ - if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) { + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) { dev_err(adapter->dev, "%s: failed to write download command to boot code.\n", __func__); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_TODEVICE); return -1; } /* Write the upper 32bits of the physical address to scratch * register 1 */ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG, - (u32)((u64)*buf_pa >> 32))) { + (u32)((u64)buf_pa >> 32))) { dev_err(adapter->dev, "%s: failed to write download command to boot code.\n", __func__); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_TODEVICE); return -1; } @@ -952,6 +1134,8 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) dev_err(adapter->dev, "%s: failed to write command len to scratch reg 2\n", __func__); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_TODEVICE); return -1; } @@ -960,22 +1144,39 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) CPU_INTR_DOOR_BELL)) { dev_err(adapter->dev, "%s: failed to assert door-bell intr\n", __func__); + pci_unmap_single(card->dev, buf_pa, + MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE); return -1; } return 0; } -/* - * This function downloads commands to the device +/* This function init rx port in firmware which in turn enables to receive data + * from device before transmitting any packet. + */ +static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ + if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) { + dev_err(adapter->dev, + "RECV DATA: failed to write REG_RXBD_RDPTR\n"); + return -1; + } + return 0; +} + +/* This function downloads commands to the device */ static int mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; int ret = 0; - phys_addr_t *cmd_buf_pa; - phys_addr_t *cmdrsp_buf_pa; + dma_addr_t cmd_buf_pa, cmdrsp_buf_pa; + u8 *payload = (u8 *)skb->data; if (!(skb->data && skb->len)) { dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n", @@ -990,17 +1191,18 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -EBUSY; } - /* Make sure a command buffer is available */ - if (!card->cmd_buf) { - dev_err(adapter->dev, "Command buffer not available\n"); - return -EBUSY; - } + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); adapter->cmd_sent = true; - /* Copy the given skb in to DMA accessable shared buffer */ - skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len); - skb_trim(card->cmd_buf, skb->len); - memcpy(card->cmd_buf->data, skb->data, skb->len); + + *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len); + *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD); + + if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE)) + return -1; + + card->cmd_buf = skb; /* To send a command, the driver will: 1. Write the 64bit physical address of the data buffer to @@ -1013,11 +1215,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) */ if (card->cmdrsp_buf) { - cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf); + MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa); /* Write the lower 32bits of the cmdrsp buffer physical address */ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, - (u32)*cmdrsp_buf_pa)) { + (u32)cmdrsp_buf_pa)) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; @@ -1026,7 +1228,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) /* Write the upper 32bits of the cmdrsp buffer physical address */ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, - (u32)((u64)*cmdrsp_buf_pa >> 32))) { + (u32)((u64)cmdrsp_buf_pa >> 32))) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; @@ -1034,9 +1236,9 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) } } - cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf); + MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa); /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */ - if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) { + if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; @@ -1044,7 +1246,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) } /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */ if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI, - (u32)((u64)*cmd_buf_pa >> 32))) { + (u32)((u64)cmd_buf_pa >> 32))) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; @@ -1083,11 +1285,22 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; struct sk_buff *skb = card->cmdrsp_buf; int count = 0; + u16 rx_len; + __le16 pkt_len; + dma_addr_t buf_pa; dev_dbg(adapter->dev, "info: Rx CMD Response\n"); + MWIFIEX_SKB_PACB(skb, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE); + + pkt_len = *((__le16 *)skb->data); + rx_len = le16_to_cpu(pkt_len); + skb_trim(skb, rx_len); + skb_pull(skb, INTF_HEADER_LEN); + if (!adapter->curr_cmd) { - skb_pull(skb, INTF_HEADER_LEN); if (adapter->ps_state == PS_STATE_SLEEP_CFM) { mwifiex_process_sleep_confirm_resp(adapter, skb->data, skb->len); @@ -1100,9 +1313,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) } memcpy(adapter->upld_buf, skb->data, min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); - skb_push(skb, INTF_HEADER_LEN); + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); } else if (mwifiex_pcie_ok_to_access_hw(adapter)) { - skb_pull(skb, INTF_HEADER_LEN); adapter->curr_cmd->resp_skb = skb; adapter->cmd_resp_received = true; /* Take the pointer and set it to CMD node and will @@ -1136,10 +1352,23 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; + dma_addr_t buf_pa; + struct sk_buff *skb_tmp; if (skb) { card->cmdrsp_buf = skb; skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + } + + skb_tmp = card->cmd_buf; + if (skb_tmp) { + MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE); + card->cmd_buf = NULL; } return 0; @@ -1153,6 +1382,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; u32 wrptr, event; + dma_addr_t buf_pa; + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); if (adapter->event_received) { dev_dbg(adapter->dev, "info: Event being processed, " @@ -1184,6 +1417,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr); skb_cmd = card->evt_buf_list[rdptr]; + MWIFIEX_SKB_PACB(skb_cmd, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE); + /* Take the pointer and set it to event pointer in adapter and will return back after event handling callback */ card->evt_buf_list[rdptr] = NULL; @@ -1228,7 +1465,7 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, int ret = 0; u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; u32 wrptr; - phys_addr_t *buf_pa; + dma_addr_t buf_pa; if (!skb) return 0; @@ -1248,9 +1485,14 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, if (!card->evt_buf_list[rdptr]) { skb_push(skb, INTF_HEADER_LEN); + if (mwifiex_map_pci_memory(adapter, skb, + MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + MWIFIEX_SKB_PACB(skb, &buf_pa); card->evt_buf_list[rdptr] = skb; - buf_pa = MWIFIEX_SKB_PACB(skb); - card->evtbd_ring[rdptr]->paddr = *buf_pa; + MWIFIEX_SKB_PACB(skb, &buf_pa); + card->evtbd_ring[rdptr]->paddr = buf_pa; card->evtbd_ring[rdptr]->len = (u16)skb->len; card->evtbd_ring[rdptr]->flags = 0; skb = NULL; @@ -1299,11 +1541,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct sk_buff *skb; u32 txlen, tx_blocks = 0, tries, len; u32 block_retry_cnt = 0; - - if (!adapter) { - pr_err("adapter structure is not valid\n"); - return -1; - } + dma_addr_t buf_pa; + struct pcie_service_card *card = adapter->card; if (!firmware || !firmware_len) { dev_err(adapter->dev, @@ -1325,7 +1564,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, ret = -ENOMEM; goto done; } - mwifiex_update_sk_buff_pa(skb); /* Perform firmware data transfer */ do { @@ -1400,6 +1638,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, ret = -1; goto done; } + + MWIFIEX_SKB_PACB(skb, &buf_pa); + /* Wait for the command done interrupt */ do { if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS, @@ -1407,11 +1648,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, dev_err(adapter->dev, "%s: Failed to read " "interrupt status during fw dnld.\n", __func__); + pci_unmap_single(card->dev, buf_pa, skb->len, + PCI_DMA_TODEVICE); ret = -1; goto done; } } while ((ireg_intr & CPU_INTR_DOOR_BELL) == CPU_INTR_DOOR_BELL); + + pci_unmap_single(card->dev, buf_pa, skb->len, + PCI_DMA_TODEVICE); + offset += txlen; } while (true); @@ -1594,39 +1841,40 @@ exit: static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) { int ret; - u32 pcie_ireg = 0; + u32 pcie_ireg; unsigned long flags; spin_lock_irqsave(&adapter->int_lock, flags); /* Clear out unused interrupts */ - adapter->int_status &= HOST_INTR_MASK; + pcie_ireg = adapter->int_status; + adapter->int_status = 0; spin_unlock_irqrestore(&adapter->int_lock, flags); - while (adapter->int_status & HOST_INTR_MASK) { - if (adapter->int_status & HOST_INTR_DNLD_DONE) { - adapter->int_status &= ~HOST_INTR_DNLD_DONE; - if (adapter->data_sent) { - dev_dbg(adapter->dev, "info: DATA sent intr\n"); - adapter->data_sent = false; - } + while (pcie_ireg & HOST_INTR_MASK) { + if (pcie_ireg & HOST_INTR_DNLD_DONE) { + pcie_ireg &= ~HOST_INTR_DNLD_DONE; + dev_dbg(adapter->dev, "info: TX DNLD Done\n"); + ret = mwifiex_pcie_send_data_complete(adapter); + if (ret) + return ret; } - if (adapter->int_status & HOST_INTR_UPLD_RDY) { - adapter->int_status &= ~HOST_INTR_UPLD_RDY; + if (pcie_ireg & HOST_INTR_UPLD_RDY) { + pcie_ireg &= ~HOST_INTR_UPLD_RDY; dev_dbg(adapter->dev, "info: Rx DATA\n"); ret = mwifiex_pcie_process_recv_data(adapter); if (ret) return ret; } - if (adapter->int_status & HOST_INTR_EVENT_RDY) { - adapter->int_status &= ~HOST_INTR_EVENT_RDY; + if (pcie_ireg & HOST_INTR_EVENT_RDY) { + pcie_ireg &= ~HOST_INTR_EVENT_RDY; dev_dbg(adapter->dev, "info: Rx EVENT\n"); ret = mwifiex_pcie_process_event_ready(adapter); if (ret) return ret; } - if (adapter->int_status & HOST_INTR_CMD_DONE) { - adapter->int_status &= ~HOST_INTR_CMD_DONE; + if (pcie_ireg & HOST_INTR_CMD_DONE) { + pcie_ireg &= ~HOST_INTR_CMD_DONE; if (adapter->cmd_sent) { dev_dbg(adapter->dev, "info: CMD sent Interrupt\n"); @@ -1654,8 +1902,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) "Write register failed\n"); return -1; } - adapter->int_status |= pcie_ireg; - adapter->int_status &= HOST_INTR_MASK; } } @@ -1687,7 +1933,7 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type, } if (type == MWIFIEX_TYPE_DATA) - return mwifiex_pcie_send_data(adapter, skb); + return mwifiex_pcie_send_data(adapter, skb, tx_param); else if (type == MWIFIEX_TYPE_CMD) return mwifiex_pcie_send_cmd(adapter, skb); @@ -1814,15 +2060,8 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; struct pci_dev *pdev = card->dev; - mwifiex_pcie_delete_sleep_cookie_buf(adapter); - mwifiex_pcie_delete_cmdrsp_buf(adapter); - mwifiex_pcie_delete_evtbd_ring(adapter); - mwifiex_pcie_delete_rxbd_ring(adapter); - mwifiex_pcie_delete_txbd_ring(adapter); - card->cmdrsp_buf = NULL; - - dev_dbg(adapter->dev, "Clearing driver ready signature\n"); if (user_rmmod) { + dev_dbg(adapter->dev, "Clearing driver ready signature\n"); if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000)) dev_err(adapter->dev, "Failed to write driver not-ready signature\n"); @@ -1879,6 +2118,13 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) if (card) { dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__); free_irq(card->dev->irq, card->dev); + + mwifiex_pcie_delete_sleep_cookie_buf(adapter); + mwifiex_pcie_delete_cmdrsp_buf(adapter); + mwifiex_pcie_delete_evtbd_ring(adapter); + mwifiex_pcie_delete_rxbd_ring(adapter); + mwifiex_pcie_delete_txbd_ring(adapter); + card->cmdrsp_buf = NULL; } } @@ -1900,6 +2146,8 @@ static struct mwifiex_if_ops pcie_ops = { .event_complete = mwifiex_pcie_event_complete, .update_mp_end_port = NULL, .cleanup_mpa_buf = NULL, + .init_fw_port = mwifiex_pcie_init_fw_port, + .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, }; /* diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 2f218f9a3fd3..37eeb2ca6b29 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -114,11 +114,12 @@ struct pcie_service_card { struct pci_dev *dev; struct mwifiex_adapter *adapter; + u8 txbd_flush; u32 txbd_wrptr; u32 txbd_rdptr; u32 txbd_ring_size; u8 *txbd_ring_vbase; - phys_addr_t txbd_ring_pbase; + dma_addr_t txbd_ring_pbase; struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; @@ -126,7 +127,7 @@ struct pcie_service_card { u32 rxbd_rdptr; u32 rxbd_ring_size; u8 *rxbd_ring_vbase; - phys_addr_t rxbd_ring_pbase; + dma_addr_t rxbd_ring_pbase; struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; @@ -134,15 +135,39 @@ struct pcie_service_card { u32 evtbd_rdptr; u32 evtbd_ring_size; u8 *evtbd_ring_vbase; - phys_addr_t evtbd_ring_pbase; + dma_addr_t evtbd_ring_pbase; struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; struct sk_buff *cmd_buf; struct sk_buff *cmdrsp_buf; - struct sk_buff *sleep_cookie; + u8 *sleep_cookie_vbase; + dma_addr_t sleep_cookie_pbase; void __iomem *pci_mmap; void __iomem *pci_mmap1; }; +static inline int +mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) +{ + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == + (rdptr & MWIFIEX_TXBD_MASK)) && + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) + return 1; + + return 0; +} + +static inline int +mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) +{ + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != + (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) || + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) + return 1; + + return 0; +} #endif /* _MWIFIEX_PCIE_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 5d87195390f8..c4607859d59d 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -931,7 +931,6 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, struct host_cmd_ds_pcie_details *host_spec = &cmd->params.pcie_host_spec; struct pcie_service_card *card = priv->adapter->card; - phys_addr_t *buf_pa; cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS); cmd->size = cpu_to_le16(sizeof(struct @@ -953,10 +952,11 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase); host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32); host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD; - if (card->sleep_cookie) { - buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie); - host_spec->sleep_cookie_addr_lo = (u32) *buf_pa; - host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32); + if (card->sleep_cookie_vbase) { + host_spec->sleep_cookie_addr_lo = + (u32)(card->sleep_cookie_pbase); + host_spec->sleep_cookie_addr_hi = + (u32)(((u64)(card->sleep_cookie_pbase)) >> 32); dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n", host_spec->sleep_cookie_addr_lo); } diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 8c80024c30ff..296faec14365 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -117,14 +117,16 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; case -1: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", ret); adapter->dbg.num_tx_host_to_card_failure++; mwifiex_write_data_complete(adapter, skb, 0, ret); break; case -EINPROGRESS: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; break; case 0: mwifiex_write_data_complete(adapter, skb, 0, ret); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 8dd72240f162..6e76a15a8950 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -219,6 +219,7 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) config->rts_threshold = 0x7FFF; config->frag_threshold = 0x7FFF; config->retry_limit = 0x7F; + config->qos_info = 0xFF; } /* This function parses BSS related parameters from structure @@ -297,6 +298,38 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) return; } +/* This function parses WMM related parameters from cfg80211_ap_settings + * structure and updates bss_config structure. + */ +void +mwifiex_set_wmm_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params) +{ + const u8 *vendor_ie; + struct ieee_types_header *wmm_ie; + u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02}; + + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, + params->beacon.tail, + params->beacon.tail_len); + if (vendor_ie) { + wmm_ie = (struct ieee_types_header *)vendor_ie; + memcpy(&bss_cfg->wmm_info, wmm_ie + 1, + sizeof(bss_cfg->wmm_info)); + priv->wmm_enabled = 1; + } else { + memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info)); + memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui)); + bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE; + bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION; + priv->wmm_enabled = 0; + } + + bss_cfg->qos_info = 0x00; + return; +} /* This function parses BSS related parameters from structure * and prepares TLVs specific to WEP encryption. * These TLVs are appended to command buffer. @@ -354,6 +387,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) struct host_cmd_tlv_rates *tlv_rates; struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer; struct mwifiex_ie_types_htcap *htcap; + struct mwifiex_ie_types_wmmcap *wmm_cap; struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; int i; u16 cmd_size = *param_size; @@ -507,6 +541,16 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) tlv += sizeof(struct mwifiex_ie_types_htcap); } + if (bss_cfg->wmm_info.qos_info != 0xFF) { + wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv; + wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC); + wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info)); + memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info, + sizeof(wmm_cap->wmm_info)); + cmd_size += sizeof(struct mwifiex_ie_types_wmmcap); + tlv += sizeof(struct mwifiex_ie_types_wmmcap); + } + if (bss_cfg->sta_ao_timer) { ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER); diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 63ac9f2d11ae..5d4a10a8a005 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -786,21 +786,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) return 0; } -/* This function reads one block of firmware data. */ -static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter, - u32 offset, u32 len, u8 *buf) -{ - if (!buf || !len) - return -1; - - if (offset + len > adapter->firmware->size) - return -1; - - memcpy(buf, adapter->firmware->data + offset, len); - - return 0; -} - static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { @@ -836,23 +821,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, dlen = 0; } else { /* copy the header of the fw_data to get the length */ - if (firmware) - memcpy(&fwdata->fw_hdr, &firmware[tlen], - sizeof(struct fw_header)); - else - mwifiex_get_fw_data(adapter, tlen, - sizeof(struct fw_header), - (u8 *)&fwdata->fw_hdr); + memcpy(&fwdata->fw_hdr, &firmware[tlen], + sizeof(struct fw_header)); dlen = le32_to_cpu(fwdata->fw_hdr.data_len); dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd); tlen += sizeof(struct fw_header); - if (firmware) - memcpy(fwdata->data, &firmware[tlen], dlen); - else - mwifiex_get_fw_data(adapter, tlen, dlen, - (u8 *)fwdata->data); + memcpy(fwdata->data, &firmware[tlen], dlen); fwdata->seq_num = cpu_to_le32(fw_seqnum); tlen += dlen; diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index f6d36b9654a0..cb2d0582bd36 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -22,16 +22,16 @@ static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) { - return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t)); + return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t)); } static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) { - return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t)); + return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t)); } -static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb) +static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa) { - return (phys_addr_t *)skb->cb; + memcpy(buf_pa, skb->cb, sizeof(dma_addr_t)); } #endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 818f871ae987..135d96df2063 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -568,6 +568,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) mwifiex_wmm_delete_all_ralist(priv); memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); + if (priv->adapter->if_ops.clean_pcie_ring) + priv->adapter->if_ops.clean_pcie_ring(priv->adapter); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } @@ -1206,13 +1208,15 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, ra_list_flags); break; case -1: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); adapter->dbg.num_tx_host_to_card_failure++; mwifiex_write_data_complete(adapter, skb, 0, ret); break; case -EINPROGRESS: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; default: break; } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 19b46fdf9f0f..a9c078899252 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -101,6 +101,18 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) #define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) +/* txpriorities are mapped with hw queues. + * Each hw queue has a txpriority. + */ +#define TOTAL_HW_TX_QUEUES 8 + +/* Each HW queue can have one AMPDU stream. + * But, because one of the hw queue is reserved, + * maximum AMPDU queues that can be created are + * one short of total tx queues. + */ +#define MWL8K_NUM_AMPDU_STREAMS (TOTAL_HW_TX_QUEUES - 1) + struct rxd_ops { int rxd_size; void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); @@ -160,7 +172,6 @@ struct mwl8k_ampdu_stream { u8 tid; u8 state; u8 idx; - u8 txq_idx; /* index of this stream in priv->txq */ }; struct mwl8k_priv { @@ -202,6 +213,8 @@ struct mwl8k_priv { int fw_mutex_depth; struct completion *hostcmd_wait; + atomic_t watchdog_event_pending; + /* lock held over TX and TX reap */ spinlock_t tx_lock; @@ -1516,6 +1529,9 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) return -EBUSY; } + if (atomic_read(&priv->watchdog_event_pending)) + return 0; + /* * The TX queues are stopped at this point, so this test * doesn't need to take ->tx_lock. @@ -1537,6 +1553,14 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) spin_unlock_bh(&priv->tx_lock); timeout = wait_for_completion_timeout(&tx_wait, msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS)); + + if (atomic_read(&priv->watchdog_event_pending)) { + spin_lock_bh(&priv->tx_lock); + priv->tx_wait = NULL; + spin_unlock_bh(&priv->tx_lock); + return 0; + } + spin_lock_bh(&priv->tx_lock); if (timeout) { @@ -1564,6 +1588,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) rc = -ETIMEDOUT; } + priv->tx_wait = NULL; spin_unlock_bh(&priv->tx_lock); return rc; @@ -1734,14 +1759,13 @@ mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) struct mwl8k_priv *priv = hw->priv; int i; - for (i = 0; i < priv->num_ampdu_queues; i++) { + for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { stream = &priv->ampdu[i]; if (stream->state == AMPDU_NO_STREAM) { stream->sta = sta; stream->state = AMPDU_STREAM_NEW; stream->tid = tid; stream->idx = i; - stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", sta->addr, tid); return stream; @@ -1782,7 +1806,7 @@ mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) struct mwl8k_priv *priv = hw->priv; int i; - for (i = 0 ; i < priv->num_ampdu_queues; i++) { + for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { struct mwl8k_ampdu_stream *stream; stream = &priv->ampdu[i]; if (stream->state == AMPDU_NO_STREAM) @@ -1829,6 +1853,13 @@ static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) tx_stats->pkts++; } +/* The hardware ampdu queues start from 5. + * txpriorities for ampdu queues are + * 5 6 7 0 1 2 3 4 ie., queue 5 is highest + * and queue 3 is lowest (queue 4 is reserved) + */ +#define BA_QUEUE 5 + static void mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, @@ -1928,8 +1959,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, stream = mwl8k_lookup_stream(hw, sta->addr, tid); if (stream != NULL) { if (stream->state == AMPDU_STREAM_ACTIVE) { - txpriority = stream->txq_idx; - index = stream->txq_idx; + WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK)); + txpriority = (BA_QUEUE + stream->idx) % + TOTAL_HW_TX_QUEUES; + if (stream->idx <= 1) + index = stream->idx + + MWL8K_TX_WMM_QUEUES; + } else if (stream->state == AMPDU_STREAM_NEW) { /* We get here if the driver sends us packets * after we've initiated a stream, but before @@ -1971,6 +2007,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, } } spin_unlock(&priv->stream_lock); + } else { + qos &= ~MWL8K_QOS_ACK_POLICY_MASK; + qos |= MWL8K_QOS_ACK_POLICY_NORMAL; } dma = pci_map_single(priv->pdev, skb->data, @@ -3578,7 +3617,11 @@ static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) return rc; } -#define INVALID_BA 0xAA +#define MWL8K_WMM_QUEUE_NUMBER 3 + +static void mwl8k_destroy_ba(struct ieee80211_hw *hw, + u8 idx); + static void mwl8k_watchdog_ba_events(struct work_struct *work) { int rc; @@ -3586,24 +3629,41 @@ static void mwl8k_watchdog_ba_events(struct work_struct *work) struct mwl8k_ampdu_stream *streams; struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, watchdog_ba_handle); + struct ieee80211_hw *hw = priv->hw; + int i; + u32 status = 0; + + mwl8k_fw_lock(hw); rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); if (rc) - return; + goto done; - if (bitmap == INVALID_BA) - return; + spin_lock(&priv->stream_lock); /* the bitmap is the hw queue number. Map it to the ampdu queue. */ - stream_index = bitmap - MWL8K_TX_WMM_QUEUES; - - BUG_ON(stream_index >= priv->num_ampdu_queues); - - streams = &priv->ampdu[stream_index]; - - if (streams->state == AMPDU_STREAM_ACTIVE) - ieee80211_stop_tx_ba_session(streams->sta, streams->tid); + for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) { + if (bitmap & (1 << i)) { + stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) % + TOTAL_HW_TX_QUEUES; + streams = &priv->ampdu[stream_index]; + if (streams->state == AMPDU_STREAM_ACTIVE) { + ieee80211_stop_tx_ba_session(streams->sta, + streams->tid); + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream_index); + spin_lock(&priv->stream_lock); + } + } + } + spin_unlock(&priv->stream_lock); +done: + atomic_dec(&priv->watchdog_event_pending); + status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG), + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + mwl8k_fw_unlock(hw); return; } @@ -3763,7 +3823,7 @@ mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, } static void mwl8k_destroy_ba(struct ieee80211_hw *hw, - struct mwl8k_ampdu_stream *stream) + u8 idx) { struct mwl8k_cmd_bastream *cmd; @@ -3775,10 +3835,10 @@ static void mwl8k_destroy_ba(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); - cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); + cmd->destroy_params.ba_context = cpu_to_le32(idx); mwl8k_post_cmd(hw, &cmd->header); - wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); + wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx); kfree(cmd); } @@ -3875,7 +3935,30 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 *addr) { struct mwl8k_cmd_set_new_stn *cmd; - int rc; + struct mwl8k_priv *priv = hw->priv; + int rc, i; + u8 idx; + + spin_lock(&priv->stream_lock); + /* Destroy any active ampdu streams for this sta */ + for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { + struct mwl8k_ampdu_stream *s; + s = &priv->ampdu[i]; + if (s->state != AMPDU_NO_STREAM) { + if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) { + if (s->state == AMPDU_STREAM_ACTIVE) { + idx = s->idx; + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, idx); + spin_lock(&priv->stream_lock); + } else if (s->state == AMPDU_STREAM_NEW) { + mwl8k_remove_stream(hw, s); + } + } + } + } + + spin_unlock(&priv->stream_lock); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) @@ -4301,6 +4384,10 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) } if (status & MWL8K_A2H_INT_BA_WATCHDOG) { + iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + + atomic_inc(&priv->watchdog_event_pending); status &= ~MWL8K_A2H_INT_BA_WATCHDOG; ieee80211_queue_work(hw, &priv->watchdog_ba_handle); } @@ -4444,6 +4531,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) priv->irq = -1; tasklet_disable(&priv->poll_tx_task); tasklet_disable(&priv->poll_rx_task); + } else { + ieee80211_wake_queues(hw); } return rc; @@ -5092,7 +5181,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int i, rc = 0; struct mwl8k_priv *priv = hw->priv; struct mwl8k_ampdu_stream *stream; - u8 *addr = sta->addr; + u8 *addr = sta->addr, idx; struct mwl8k_sta *sta_info = MWL8K_STA(sta); if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) @@ -5175,8 +5264,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: if (stream) { if (stream->state == AMPDU_STREAM_ACTIVE) { + idx = stream->idx; spin_unlock(&priv->stream_lock); - mwl8k_destroy_ba(hw, stream); + mwl8k_destroy_ba(hw, idx); spin_lock(&priv->stream_lock); } mwl8k_remove_stream(hw, stream); @@ -5192,8 +5282,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!rc) stream->state = AMPDU_STREAM_ACTIVE; else { + idx = stream->idx; spin_unlock(&priv->stream_lock); - mwl8k_destroy_ba(hw, stream); + mwl8k_destroy_ba(hw, idx); spin_lock(&priv->stream_lock); wiphy_debug(hw->wiphy, "Failed adding stream for sta %pM tid %d\n", @@ -5256,7 +5347,7 @@ enum { MWL8366, }; -#define MWL8K_8366_AP_FW_API 2 +#define MWL8K_8366_AP_FW_API 3 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) @@ -5473,6 +5564,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) priv->sniffer_enabled = false; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; + atomic_set(&priv->watchdog_event_pending, 0); rc = mwl8k_rxq_init(hw, 0); if (rc) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 933e5d941937..57e3af8ebb4b 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -559,6 +559,7 @@ static int p54p_probe(struct pci_dev *pdev, mem_len = pci_resource_len(pdev, 0); if (mem_len < sizeof(struct p54p_csr)) { dev_err(&pdev->dev, "Too short PCI resources\n"); + err = -ENODEV; goto err_disable_dev; } @@ -568,8 +569,10 @@ static int p54p_probe(struct pci_dev *pdev, goto err_disable_dev; } - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { dev_err(&pdev->dev, "No suitable DMA available\n"); goto err_free_reg; } diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 12f93e42e160..f139a913c25a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3866,6 +3866,400 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, return rfcsr24; } +static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 0, 0x50); + rt2800_rfcsr_write(rt2x00dev, 1, 0x01); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); + rt2800_rfcsr_write(rt2x00dev, 3, 0x75); + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x50); + rt2800_rfcsr_write(rt2x00dev, 8, 0x39); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x60); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x75); + rt2800_rfcsr_write(rt2x00dev, 13, 0x75); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x31); + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 26, 0x25); + rt2800_rfcsr_write(rt2x00dev, 27, 0x23); + rt2800_rfcsr_write(rt2x00dev, 28, 0x13); + rt2800_rfcsr_write(rt2x00dev, 29, 0x83); + rt2800_rfcsr_write(rt2x00dev, 30, 0x00); + rt2800_rfcsr_write(rt2x00dev, 31, 0x00); +} + +static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x60); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x41); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); +} + +static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x08); + rt2800_rfcsr_write(rt2x00dev, 4, 0x00); + rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); + rt2800_rfcsr_write(rt2x00dev, 8, 0xf3); + rt2800_rfcsr_write(rt2x00dev, 9, 0x02); + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); + rt2800_rfcsr_write(rt2x00dev, 18, 0x02); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 25, 0x83); + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); + rt2800_rfcsr_write(rt2x00dev, 34, 0x05); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); + rt2800_rfcsr_write(rt2x00dev, 38, 0x85); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); + rt2800_rfcsr_write(rt2x00dev, 43, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); + rt2800_rfcsr_write(rt2x00dev, 47, 0x00); + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); + rt2800_rfcsr_write(rt2x00dev, 49, 0x98); + rt2800_rfcsr_write(rt2x00dev, 52, 0x38); + rt2800_rfcsr_write(rt2x00dev, 53, 0x00); + rt2800_rfcsr_write(rt2x00dev, 54, 0x78); + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); + rt2800_rfcsr_write(rt2x00dev, 56, 0x02); + rt2800_rfcsr_write(rt2x00dev, 57, 0x80); + rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); + rt2800_rfcsr_write(rt2x00dev, 59, 0x09); + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); + rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); +} + +static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 0, 0xf0); + rt2800_rfcsr_write(rt2x00dev, 1, 0x23); + rt2800_rfcsr_write(rt2x00dev, 2, 0x50); + rt2800_rfcsr_write(rt2x00dev, 3, 0x18); + rt2800_rfcsr_write(rt2x00dev, 4, 0x00); + rt2800_rfcsr_write(rt2x00dev, 5, 0x00); + rt2800_rfcsr_write(rt2x00dev, 6, 0x33); + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); + rt2800_rfcsr_write(rt2x00dev, 8, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 9, 0x02); + rt2800_rfcsr_write(rt2x00dev, 10, 0xd2); + rt2800_rfcsr_write(rt2x00dev, 11, 0x42); + rt2800_rfcsr_write(rt2x00dev, 12, 0x1c); + rt2800_rfcsr_write(rt2x00dev, 13, 0x00); + rt2800_rfcsr_write(rt2x00dev, 14, 0x5a); + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); + rt2800_rfcsr_write(rt2x00dev, 16, 0x01); + rt2800_rfcsr_write(rt2x00dev, 18, 0x45); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); + rt2800_rfcsr_write(rt2x00dev, 21, 0x00); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x00); + rt2800_rfcsr_write(rt2x00dev, 24, 0x00); + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); + rt2800_rfcsr_write(rt2x00dev, 26, 0x00); + rt2800_rfcsr_write(rt2x00dev, 27, 0x03); + rt2800_rfcsr_write(rt2x00dev, 28, 0x03); + rt2800_rfcsr_write(rt2x00dev, 29, 0x00); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); + rt2800_rfcsr_write(rt2x00dev, 34, 0x01); + rt2800_rfcsr_write(rt2x00dev, 35, 0x03); + rt2800_rfcsr_write(rt2x00dev, 36, 0xbd); + rt2800_rfcsr_write(rt2x00dev, 37, 0x3c); + rt2800_rfcsr_write(rt2x00dev, 38, 0x5f); + rt2800_rfcsr_write(rt2x00dev, 39, 0xc5); + rt2800_rfcsr_write(rt2x00dev, 40, 0x33); + rt2800_rfcsr_write(rt2x00dev, 41, 0x5b); + rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); + rt2800_rfcsr_write(rt2x00dev, 43, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 44, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 45, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 46, 0xdd); + rt2800_rfcsr_write(rt2x00dev, 47, 0x0d); + rt2800_rfcsr_write(rt2x00dev, 48, 0x14); + rt2800_rfcsr_write(rt2x00dev, 49, 0x00); + rt2800_rfcsr_write(rt2x00dev, 50, 0x2d); + rt2800_rfcsr_write(rt2x00dev, 51, 0x7f); + rt2800_rfcsr_write(rt2x00dev, 52, 0x00); + rt2800_rfcsr_write(rt2x00dev, 53, 0x52); + rt2800_rfcsr_write(rt2x00dev, 54, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 55, 0x7f); + rt2800_rfcsr_write(rt2x00dev, 56, 0x00); + rt2800_rfcsr_write(rt2x00dev, 57, 0x52); + rt2800_rfcsr_write(rt2x00dev, 58, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 59, 0x00); + rt2800_rfcsr_write(rt2x00dev, 60, 0x00); + rt2800_rfcsr_write(rt2x00dev, 61, 0x00); + rt2800_rfcsr_write(rt2x00dev, 62, 0x00); + rt2800_rfcsr_write(rt2x00dev, 63, 0x00); +} + +static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 0, 0xa0); + rt2800_rfcsr_write(rt2x00dev, 1, 0xe1); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 3, 0x62); + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x8b); + rt2800_rfcsr_write(rt2x00dev, 6, 0x42); + rt2800_rfcsr_write(rt2x00dev, 7, 0x34); + rt2800_rfcsr_write(rt2x00dev, 8, 0x00); + rt2800_rfcsr_write(rt2x00dev, 9, 0xc0); + rt2800_rfcsr_write(rt2x00dev, 10, 0x61); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x3b); + rt2800_rfcsr_write(rt2x00dev, 13, 0xe0); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x53); + rt2800_rfcsr_write(rt2x00dev, 16, 0xe0); + rt2800_rfcsr_write(rt2x00dev, 17, 0x94); + rt2800_rfcsr_write(rt2x00dev, 18, 0x5c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 20, 0xb2); + rt2800_rfcsr_write(rt2x00dev, 21, 0xf6); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x14); + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); + rt2800_rfcsr_write(rt2x00dev, 25, 0x3d); + rt2800_rfcsr_write(rt2x00dev, 26, 0x85); + rt2800_rfcsr_write(rt2x00dev, 27, 0x00); + rt2800_rfcsr_write(rt2x00dev, 28, 0x41); + rt2800_rfcsr_write(rt2x00dev, 29, 0x8f); + rt2800_rfcsr_write(rt2x00dev, 30, 0x20); + rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); +} + +static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 0, 0x70); + rt2800_rfcsr_write(rt2x00dev, 1, 0x81); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 3, 0x02); + rt2800_rfcsr_write(rt2x00dev, 4, 0x4c); + rt2800_rfcsr_write(rt2x00dev, 5, 0x05); + rt2800_rfcsr_write(rt2x00dev, 6, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); + rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); + rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); + rt2800_rfcsr_write(rt2x00dev, 12, 0x70); + rt2800_rfcsr_write(rt2x00dev, 13, 0x65); + rt2800_rfcsr_write(rt2x00dev, 14, 0xa0); + rt2800_rfcsr_write(rt2x00dev, 15, 0x53); + rt2800_rfcsr_write(rt2x00dev, 16, 0x4c); + rt2800_rfcsr_write(rt2x00dev, 17, 0x23); + rt2800_rfcsr_write(rt2x00dev, 18, 0xac); + rt2800_rfcsr_write(rt2x00dev, 19, 0x93); + rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 21, 0xd0); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x3c); + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800_rfcsr_write(rt2x00dev, 25, 0x15); + rt2800_rfcsr_write(rt2x00dev, 26, 0x85); + rt2800_rfcsr_write(rt2x00dev, 27, 0x00); + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); + rt2800_rfcsr_write(rt2x00dev, 30, 0x09); + rt2800_rfcsr_write(rt2x00dev, 31, 0x10); +} + +static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x88); + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); + else + rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 12, 0xc6); + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); + rt2800_rfcsr_write(rt2x00dev, 16, 0x00); + rt2800_rfcsr_write(rt2x00dev, 18, 0x03); + rt2800_rfcsr_write(rt2x00dev, 19, 0x00); + + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); + rt2800_rfcsr_write(rt2x00dev, 21, 0x00); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 23, 0x00); + rt2800_rfcsr_write(rt2x00dev, 24, 0x00); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); + else + rt2800_rfcsr_write(rt2x00dev, 25, 0xc0); + rt2800_rfcsr_write(rt2x00dev, 26, 0x00); + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); + + rt2800_rfcsr_write(rt2x00dev, 30, 0x00); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); + rt2800_rfcsr_write(rt2x00dev, 37, 0x08); + rt2800_rfcsr_write(rt2x00dev, 38, 0x85); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); + + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); + else + rt2800_rfcsr_write(rt2x00dev, 40, 0x4b); + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 42, 0xd2); + rt2800_rfcsr_write(rt2x00dev, 43, 0x9a); + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); + else + rt2800_rfcsr_write(rt2x00dev, 46, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 47, 0x00); + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); + rt2800_rfcsr_write(rt2x00dev, 49, 0x94); + + rt2800_rfcsr_write(rt2x00dev, 52, 0x38); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 53, 0x00); + else + rt2800_rfcsr_write(rt2x00dev, 53, 0x84); + rt2800_rfcsr_write(rt2x00dev, 54, 0x78); + rt2800_rfcsr_write(rt2x00dev, 55, 0x44); + rt2800_rfcsr_write(rt2x00dev, 56, 0x22); + rt2800_rfcsr_write(rt2x00dev, 57, 0x80); + rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); + rt2800_rfcsr_write(rt2x00dev, 59, 0x63); + + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) + rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); + else + rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); + rt2800_rfcsr_write(rt2x00dev, 62, 0x00); + rt2800_rfcsr_write(rt2x00dev, 63, 0x00); +} + +static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev) +{ + rt2800_rfcsr_write(rt2x00dev, 1, 0x17); + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x88); + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); + rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); + rt2800_rfcsr_write(rt2x00dev, 16, 0x00); + rt2800_rfcsr_write(rt2x00dev, 18, 0x03); + rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); + rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); + rt2800_rfcsr_write(rt2x00dev, 24, 0x44); + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x20); + rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); + rt2800_rfcsr_write(rt2x00dev, 37, 0x08); + rt2800_rfcsr_write(rt2x00dev, 38, 0x89); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); + rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); + rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); + rt2800_rfcsr_write(rt2x00dev, 49, 0x94); + rt2800_rfcsr_write(rt2x00dev, 50, 0x94); + rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); + rt2800_rfcsr_write(rt2x00dev, 52, 0x48); + rt2800_rfcsr_write(rt2x00dev, 53, 0x44); + rt2800_rfcsr_write(rt2x00dev, 54, 0x38); + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); + rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); + rt2800_rfcsr_write(rt2x00dev, 57, 0x00); + rt2800_rfcsr_write(rt2x00dev, 58, 0x39); + rt2800_rfcsr_write(rt2x00dev, 59, 0x07); + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); + rt2800_rfcsr_write(rt2x00dev, 61, 0x91); + rt2800_rfcsr_write(rt2x00dev, 62, 0x39); + rt2800_rfcsr_write(rt2x00dev, 63, 0x07); +} + static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) { struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; @@ -3889,6 +4283,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * Init RF calibration. */ + if (rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) { @@ -3907,379 +4302,35 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); } - if (rt2x00_rt(rt2x00dev, RT3070) || - rt2x00_rt(rt2x00dev, RT3071) || - rt2x00_rt(rt2x00dev, RT3090)) { - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x60); - rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 10, 0x41); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 24, 0x16); - rt2800_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); - } else if (rt2x00_rt(rt2x00dev, RT3290)) { - rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 2, 0x80); - rt2800_rfcsr_write(rt2x00dev, 3, 0x08); - rt2800_rfcsr_write(rt2x00dev, 4, 0x00); - rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); - rt2800_rfcsr_write(rt2x00dev, 8, 0xf3); - rt2800_rfcsr_write(rt2x00dev, 9, 0x02); - rt2800_rfcsr_write(rt2x00dev, 10, 0x53); - rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 12, 0x46); - rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); - rt2800_rfcsr_write(rt2x00dev, 18, 0x02); - rt2800_rfcsr_write(rt2x00dev, 22, 0x20); - rt2800_rfcsr_write(rt2x00dev, 25, 0x83); - rt2800_rfcsr_write(rt2x00dev, 26, 0x82); - rt2800_rfcsr_write(rt2x00dev, 27, 0x09); - rt2800_rfcsr_write(rt2x00dev, 29, 0x10); - rt2800_rfcsr_write(rt2x00dev, 30, 0x10); - rt2800_rfcsr_write(rt2x00dev, 31, 0x80); - rt2800_rfcsr_write(rt2x00dev, 32, 0x80); - rt2800_rfcsr_write(rt2x00dev, 33, 0x00); - rt2800_rfcsr_write(rt2x00dev, 34, 0x05); - rt2800_rfcsr_write(rt2x00dev, 35, 0x12); - rt2800_rfcsr_write(rt2x00dev, 36, 0x00); - rt2800_rfcsr_write(rt2x00dev, 38, 0x85); - rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); - rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); - rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); - rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); - rt2800_rfcsr_write(rt2x00dev, 43, 0x7b); - rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); - rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); - rt2800_rfcsr_write(rt2x00dev, 46, 0x73); - rt2800_rfcsr_write(rt2x00dev, 47, 0x00); - rt2800_rfcsr_write(rt2x00dev, 48, 0x10); - rt2800_rfcsr_write(rt2x00dev, 49, 0x98); - rt2800_rfcsr_write(rt2x00dev, 52, 0x38); - rt2800_rfcsr_write(rt2x00dev, 53, 0x00); - rt2800_rfcsr_write(rt2x00dev, 54, 0x78); - rt2800_rfcsr_write(rt2x00dev, 55, 0x43); - rt2800_rfcsr_write(rt2x00dev, 56, 0x02); - rt2800_rfcsr_write(rt2x00dev, 57, 0x80); - rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); - rt2800_rfcsr_write(rt2x00dev, 59, 0x09); - rt2800_rfcsr_write(rt2x00dev, 60, 0x45); - rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); - } else if (rt2x00_rt(rt2x00dev, RT3390)) { - rt2800_rfcsr_write(rt2x00dev, 0, 0xa0); - rt2800_rfcsr_write(rt2x00dev, 1, 0xe1); - rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); - rt2800_rfcsr_write(rt2x00dev, 3, 0x62); - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x8b); - rt2800_rfcsr_write(rt2x00dev, 6, 0x42); - rt2800_rfcsr_write(rt2x00dev, 7, 0x34); - rt2800_rfcsr_write(rt2x00dev, 8, 0x00); - rt2800_rfcsr_write(rt2x00dev, 9, 0xc0); - rt2800_rfcsr_write(rt2x00dev, 10, 0x61); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x3b); - rt2800_rfcsr_write(rt2x00dev, 13, 0xe0); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x53); - rt2800_rfcsr_write(rt2x00dev, 16, 0xe0); - rt2800_rfcsr_write(rt2x00dev, 17, 0x94); - rt2800_rfcsr_write(rt2x00dev, 18, 0x5c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 20, 0xb2); - rt2800_rfcsr_write(rt2x00dev, 21, 0xf6); - rt2800_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800_rfcsr_write(rt2x00dev, 23, 0x14); - rt2800_rfcsr_write(rt2x00dev, 24, 0x08); - rt2800_rfcsr_write(rt2x00dev, 25, 0x3d); - rt2800_rfcsr_write(rt2x00dev, 26, 0x85); - rt2800_rfcsr_write(rt2x00dev, 27, 0x00); - rt2800_rfcsr_write(rt2x00dev, 28, 0x41); - rt2800_rfcsr_write(rt2x00dev, 29, 0x8f); - rt2800_rfcsr_write(rt2x00dev, 30, 0x20); - rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); - } else if (rt2x00_rt(rt2x00dev, RT3572)) { - rt2800_rfcsr_write(rt2x00dev, 0, 0x70); - rt2800_rfcsr_write(rt2x00dev, 1, 0x81); - rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); - rt2800_rfcsr_write(rt2x00dev, 3, 0x02); - rt2800_rfcsr_write(rt2x00dev, 4, 0x4c); - rt2800_rfcsr_write(rt2x00dev, 5, 0x05); - rt2800_rfcsr_write(rt2x00dev, 6, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); - rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); - rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); - rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); - rt2800_rfcsr_write(rt2x00dev, 12, 0x70); - rt2800_rfcsr_write(rt2x00dev, 13, 0x65); - rt2800_rfcsr_write(rt2x00dev, 14, 0xa0); - rt2800_rfcsr_write(rt2x00dev, 15, 0x53); - rt2800_rfcsr_write(rt2x00dev, 16, 0x4c); - rt2800_rfcsr_write(rt2x00dev, 17, 0x23); - rt2800_rfcsr_write(rt2x00dev, 18, 0xac); - rt2800_rfcsr_write(rt2x00dev, 19, 0x93); - rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 21, 0xd0); - rt2800_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800_rfcsr_write(rt2x00dev, 23, 0x3c); - rt2800_rfcsr_write(rt2x00dev, 24, 0x16); - rt2800_rfcsr_write(rt2x00dev, 25, 0x15); - rt2800_rfcsr_write(rt2x00dev, 26, 0x85); - rt2800_rfcsr_write(rt2x00dev, 27, 0x00); - rt2800_rfcsr_write(rt2x00dev, 28, 0x00); - rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); - rt2800_rfcsr_write(rt2x00dev, 30, 0x09); - rt2800_rfcsr_write(rt2x00dev, 31, 0x10); - } else if (rt2800_is_305x_soc(rt2x00dev)) { - rt2800_rfcsr_write(rt2x00dev, 0, 0x50); - rt2800_rfcsr_write(rt2x00dev, 1, 0x01); - rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); - rt2800_rfcsr_write(rt2x00dev, 3, 0x75); - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x50); - rt2800_rfcsr_write(rt2x00dev, 8, 0x39); - rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 10, 0x60); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x75); - rt2800_rfcsr_write(rt2x00dev, 13, 0x75); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800_rfcsr_write(rt2x00dev, 23, 0x31); - rt2800_rfcsr_write(rt2x00dev, 24, 0x08); - rt2800_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800_rfcsr_write(rt2x00dev, 26, 0x25); - rt2800_rfcsr_write(rt2x00dev, 27, 0x23); - rt2800_rfcsr_write(rt2x00dev, 28, 0x13); - rt2800_rfcsr_write(rt2x00dev, 29, 0x83); - rt2800_rfcsr_write(rt2x00dev, 30, 0x00); - rt2800_rfcsr_write(rt2x00dev, 31, 0x00); + if (rt2800_is_305x_soc(rt2x00dev)) { + rt2800_init_rfcsr_305x_soc(rt2x00dev); return 0; - } else if (rt2x00_rt(rt2x00dev, RT3352)) { - rt2800_rfcsr_write(rt2x00dev, 0, 0xf0); - rt2800_rfcsr_write(rt2x00dev, 1, 0x23); - rt2800_rfcsr_write(rt2x00dev, 2, 0x50); - rt2800_rfcsr_write(rt2x00dev, 3, 0x18); - rt2800_rfcsr_write(rt2x00dev, 4, 0x00); - rt2800_rfcsr_write(rt2x00dev, 5, 0x00); - rt2800_rfcsr_write(rt2x00dev, 6, 0x33); - rt2800_rfcsr_write(rt2x00dev, 7, 0x00); - rt2800_rfcsr_write(rt2x00dev, 8, 0xf1); - rt2800_rfcsr_write(rt2x00dev, 9, 0x02); - rt2800_rfcsr_write(rt2x00dev, 10, 0xd2); - rt2800_rfcsr_write(rt2x00dev, 11, 0x42); - rt2800_rfcsr_write(rt2x00dev, 12, 0x1c); - rt2800_rfcsr_write(rt2x00dev, 13, 0x00); - rt2800_rfcsr_write(rt2x00dev, 14, 0x5a); - rt2800_rfcsr_write(rt2x00dev, 15, 0x00); - rt2800_rfcsr_write(rt2x00dev, 16, 0x01); - rt2800_rfcsr_write(rt2x00dev, 18, 0x45); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0x00); - rt2800_rfcsr_write(rt2x00dev, 21, 0x00); - rt2800_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800_rfcsr_write(rt2x00dev, 23, 0x00); - rt2800_rfcsr_write(rt2x00dev, 24, 0x00); - rt2800_rfcsr_write(rt2x00dev, 25, 0x80); - rt2800_rfcsr_write(rt2x00dev, 26, 0x00); - rt2800_rfcsr_write(rt2x00dev, 27, 0x03); - rt2800_rfcsr_write(rt2x00dev, 28, 0x03); - rt2800_rfcsr_write(rt2x00dev, 29, 0x00); - rt2800_rfcsr_write(rt2x00dev, 30, 0x10); - rt2800_rfcsr_write(rt2x00dev, 31, 0x80); - rt2800_rfcsr_write(rt2x00dev, 32, 0x80); - rt2800_rfcsr_write(rt2x00dev, 33, 0x00); - rt2800_rfcsr_write(rt2x00dev, 34, 0x01); - rt2800_rfcsr_write(rt2x00dev, 35, 0x03); - rt2800_rfcsr_write(rt2x00dev, 36, 0xbd); - rt2800_rfcsr_write(rt2x00dev, 37, 0x3c); - rt2800_rfcsr_write(rt2x00dev, 38, 0x5f); - rt2800_rfcsr_write(rt2x00dev, 39, 0xc5); - rt2800_rfcsr_write(rt2x00dev, 40, 0x33); - rt2800_rfcsr_write(rt2x00dev, 41, 0x5b); - rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); - rt2800_rfcsr_write(rt2x00dev, 43, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 44, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 45, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 46, 0xdd); - rt2800_rfcsr_write(rt2x00dev, 47, 0x0d); - rt2800_rfcsr_write(rt2x00dev, 48, 0x14); - rt2800_rfcsr_write(rt2x00dev, 49, 0x00); - rt2800_rfcsr_write(rt2x00dev, 50, 0x2d); - rt2800_rfcsr_write(rt2x00dev, 51, 0x7f); - rt2800_rfcsr_write(rt2x00dev, 52, 0x00); - rt2800_rfcsr_write(rt2x00dev, 53, 0x52); - rt2800_rfcsr_write(rt2x00dev, 54, 0x1b); - rt2800_rfcsr_write(rt2x00dev, 55, 0x7f); - rt2800_rfcsr_write(rt2x00dev, 56, 0x00); - rt2800_rfcsr_write(rt2x00dev, 57, 0x52); - rt2800_rfcsr_write(rt2x00dev, 58, 0x1b); - rt2800_rfcsr_write(rt2x00dev, 59, 0x00); - rt2800_rfcsr_write(rt2x00dev, 60, 0x00); - rt2800_rfcsr_write(rt2x00dev, 61, 0x00); - rt2800_rfcsr_write(rt2x00dev, 62, 0x00); - rt2800_rfcsr_write(rt2x00dev, 63, 0x00); - } else if (rt2x00_rt(rt2x00dev, RT5390)) { - rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 2, 0x80); - rt2800_rfcsr_write(rt2x00dev, 3, 0x88); - rt2800_rfcsr_write(rt2x00dev, 5, 0x10); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); - else - rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); - rt2800_rfcsr_write(rt2x00dev, 7, 0x00); - rt2800_rfcsr_write(rt2x00dev, 10, 0x53); - rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 12, 0xc6); - rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); - rt2800_rfcsr_write(rt2x00dev, 14, 0x00); - rt2800_rfcsr_write(rt2x00dev, 15, 0x00); - rt2800_rfcsr_write(rt2x00dev, 16, 0x00); - rt2800_rfcsr_write(rt2x00dev, 18, 0x03); - rt2800_rfcsr_write(rt2x00dev, 19, 0x00); - - rt2800_rfcsr_write(rt2x00dev, 20, 0x00); - rt2800_rfcsr_write(rt2x00dev, 21, 0x00); - rt2800_rfcsr_write(rt2x00dev, 22, 0x20); - rt2800_rfcsr_write(rt2x00dev, 23, 0x00); - rt2800_rfcsr_write(rt2x00dev, 24, 0x00); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 25, 0x80); - else - rt2800_rfcsr_write(rt2x00dev, 25, 0xc0); - rt2800_rfcsr_write(rt2x00dev, 26, 0x00); - rt2800_rfcsr_write(rt2x00dev, 27, 0x09); - rt2800_rfcsr_write(rt2x00dev, 28, 0x00); - rt2800_rfcsr_write(rt2x00dev, 29, 0x10); - - rt2800_rfcsr_write(rt2x00dev, 30, 0x00); - rt2800_rfcsr_write(rt2x00dev, 31, 0x80); - rt2800_rfcsr_write(rt2x00dev, 32, 0x80); - rt2800_rfcsr_write(rt2x00dev, 33, 0x00); - rt2800_rfcsr_write(rt2x00dev, 34, 0x07); - rt2800_rfcsr_write(rt2x00dev, 35, 0x12); - rt2800_rfcsr_write(rt2x00dev, 36, 0x00); - rt2800_rfcsr_write(rt2x00dev, 37, 0x08); - rt2800_rfcsr_write(rt2x00dev, 38, 0x85); - rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); - - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); - else - rt2800_rfcsr_write(rt2x00dev, 40, 0x4b); - rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); - rt2800_rfcsr_write(rt2x00dev, 42, 0xd2); - rt2800_rfcsr_write(rt2x00dev, 43, 0x9a); - rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); - rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 46, 0x73); - else - rt2800_rfcsr_write(rt2x00dev, 46, 0x7b); - rt2800_rfcsr_write(rt2x00dev, 47, 0x00); - rt2800_rfcsr_write(rt2x00dev, 48, 0x10); - rt2800_rfcsr_write(rt2x00dev, 49, 0x94); - - rt2800_rfcsr_write(rt2x00dev, 52, 0x38); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 53, 0x00); - else - rt2800_rfcsr_write(rt2x00dev, 53, 0x84); - rt2800_rfcsr_write(rt2x00dev, 54, 0x78); - rt2800_rfcsr_write(rt2x00dev, 55, 0x44); - rt2800_rfcsr_write(rt2x00dev, 56, 0x22); - rt2800_rfcsr_write(rt2x00dev, 57, 0x80); - rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); - rt2800_rfcsr_write(rt2x00dev, 59, 0x63); - - rt2800_rfcsr_write(rt2x00dev, 60, 0x45); - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) - rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); - else - rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); - rt2800_rfcsr_write(rt2x00dev, 62, 0x00); - rt2800_rfcsr_write(rt2x00dev, 63, 0x00); - } else if (rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_rfcsr_write(rt2x00dev, 1, 0x17); - rt2800_rfcsr_write(rt2x00dev, 2, 0x80); - rt2800_rfcsr_write(rt2x00dev, 3, 0x88); - rt2800_rfcsr_write(rt2x00dev, 5, 0x10); - rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); - rt2800_rfcsr_write(rt2x00dev, 7, 0x00); - rt2800_rfcsr_write(rt2x00dev, 10, 0x53); - rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 12, 0x46); - rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); - rt2800_rfcsr_write(rt2x00dev, 14, 0x00); - rt2800_rfcsr_write(rt2x00dev, 15, 0x00); - rt2800_rfcsr_write(rt2x00dev, 16, 0x00); - rt2800_rfcsr_write(rt2x00dev, 18, 0x03); - rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); - rt2800_rfcsr_write(rt2x00dev, 20, 0x00); - rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); - rt2800_rfcsr_write(rt2x00dev, 22, 0x20); - rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); - rt2800_rfcsr_write(rt2x00dev, 24, 0x44); - rt2800_rfcsr_write(rt2x00dev, 25, 0x80); - rt2800_rfcsr_write(rt2x00dev, 26, 0x82); - rt2800_rfcsr_write(rt2x00dev, 27, 0x09); - rt2800_rfcsr_write(rt2x00dev, 28, 0x00); - rt2800_rfcsr_write(rt2x00dev, 29, 0x10); - rt2800_rfcsr_write(rt2x00dev, 30, 0x10); - rt2800_rfcsr_write(rt2x00dev, 31, 0x80); - rt2800_rfcsr_write(rt2x00dev, 32, 0x20); - rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); - rt2800_rfcsr_write(rt2x00dev, 34, 0x07); - rt2800_rfcsr_write(rt2x00dev, 35, 0x12); - rt2800_rfcsr_write(rt2x00dev, 36, 0x00); - rt2800_rfcsr_write(rt2x00dev, 37, 0x08); - rt2800_rfcsr_write(rt2x00dev, 38, 0x89); - rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); - rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); - rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); - rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); - rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); - rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); - rt2800_rfcsr_write(rt2x00dev, 46, 0x73); - rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); - rt2800_rfcsr_write(rt2x00dev, 48, 0x10); - rt2800_rfcsr_write(rt2x00dev, 49, 0x94); - rt2800_rfcsr_write(rt2x00dev, 50, 0x94); - rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); - rt2800_rfcsr_write(rt2x00dev, 52, 0x48); - rt2800_rfcsr_write(rt2x00dev, 53, 0x44); - rt2800_rfcsr_write(rt2x00dev, 54, 0x38); - rt2800_rfcsr_write(rt2x00dev, 55, 0x43); - rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); - rt2800_rfcsr_write(rt2x00dev, 57, 0x00); - rt2800_rfcsr_write(rt2x00dev, 58, 0x39); - rt2800_rfcsr_write(rt2x00dev, 59, 0x07); - rt2800_rfcsr_write(rt2x00dev, 60, 0x45); - rt2800_rfcsr_write(rt2x00dev, 61, 0x91); - rt2800_rfcsr_write(rt2x00dev, 62, 0x39); - rt2800_rfcsr_write(rt2x00dev, 63, 0x07); + } + + switch (rt2x00dev->chip.rt) { + case RT3070: + case RT3071: + case RT3090: + rt2800_init_rfcsr_30xx(rt2x00dev); + break; + case RT3290: + rt2800_init_rfcsr_3290(rt2x00dev); + break; + case RT3352: + rt2800_init_rfcsr_3352(rt2x00dev); + break; + case RT3390: + rt2800_init_rfcsr_3390(rt2x00dev); + break; + case RT3572: + rt2800_init_rfcsr_3572(rt2x00dev); + break; + case RT5390: + rt2800_init_rfcsr_5390(rt2x00dev); + break; + case RT5392: + rt2800_init_rfcsr_5392(rt2x00dev); + break; } if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) { @@ -4620,12 +4671,14 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) mutex_unlock(&rt2x00dev->csr_mutex); } -void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) { unsigned int i; for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) rt2800_efuse_read(rt2x00dev, i); + + return 0; } EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse); @@ -4635,11 +4688,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) u16 word; u8 *mac; u8 default_lna_gain; + int retval; /* * Read the EEPROM. */ - rt2800_read_eeprom(rt2x00dev); + retval = rt2800_read_eeprom(rt2x00dev); + if (retval) + return retval; /* * Start validation of the data that has been read. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index a128ceadcb3e..6ec739466db4 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -43,7 +43,7 @@ struct rt2800_ops { const unsigned int offset, const struct rt2x00_field32 field, u32 *reg); - void (*read_eeprom)(struct rt2x00_dev *rt2x00dev); + int (*read_eeprom)(struct rt2x00_dev *rt2x00dev); bool (*hwcrypt_disabled)(struct rt2x00_dev *rt2x00dev); int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev, @@ -117,11 +117,11 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); } -static inline void rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev) +static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev) { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - rt2800ops->read_eeprom(rt2x00dev); + return rt2800ops->read_eeprom(rt2x00dev); } static inline bool rt2800_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev) @@ -207,7 +207,7 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); -void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); +int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 9224d874bf24..0e8d1705e368 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -90,17 +90,22 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) } #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) -static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) +static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); + if (!base_addr) + return -ENOMEM; + memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE); iounmap(base_addr); + return 0; } #else -static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) +static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { + return -ENOMEM; } #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ @@ -135,7 +140,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom) rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); } -static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) +static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) { struct eeprom_93cx6 eeprom; u32 reg; @@ -164,6 +169,8 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, EEPROM_SIZE / sizeof(u16)); + + return 0; } static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) @@ -171,13 +178,14 @@ static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) return rt2800_efuse_detect(rt2x00dev); } -static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) { - rt2800_read_eeprom_efuse(rt2x00dev); + return rt2800_read_eeprom_efuse(rt2x00dev); } #else -static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) +static inline int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) { + return -EOPNOTSUPP; } static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) @@ -185,8 +193,9 @@ static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) return 0; } -static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) { + return -EOPNOTSUPP; } #endif /* CONFIG_PCI */ @@ -970,14 +979,18 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) /* * Device probe functions. */ -static void rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev) +static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev) { + int retval; + if (rt2x00_is_soc(rt2x00dev)) - rt2800pci_read_eeprom_soc(rt2x00dev); + retval = rt2800pci_read_eeprom_soc(rt2x00dev); else if (rt2800pci_efuse_detect(rt2x00dev)) - rt2800pci_read_eeprom_efuse(rt2x00dev); + retval = rt2800pci_read_eeprom_efuse(rt2x00dev); else - rt2800pci_read_eeprom_pci(rt2x00dev); + retval = rt2800pci_read_eeprom_pci(rt2x00dev); + + return retval; } static const struct ieee80211_ops rt2800pci_mac80211_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5c149b58ab46..4721cada1591 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -735,13 +735,17 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, /* * Device probe functions. */ -static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev) +static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev) { + int retval; + if (rt2800_efuse_detect(rt2x00dev)) - rt2800_read_eeprom_efuse(rt2x00dev); + retval = rt2800_read_eeprom_efuse(rt2x00dev); else - rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, - EEPROM_SIZE); + retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, + EEPROM_SIZE); + + return retval; } static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) |