Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for 4.12. Major changes:

ath10k

* improve firmware download time for QCA6174 and QCA9377, especially
  helps resume time

ath9k_htc

* add support AirTies 1eda:2315 AR9271 device
This commit is contained in:
Kalle Valo 2017-04-05 10:14:09 +03:00
commit 09e40034f3
22 changed files with 650 additions and 73 deletions

View File

@ -19,12 +19,21 @@
#include "hif.h" #include "hif.h"
#include "debug.h" #include "debug.h"
#include "htc.h" #include "htc.h"
#include "hw.h"
void ath10k_bmi_start(struct ath10k *ar) void ath10k_bmi_start(struct ath10k *ar)
{ {
int ret;
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n"); ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
ar->bmi.done_sent = false; ar->bmi.done_sent = false;
/* Enable hardware clock to speed up firmware download */
if (ar->hw_params.hw_ops->enable_pll_clk) {
ret = ar->hw_params.hw_ops->enable_pll_clk(ar);
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret);
}
} }
int ath10k_bmi_done(struct ath10k *ar) int ath10k_bmi_done(struct ath10k *ar)
@ -129,6 +138,69 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
return 0; return 0;
} }
int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
{
struct bmi_cmd cmd;
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
int ret;
ath10k_dbg(ar, ATH10K_DBG_BMI,
"bmi write soc register 0x%08x val 0x%08x\n",
address, reg_val);
if (ar->bmi.done_sent) {
ath10k_warn(ar, "bmi write soc register command in progress\n");
return -EBUSY;
}
cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
cmd.write_soc_reg.addr = __cpu_to_le32(address);
cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
if (ret) {
ath10k_warn(ar, "Unable to write soc register to device: %d\n",
ret);
return ret;
}
return 0;
}
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
{
struct bmi_cmd cmd;
union bmi_resp resp;
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
u32 resplen = sizeof(resp.read_soc_reg);
int ret;
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
address);
if (ar->bmi.done_sent) {
ath10k_warn(ar, "bmi read soc register command in progress\n");
return -EBUSY;
}
cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
cmd.read_soc_reg.addr = __cpu_to_le32(address);
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
if (ret) {
ath10k_warn(ar, "Unable to read soc register from device: %d\n",
ret);
return ret;
}
*reg_val = __le32_to_cpu(resp.read_soc_reg.value);
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
*reg_val);
return 0;
}
int ath10k_bmi_write_memory(struct ath10k *ar, int ath10k_bmi_write_memory(struct ath10k *ar,
u32 address, const void *buffer, u32 length) u32 address, const void *buffer, u32 length)
{ {

View File

@ -232,4 +232,6 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address);
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length); int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length);
int ath10k_bmi_fast_download(struct ath10k *ar, u32 address, int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
const void *buffer, u32 length); const void *buffer, u32 length);
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val);
int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val);
#endif /* _BMI_H_ */ #endif /* _BMI_H_ */

View File

@ -166,7 +166,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.board_size = QCA6174_BOARD_DATA_SZ, .board_size = QCA6174_BOARD_DATA_SZ,
.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
}, },
.hw_ops = &qca988x_ops, .hw_ops = &qca6174_ops,
.hw_clk = qca6174_clk,
.target_cpu_freq = 176000000,
.decap_align_bytes = 4, .decap_align_bytes = 4,
}, },
{ {
@ -280,7 +282,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.board_size = QCA9377_BOARD_DATA_SZ, .board_size = QCA9377_BOARD_DATA_SZ,
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
}, },
.hw_ops = &qca988x_ops, .hw_ops = &qca6174_ops,
.hw_clk = qca6174_clk,
.target_cpu_freq = 176000000,
.decap_align_bytes = 4, .decap_align_bytes = 4,
}, },
{ {

View File

@ -775,6 +775,8 @@ struct ath10k {
u32 num_rf_chains; u32 num_rf_chains;
u32 max_spatial_stream; u32 max_spatial_stream;
/* protected by conf_mutex */ /* protected by conf_mutex */
u32 low_5ghz_chan;
u32 high_5ghz_chan;
bool ani_enabled; bool ani_enabled;
bool p2p; bool p2p;

View File

@ -249,9 +249,6 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
if (len > buf_len)
len = buf_len;
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
for (i = 0; i < WMI_SERVICE_MAX; i++) { for (i = 0; i < WMI_SERVICE_MAX; i++) {
enabled = test_bit(i, ar->wmi.svc_map); enabled = test_bit(i, ar->wmi.svc_map);
@ -1997,6 +1994,15 @@ static ssize_t ath10k_write_simulate_radar(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath10k *ar = file->private_data; struct ath10k *ar = file->private_data;
struct ath10k_vif *arvif;
/* Just check for for the first vif alone, as all the vifs will be
* sharing the same channel and if the channel is disabled, all the
* vifs will share the same 'is_started' state.
*/
arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
if (!arvif->is_started)
return -EINVAL;
ieee80211_radar_detected(ar->hw); ieee80211_radar_detected(ar->hw);

View File

@ -19,6 +19,7 @@
#include "hw.h" #include "hw.h"
#include "hif.h" #include "hif.h"
#include "wmi-ops.h" #include "wmi-ops.h"
#include "bmi.h"
const struct ath10k_hw_regs qca988x_regs = { const struct ath10k_hw_regs qca988x_regs = {
.rtc_soc_base_address = 0x00004000, .rtc_soc_base_address = 0x00004000,
@ -72,6 +73,9 @@ const struct ath10k_hw_regs qca6174_regs = {
.pcie_intr_fw_mask = 0x00000400, .pcie_intr_fw_mask = 0x00000400,
.pcie_intr_ce_mask_all = 0x0007f800, .pcie_intr_ce_mask_all = 0x0007f800,
.pcie_intr_clr_address = 0x00000014, .pcie_intr_clr_address = 0x00000014,
.cpu_pll_init_address = 0x00404020,
.cpu_speed_address = 0x00404024,
.core_clk_div_address = 0x00404028,
}; };
const struct ath10k_hw_regs qca99x0_regs = { const struct ath10k_hw_regs qca99x0_regs = {
@ -187,6 +191,73 @@ const struct ath10k_hw_values qca4019_values = {
.ce_desc_meta_data_lsb = 4, .ce_desc_meta_data_lsb = 4,
}; };
const struct ath10k_hw_clk_params qca6174_clk[ATH10K_HW_REFCLK_COUNT] = {
{
.refclk = 48000000,
.div = 0xe,
.rnfrac = 0x2aaa8,
.settle_time = 2400,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 19200000,
.div = 0x24,
.rnfrac = 0x2aaa8,
.settle_time = 960,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 24000000,
.div = 0x1d,
.rnfrac = 0x15551,
.settle_time = 1200,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 26000000,
.div = 0x1b,
.rnfrac = 0x4ec4,
.settle_time = 1300,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 37400000,
.div = 0x12,
.rnfrac = 0x34b49,
.settle_time = 1870,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 38400000,
.div = 0x12,
.rnfrac = 0x15551,
.settle_time = 1920,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 40000000,
.div = 0x12,
.rnfrac = 0x26665,
.settle_time = 2000,
.refdiv = 0,
.outdiv = 1,
},
{
.refclk = 52000000,
.div = 0x1b,
.rnfrac = 0x4ec4,
.settle_time = 2600,
.refdiv = 0,
.outdiv = 1,
},
};
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
{ {
@ -361,6 +432,195 @@ static void ath10k_hw_qca988x_set_coverage_class(struct ath10k *ar,
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
} }
/**
* ath10k_hw_qca6174_enable_pll_clock() - enable the qca6174 hw pll clock
* @ar: the ath10k blob
*
* This function is very hardware specific, the clock initialization
* steps is very sensitive and could lead to unknown crash, so they
* should be done in sequence.
*
* *** Be aware if you planned to refactor them. ***
*
* Return: 0 if successfully enable the pll, otherwise EINVAL
*/
static int ath10k_hw_qca6174_enable_pll_clock(struct ath10k *ar)
{
int ret, wait_limit;
u32 clk_div_addr, pll_init_addr, speed_addr;
u32 addr, reg_val, mem_val;
struct ath10k_hw_params *hw;
const struct ath10k_hw_clk_params *hw_clk;
hw = &ar->hw_params;
if (ar->regs->core_clk_div_address == 0 ||
ar->regs->cpu_pll_init_address == 0 ||
ar->regs->cpu_speed_address == 0)
return -EINVAL;
clk_div_addr = ar->regs->core_clk_div_address;
pll_init_addr = ar->regs->cpu_pll_init_address;
speed_addr = ar->regs->cpu_speed_address;
/* Read efuse register to find out the right hw clock configuration */
addr = (RTC_SOC_BASE_ADDRESS | EFUSE_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
/* sanitize if the hw refclk index is out of the boundary */
if (MS(reg_val, EFUSE_XTAL_SEL) > ATH10K_HW_REFCLK_COUNT)
return -EINVAL;
hw_clk = &hw->hw_clk[MS(reg_val, EFUSE_XTAL_SEL)];
/* Set the rnfrac and outdiv params to bb_pll register */
addr = (RTC_SOC_BASE_ADDRESS | BB_PLL_CONFIG_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val &= ~(BB_PLL_CONFIG_FRAC_MASK | BB_PLL_CONFIG_OUTDIV_MASK);
reg_val |= (SM(hw_clk->rnfrac, BB_PLL_CONFIG_FRAC) |
SM(hw_clk->outdiv, BB_PLL_CONFIG_OUTDIV));
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* Set the correct settle time value to pll_settle register */
addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_SETTLE_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val &= ~WLAN_PLL_SETTLE_TIME_MASK;
reg_val |= SM(hw_clk->settle_time, WLAN_PLL_SETTLE_TIME);
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* Set the clock_ctrl div to core_clk_ctrl register */
addr = (RTC_SOC_BASE_ADDRESS | SOC_CORE_CLK_CTRL_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val &= ~SOC_CORE_CLK_CTRL_DIV_MASK;
reg_val |= SM(1, SOC_CORE_CLK_CTRL_DIV);
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* Set the clock_div register */
mem_val = 1;
ret = ath10k_bmi_write_memory(ar, clk_div_addr, &mem_val,
sizeof(mem_val));
if (ret)
return -EINVAL;
/* Configure the pll_control register */
addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val |= (SM(hw_clk->refdiv, WLAN_PLL_CONTROL_REFDIV) |
SM(hw_clk->div, WLAN_PLL_CONTROL_DIV) |
SM(1, WLAN_PLL_CONTROL_NOPWD));
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* busy wait (max 1s) the rtc_sync status register indicate ready */
wait_limit = 100000;
addr = (RTC_WMAC_BASE_ADDRESS | RTC_SYNC_STATUS_OFFSET);
do {
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
if (!MS(reg_val, RTC_SYNC_STATUS_PLL_CHANGING))
break;
wait_limit--;
udelay(10);
} while (wait_limit > 0);
if (MS(reg_val, RTC_SYNC_STATUS_PLL_CHANGING))
return -EINVAL;
/* Unset the pll_bypass in pll_control register */
addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val &= ~WLAN_PLL_CONTROL_BYPASS_MASK;
reg_val |= SM(0, WLAN_PLL_CONTROL_BYPASS);
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* busy wait (max 1s) the rtc_sync status register indicate ready */
wait_limit = 100000;
addr = (RTC_WMAC_BASE_ADDRESS | RTC_SYNC_STATUS_OFFSET);
do {
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
if (!MS(reg_val, RTC_SYNC_STATUS_PLL_CHANGING))
break;
wait_limit--;
udelay(10);
} while (wait_limit > 0);
if (MS(reg_val, RTC_SYNC_STATUS_PLL_CHANGING))
return -EINVAL;
/* Enable the hardware cpu clock register */
addr = (RTC_SOC_BASE_ADDRESS | SOC_CPU_CLOCK_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val &= ~SOC_CPU_CLOCK_STANDARD_MASK;
reg_val |= SM(1, SOC_CPU_CLOCK_STANDARD);
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* unset the nopwd from pll_control register */
addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET);
ret = ath10k_bmi_read_soc_reg(ar, addr, &reg_val);
if (ret)
return -EINVAL;
reg_val &= ~WLAN_PLL_CONTROL_NOPWD_MASK;
ret = ath10k_bmi_write_soc_reg(ar, addr, reg_val);
if (ret)
return -EINVAL;
/* enable the pll_init register */
mem_val = 1;
ret = ath10k_bmi_write_memory(ar, pll_init_addr, &mem_val,
sizeof(mem_val));
if (ret)
return -EINVAL;
/* set the target clock frequency to speed register */
ret = ath10k_bmi_write_memory(ar, speed_addr, &hw->target_cpu_freq,
sizeof(hw->target_cpu_freq));
if (ret)
return -EINVAL;
return 0;
}
const struct ath10k_hw_ops qca988x_ops = { const struct ath10k_hw_ops qca988x_ops = {
.set_coverage_class = ath10k_hw_qca988x_set_coverage_class, .set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
}; };
@ -374,3 +634,8 @@ static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
const struct ath10k_hw_ops qca99x0_ops = { const struct ath10k_hw_ops qca99x0_ops = {
.rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes, .rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes,
}; };
const struct ath10k_hw_ops qca6174_ops = {
.set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
.enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock,
};

View File

@ -255,6 +255,9 @@ struct ath10k_hw_regs {
u32 pcie_intr_fw_mask; u32 pcie_intr_fw_mask;
u32 pcie_intr_ce_mask_all; u32 pcie_intr_ce_mask_all;
u32 pcie_intr_clr_address; u32 pcie_intr_clr_address;
u32 cpu_pll_init_address;
u32 cpu_speed_address;
u32 core_clk_div_address;
}; };
extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca988x_regs;
@ -363,6 +366,30 @@ enum ath10k_hw_cc_wraparound_type {
ATH10K_HW_CC_WRAP_SHIFTED_EACH = 2, ATH10K_HW_CC_WRAP_SHIFTED_EACH = 2,
}; };
enum ath10k_hw_refclk_speed {
ATH10K_HW_REFCLK_UNKNOWN = -1,
ATH10K_HW_REFCLK_48_MHZ = 0,
ATH10K_HW_REFCLK_19_2_MHZ = 1,
ATH10K_HW_REFCLK_24_MHZ = 2,
ATH10K_HW_REFCLK_26_MHZ = 3,
ATH10K_HW_REFCLK_37_4_MHZ = 4,
ATH10K_HW_REFCLK_38_4_MHZ = 5,
ATH10K_HW_REFCLK_40_MHZ = 6,
ATH10K_HW_REFCLK_52_MHZ = 7,
/* must be the last one */
ATH10K_HW_REFCLK_COUNT,
};
struct ath10k_hw_clk_params {
u32 refclk;
u32 div;
u32 rnfrac;
u32 settle_time;
u32 refdiv;
u32 outdiv;
};
struct ath10k_hw_params { struct ath10k_hw_params {
u32 id; u32 id;
u16 dev_id; u16 dev_id;
@ -416,6 +443,10 @@ struct ath10k_hw_params {
/* Number of bytes used for alignment in rx_hdr_status of rx desc. */ /* Number of bytes used for alignment in rx_hdr_status of rx desc. */
int decap_align_bytes; int decap_align_bytes;
/* hw specific clock control parameters */
const struct ath10k_hw_clk_params *hw_clk;
int target_cpu_freq;
}; };
struct htt_rx_desc; struct htt_rx_desc;
@ -424,10 +455,14 @@ struct htt_rx_desc;
struct ath10k_hw_ops { struct ath10k_hw_ops {
int (*rx_desc_get_l3_pad_bytes)(struct htt_rx_desc *rxd); int (*rx_desc_get_l3_pad_bytes)(struct htt_rx_desc *rxd);
void (*set_coverage_class)(struct ath10k *ar, s16 value); void (*set_coverage_class)(struct ath10k *ar, s16 value);
int (*enable_pll_clk)(struct ath10k *ar);
}; };
extern const struct ath10k_hw_ops qca988x_ops; extern const struct ath10k_hw_ops qca988x_ops;
extern const struct ath10k_hw_ops qca99x0_ops; extern const struct ath10k_hw_ops qca99x0_ops;
extern const struct ath10k_hw_ops qca6174_ops;
extern const struct ath10k_hw_clk_params qca6174_clk[];
static inline int static inline int
ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
@ -847,4 +882,38 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
#define WAVE1_PHYCLK_USEC_MASK 0x0000007F #define WAVE1_PHYCLK_USEC_MASK 0x0000007F
#define WAVE1_PHYCLK_USEC_LSB 0 #define WAVE1_PHYCLK_USEC_LSB 0
/* qca6174 PLL offset/mask */
#define SOC_CORE_CLK_CTRL_OFFSET 0x00000114
#define SOC_CORE_CLK_CTRL_DIV_LSB 0
#define SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007
#define EFUSE_OFFSET 0x0000032c
#define EFUSE_XTAL_SEL_LSB 8
#define EFUSE_XTAL_SEL_MASK 0x00000700
#define BB_PLL_CONFIG_OFFSET 0x000002f4
#define BB_PLL_CONFIG_FRAC_LSB 0
#define BB_PLL_CONFIG_FRAC_MASK 0x0003ffff
#define BB_PLL_CONFIG_OUTDIV_LSB 18
#define BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000
#define WLAN_PLL_SETTLE_OFFSET 0x0018
#define WLAN_PLL_SETTLE_TIME_LSB 0
#define WLAN_PLL_SETTLE_TIME_MASK 0x000007ff
#define WLAN_PLL_CONTROL_OFFSET 0x0014
#define WLAN_PLL_CONTROL_DIV_LSB 0
#define WLAN_PLL_CONTROL_DIV_MASK 0x000003ff
#define WLAN_PLL_CONTROL_REFDIV_LSB 10
#define WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00
#define WLAN_PLL_CONTROL_BYPASS_LSB 16
#define WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000
#define WLAN_PLL_CONTROL_NOPWD_LSB 18
#define WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000
#define RTC_SYNC_STATUS_OFFSET 0x0244
#define RTC_SYNC_STATUS_PLL_CHANGING_LSB 5
#define RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020
/* qca6174 PLL offset/mask end */
#endif /* _HW_H_ */ #endif /* _HW_H_ */

View File

@ -3126,6 +3126,21 @@ static void ath10k_regd_update(struct ath10k *ar)
ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret); ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
} }
static void ath10k_mac_update_channel_list(struct ath10k *ar,
struct ieee80211_supported_band *band)
{
int i;
if (ar->low_5ghz_chan && ar->high_5ghz_chan) {
for (i = 0; i < band->n_channels; i++) {
if (band->channels[i].center_freq < ar->low_5ghz_chan ||
band->channels[i].center_freq > ar->high_5ghz_chan)
band->channels[i].flags |=
IEEE80211_CHAN_DISABLED;
}
}
}
static void ath10k_reg_notifier(struct wiphy *wiphy, static void ath10k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request) struct regulatory_request *request)
{ {
@ -3149,6 +3164,10 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
if (ar->state == ATH10K_STATE_ON) if (ar->state == ATH10K_STATE_ON)
ath10k_regd_update(ar); ath10k_regd_update(ar);
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
ath10k_mac_update_channel_list(ar,
ar->hw->wiphy->bands[NL80211_BAND_5GHZ]);
} }
/***************/ /***************/
@ -7129,7 +7148,7 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
lockdep_assert_held(&ar->data_lock); lockdep_assert_held(&ar->data_lock);
WARN_ON(ctx && vifs); WARN_ON(ctx && vifs);
WARN_ON(vifs && n_vifs != 1); WARN_ON(vifs && !n_vifs);
/* FIXME: Sort of an optimization and a workaround. Peers and vifs are /* FIXME: Sort of an optimization and a workaround. Peers and vifs are
* on a linked list now. Doing a lookup peer -> vif -> chanctx for each * on a linked list now. Doing a lookup peer -> vif -> chanctx for each

View File

@ -970,12 +970,6 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
} }
remaining_bytes -= nbytes; remaining_bytes -= nbytes;
if (ret) {
ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
address, ret);
break;
}
memcpy(data, data_buf, nbytes); memcpy(data, data_buf, nbytes);
address += nbytes; address += nbytes;

View File

@ -3643,6 +3643,11 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ch = ar->rx_channel; ch = ar->rx_channel;
/* fetch target operating channel during channel change */
if (!ch)
ch = ar->tgt_oper_chan;
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
if (!ch) { if (!ch) {
@ -4593,6 +4598,8 @@ ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
arg->phy_capab = ev->phy_capability; arg->phy_capab = ev->phy_capability;
arg->num_rf_chains = ev->num_rf_chains; arg->num_rf_chains = ev->num_rf_chains;
arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan;
arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan;
arg->num_mem_reqs = ev->num_mem_reqs; arg->num_mem_reqs = ev->num_mem_reqs;
arg->service_map = ev->wmi_service_bitmap; arg->service_map = ev->wmi_service_bitmap;
arg->service_map_len = sizeof(ev->wmi_service_bitmap); arg->service_map_len = sizeof(ev->wmi_service_bitmap);
@ -4629,6 +4636,8 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
arg->phy_capab = ev->phy_capability; arg->phy_capab = ev->phy_capability;
arg->num_rf_chains = ev->num_rf_chains; arg->num_rf_chains = ev->num_rf_chains;
arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan;
arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan;
arg->num_mem_reqs = ev->num_mem_reqs; arg->num_mem_reqs = ev->num_mem_reqs;
arg->service_map = ev->wmi_service_bitmap; arg->service_map = ev->wmi_service_bitmap;
arg->service_map_len = sizeof(ev->wmi_service_bitmap); arg->service_map_len = sizeof(ev->wmi_service_bitmap);
@ -4682,6 +4691,8 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
ar->phy_capability = __le32_to_cpu(arg.phy_capab); ar->phy_capability = __le32_to_cpu(arg.phy_capab);
ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd); ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd);
ar->low_5ghz_chan = __le32_to_cpu(arg.low_5ghz_chan);
ar->high_5ghz_chan = __le32_to_cpu(arg.high_5ghz_chan);
ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
arg.service_map, arg.service_map_len); arg.service_map, arg.service_map_len);

View File

@ -3182,7 +3182,7 @@ struct wmi_10_4_phyerr_event {
struct phyerr_radar_report { struct phyerr_radar_report {
__le32 reg0; /* RADAR_REPORT_REG0_* */ __le32 reg0; /* RADAR_REPORT_REG0_* */
__le32 reg1; /* REDAR_REPORT_REG1_* */ __le32 reg1; /* RADAR_REPORT_REG1_* */
} __packed; } __packed;
#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_MASK 0x80000000 #define RADAR_REPORT_REG0_PULSE_IS_CHIRP_MASK 0x80000000
@ -6335,6 +6335,8 @@ struct wmi_svc_rdy_ev_arg {
__le32 num_rf_chains; __le32 num_rf_chains;
__le32 eeprom_rd; __le32 eeprom_rd;
__le32 num_mem_reqs; __le32 num_mem_reqs;
__le32 low_5ghz_chan;
__le32 high_5ghz_chan;
const __le32 *service_map; const __le32 *service_map;
size_t service_map_len; size_t service_map_len;
const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];

View File

@ -102,10 +102,8 @@ static struct ieee80211_channel ath6kl_2ghz_channels[] = {
}; };
static struct ieee80211_channel ath6kl_5ghz_a_channels[] = { static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
CHAN5G(34, 0), CHAN5G(36, 0), CHAN5G(36, 0), CHAN5G(40, 0),
CHAN5G(38, 0), CHAN5G(40, 0), CHAN5G(44, 0), CHAN5G(48, 0),
CHAN5G(42, 0), CHAN5G(44, 0),
CHAN5G(46, 0), CHAN5G(48, 0),
CHAN5G(52, 0), CHAN5G(56, 0), CHAN5G(52, 0), CHAN5G(56, 0),
CHAN5G(60, 0), CHAN5G(64, 0), CHAN5G(60, 0), CHAN5G(64, 0),
CHAN5G(100, 0), CHAN5G(104, 0), CHAN5G(100, 0), CHAN5G(104, 0),

View File

@ -742,6 +742,9 @@ void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
return; return;
} }
if (!spec_priv->spec_config.enabled)
return;
ath_ps_ops(common)->wakeup(common); ath_ps_ops(common)->wakeup(common);
rxfilter = ath9k_hw_getrxfilter(ah); rxfilter = ath9k_hw_getrxfilter(ah);
ath9k_hw_setrxfilter(ah, rxfilter | ath9k_hw_setrxfilter(ah, rxfilter |

View File

@ -37,6 +37,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
{ USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */ { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */
{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
{ USB_DEVICE(0x0471, 0x209e) }, /* Philips (or NXP) PTA01 */ { USB_DEVICE(0x0471, 0x209e) }, /* Philips (or NXP) PTA01 */
{ USB_DEVICE(0x1eda, 0x2315) }, /* AirTies */
{ USB_DEVICE(0x0cf3, 0x7015), { USB_DEVICE(0x0cf3, 0x7015),
.driver_info = AR9287_USB }, /* Atheros */ .driver_info = AR9287_USB }, /* Atheros */

View File

@ -337,10 +337,10 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
wcn36xx_smd_stop(wcn); wcn36xx_smd_stop(wcn);
out_free_smd_buf: out_free_smd_buf:
kfree(wcn->hal_buf); kfree(wcn->hal_buf);
out_free_dxe_pool:
wcn36xx_dxe_free_mem_pools(wcn);
out_free_dxe_ctl: out_free_dxe_ctl:
wcn36xx_dxe_free_ctl_blks(wcn); wcn36xx_dxe_free_ctl_blks(wcn);
out_free_dxe_pool:
wcn36xx_dxe_free_mem_pools(wcn);
out_smd_close: out_smd_close:
wcn36xx_smd_close(wcn); wcn36xx_smd_close(wcn);
out_err: out_err:

View File

@ -390,22 +390,23 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
} }
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->p2p_wdev_mutex);
/* social scan on P2P_DEVICE is handled as p2p search */ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
wil_p2p_is_social_scan(request)) {
if (!wil->p2p.p2p_dev_started) { if (!wil->p2p.p2p_dev_started) {
wil_err(wil, "P2P search requested on stopped P2P device\n"); wil_err(wil, "P2P search requested on stopped P2P device\n");
rc = -EIO; rc = -EIO;
goto out; goto out;
} }
wil->scan_request = request; /* social scan on P2P_DEVICE is handled as p2p search */
wil->radio_wdev = wdev; if (wil_p2p_is_social_scan(request)) {
rc = wil_p2p_search(wil, request); wil->scan_request = request;
if (rc) { wil->radio_wdev = wdev;
wil->radio_wdev = wil_to_wdev(wil); rc = wil_p2p_search(wil, request);
wil->scan_request = NULL; if (rc) {
wil->radio_wdev = wil_to_wdev(wil);
wil->scan_request = NULL;
}
goto out;
} }
goto out;
} }
(void)wil_p2p_stop_discovery(wil); (void)wil_p2p_stop_discovery(wil);
@ -415,9 +416,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
for (i = 0; i < request->n_ssids; i++) { for (i = 0; i < request->n_ssids; i++) {
wil_dbg_misc(wil, "SSID[%d]", i); wil_dbg_misc(wil, "SSID[%d]", i);
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
request->ssids[i].ssid, request->ssids[i].ssid,
request->ssids[i].ssid_len); request->ssids[i].ssid_len, true);
} }
if (request->n_ssids) if (request->n_ssids)
@ -454,8 +455,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
} }
if (request->ie_len) if (request->ie_len)
print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("Scan IE ", DUMP_PREFIX_OFFSET, 16, 1,
request->ie, request->ie_len); request->ie, request->ie_len, true);
else else
wil_dbg_misc(wil, "Scan has no IE's\n"); wil_dbg_misc(wil, "Scan has no IE's\n");
@ -679,6 +680,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
if (rc == 0) { if (rc == 0) {
netif_carrier_on(ndev); netif_carrier_on(ndev);
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
wil->bss = bss;
/* Connect can take lots of time */ /* Connect can take lots of time */
mod_timer(&wil->connect_timer, mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000)); jiffies + msecs_to_jiffies(2000));
@ -707,6 +710,7 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return 0; return 0;
} }
wil->locally_generated_disc = true;
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
WMI_DISCONNECT_EVENTID, NULL, 0, WMI_DISCONNECT_EVENTID, NULL, 0,
WIL6210_DISCONNECT_TO_MS); WIL6210_DISCONNECT_TO_MS);
@ -760,7 +764,8 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
*/ */
wil_dbg_misc(wil, "mgmt_tx\n"); wil_dbg_misc(wil, "mgmt_tx\n");
print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len); wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
len, true);
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
if (!cmd) { if (!cmd) {
@ -1093,18 +1098,18 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
static void wil_print_bcon_data(struct cfg80211_beacon_data *b) static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
{ {
print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("head ", DUMP_PREFIX_OFFSET, 16, 1,
b->head, b->head_len); b->head, b->head_len, true);
print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("tail ", DUMP_PREFIX_OFFSET, 16, 1,
b->tail, b->tail_len); b->tail, b->tail_len, true);
print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("BCON IE ", DUMP_PREFIX_OFFSET, 16, 1,
b->beacon_ies, b->beacon_ies_len); b->beacon_ies, b->beacon_ies_len, true);
print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("PROBE ", DUMP_PREFIX_OFFSET, 16, 1,
b->probe_resp, b->probe_resp_len); b->probe_resp, b->probe_resp_len, true);
print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("PROBE IE ", DUMP_PREFIX_OFFSET, 16, 1,
b->proberesp_ies, b->proberesp_ies_len); b->proberesp_ies, b->proberesp_ies_len, true);
print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("ASSOC IE ", DUMP_PREFIX_OFFSET, 16, 1,
b->assocresp_ies, b->assocresp_ies_len); b->assocresp_ies, b->assocresp_ies_len, true);
} }
/* internal functions for device reset and starting AP */ /* internal functions for device reset and starting AP */
@ -1198,6 +1203,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
wil->pbss = pbss; wil->pbss = pbss;
netif_carrier_on(ndev); netif_carrier_on(ndev);
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go); rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go);
if (rc) if (rc)
@ -1213,6 +1219,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
wmi_pcp_stop(wil); wmi_pcp_stop(wil);
err_pcp_start: err_pcp_start:
netif_carrier_off(ndev); netif_carrier_off(ndev);
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
out: out:
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
return rc; return rc;
@ -1298,8 +1305,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
info->dtim_period); info->dtim_period);
wil_dbg_misc(wil, "PBSS %d\n", info->pbss); wil_dbg_misc(wil, "PBSS %d\n", info->pbss);
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
info->ssid, info->ssid_len); info->ssid, info->ssid_len, true);
wil_print_bcon_data(bcon); wil_print_bcon_data(bcon);
wil_print_crypto(wil, crypto); wil_print_crypto(wil, crypto);
@ -1319,6 +1326,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
wil_dbg_misc(wil, "stop_ap\n"); wil_dbg_misc(wil, "stop_ap\n");
netif_carrier_off(ndev); netif_carrier_off(ndev);
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
wil_set_recovery_state(wil, fw_recovery_idle); wil_set_recovery_state(wil, fw_recovery_idle);
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);

View File

@ -30,8 +30,8 @@ bool debug_fw; /* = false; */
module_param(debug_fw, bool, 0444); module_param(debug_fw, bool, 0444);
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug"); MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
static bool oob_mode; static u8 oob_mode;
module_param(oob_mode, bool, 0444); module_param(oob_mode, byte, 0444);
MODULE_PARM_DESC(oob_mode, MODULE_PARM_DESC(oob_mode,
" enable out of the box (OOB) mode in FW, for diagnostics and certification"); " enable out of the box (OOB) mode in FW, for diagnostics and certification");
@ -274,15 +274,20 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
wil_bcast_fini(wil); wil_bcast_fini(wil);
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, NULL, true);
netif_carrier_off(ndev); netif_carrier_off(ndev);
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
if (test_bit(wil_status_fwconnected, wil->status)) { if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status); clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code, cfg80211_disconnected(ndev, reason_code,
NULL, 0, false, GFP_KERNEL); NULL, 0,
wil->locally_generated_disc,
GFP_KERNEL);
wil->locally_generated_disc = false;
} else if (test_bit(wil_status_fwconnecting, wil->status)) { } else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL); GFP_KERNEL);
wil->bss = NULL;
} }
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_status_fwconnecting, wil->status);
break; break;
@ -304,10 +309,34 @@ static void wil_disconnect_worker(struct work_struct *work)
{ {
struct wil6210_priv *wil = container_of(work, struct wil6210_priv *wil = container_of(work,
struct wil6210_priv, disconnect_worker); struct wil6210_priv, disconnect_worker);
struct net_device *ndev = wil_to_ndev(wil);
int rc;
struct {
struct wmi_cmd_hdr wmi;
struct wmi_disconnect_event evt;
} __packed reply;
mutex_lock(&wil->mutex); if (test_bit(wil_status_fwconnected, wil->status))
_wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false); /* connect succeeded after all */
mutex_unlock(&wil->mutex); return;
if (!test_bit(wil_status_fwconnecting, wil->status))
/* already disconnected */
return;
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
WMI_DISCONNECT_EVENTID, &reply, sizeof(reply),
WIL6210_DISCONNECT_TO_MS);
if (rc) {
wil_err(wil, "disconnect error %d\n", rc);
return;
}
wil_update_net_queues_bh(wil, NULL, true);
netif_carrier_off(ndev);
cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
clear_bit(wil_status_fwconnecting, wil->status);
} }
static void wil_connect_timer_fn(ulong x) static void wil_connect_timer_fn(ulong x)
@ -555,6 +584,12 @@ int wil_priv_init(struct wil6210_priv *wil)
return -EAGAIN; return -EAGAIN;
} }
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
{
if (wil->platform_ops.bus_request)
wil->platform_ops.bus_request(wil->platform_handle, kbps);
}
/** /**
* wil6210_disconnect - disconnect one connection * wil6210_disconnect - disconnect one connection
* @wil: driver context * @wil: driver context
@ -607,13 +642,25 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
wil_w(wil, RGF_USER_USER_CPU_0, 1); wil_w(wil, RGF_USER_USER_CPU_0, 1);
} }
static void wil_set_oob_mode(struct wil6210_priv *wil, bool enable) static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode)
{ {
wil_info(wil, "enable=%d\n", enable); wil_info(wil, "oob_mode to %d\n", mode);
if (enable) switch (mode) {
case 0:
wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE |
BIT_USER_OOB_R2_MODE);
break;
case 1:
wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE);
wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE); wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
else break;
case 2:
wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE); wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE);
break;
default:
wil_err(wil, "invalid oob_mode: %d\n", mode);
}
} }
static int wil_target_reset(struct wil6210_priv *wil) static int wil_target_reset(struct wil6210_priv *wil)
@ -1066,9 +1113,7 @@ int __wil_up(struct wil6210_priv *wil)
napi_enable(&wil->napi_tx); napi_enable(&wil->napi_tx);
set_bit(wil_status_napi_en, wil->status); set_bit(wil_status_napi_en, wil->status);
if (wil->platform_ops.bus_request) wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
wil->platform_ops.bus_request(wil->platform_handle,
WIL_MAX_BUS_REQUEST_KBPS);
return 0; return 0;
} }
@ -1092,8 +1137,7 @@ int __wil_down(struct wil6210_priv *wil)
set_bit(wil_status_resetting, wil->status); set_bit(wil_status_resetting, wil->status);
if (wil->platform_ops.bus_request) wil6210_bus_request(wil, 0);
wil->platform_ops.bus_request(wil->platform_handle, 0);
wil_disable_irq(wil); wil_disable_irq(wil);
if (test_and_clear_bit(wil_status_napi_en, wil->status)) { if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
@ -1154,6 +1198,7 @@ void wil_halp_vote(struct wil6210_priv *wil)
wil->halp.ref_cnt); wil->halp.ref_cnt);
if (++wil->halp.ref_cnt == 1) { if (++wil->halp.ref_cnt == 1) {
reinit_completion(&wil->halp.comp);
wil6210_set_halp(wil); wil6210_set_halp(wil);
rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies); rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
if (!rc) { if (!rc) {

View File

@ -211,6 +211,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(dev, "wil_if_alloc failed: %d\n", rc); dev_err(dev, "wil_if_alloc failed: %d\n", rc);
return rc; return rc;
} }
wil->pdev = pdev; wil->pdev = pdev;
pci_set_drvdata(pdev, wil); pci_set_drvdata(pdev, wil);
/* rollback to if_free */ /* rollback to if_free */
@ -224,6 +225,21 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
} }
/* rollback to err_plat */ /* rollback to err_plat */
/* device supports 48bit addresses */
rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (rc) {
dev_err(dev, "dma_set_mask_and_coherent(48) failed: %d\n", rc);
rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (rc) {
dev_err(dev,
"dma_set_mask_and_coherent(32) failed: %d\n",
rc);
goto err_plat;
}
} else {
wil->use_extended_dma_addr = 1;
}
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) { if (rc) {
wil_err(wil, wil_err(wil,

View File

@ -107,13 +107,28 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
/* Allocate pring buffer and descriptors. /* Allocate pring buffer and descriptors.
* vring->va should be aligned on its size rounded up to power of 2 * vring->va should be aligned on its size rounded up to power of 2
* This is granted by the dma_alloc_coherent * This is granted by the dma_alloc_coherent.
*
* HW has limitation that all vrings addresses must share the same
* upper 16 msb bits part of 48 bits address. To workaround that,
* if we are using 48 bit addresses switch to 32 bit allocation
* before allocating vring memory.
*
* There's no check for the return value of dma_set_mask_and_coherent,
* since we assume if we were able to set the mask during
* initialization in this system it will not fail if we set it again
*/ */
if (wil->use_extended_dma_addr)
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
pmc->pring_va = dma_alloc_coherent(dev, pmc->pring_va = dma_alloc_coherent(dev,
sizeof(struct vring_tx_desc) * num_descriptors, sizeof(struct vring_tx_desc) * num_descriptors,
&pmc->pring_pa, &pmc->pring_pa,
GFP_KERNEL); GFP_KERNEL);
if (wil->use_extended_dma_addr)
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
wil_dbg_misc(wil, wil_dbg_misc(wil,
"pmc_alloc: allocated pring %p => %pad. %zd x %d = total %zd bytes\n", "pmc_alloc: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
pmc->pring_va, &pmc->pring_pa, pmc->pring_va, &pmc->pring_pa,

View File

@ -123,15 +123,32 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
vring->va = NULL; vring->va = NULL;
return -ENOMEM; return -ENOMEM;
} }
/* vring->va should be aligned on its size rounded up to power of 2 /* vring->va should be aligned on its size rounded up to power of 2
* This is granted by the dma_alloc_coherent * This is granted by the dma_alloc_coherent.
*
* HW has limitation that all vrings addresses must share the same
* upper 16 msb bits part of 48 bits address. To workaround that,
* if we are using 48 bit addresses switch to 32 bit allocation
* before allocating vring memory.
*
* There's no check for the return value of dma_set_mask_and_coherent,
* since we assume if we were able to set the mask during
* initialization in this system it will not fail if we set it again
*/ */
if (wil->use_extended_dma_addr)
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL);
if (!vring->va) { if (!vring->va) {
kfree(vring->ctx); kfree(vring->ctx);
vring->ctx = NULL; vring->ctx = NULL;
return -ENOMEM; return -ENOMEM;
} }
if (wil->use_extended_dma_addr)
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
/* initially, all descriptors are SW owned /* initially, all descriptors are SW owned
* For Tx and Rx, ownership bit is at the same location, thus * For Tx and Rx, ownership bit is at the same location, thus
* we can use any * we can use any

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -40,6 +40,7 @@ extern bool disable_ap_sme;
#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */ #define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */
#define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */ #define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
/** /**
@ -139,6 +140,7 @@ struct RGF_ICR {
#define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_1 (0x880004)
#define RGF_USER_USAGE_6 (0x880018) #define RGF_USER_USAGE_6 (0x880018)
#define BIT_USER_OOB_MODE BIT(31) #define BIT_USER_OOB_MODE BIT(31)
#define BIT_USER_OOB_R2_MODE BIT(30)
#define RGF_USER_HW_MACHINE_STATE (0x8801dc) #define RGF_USER_HW_MACHINE_STATE (0x8801dc)
#define HW_MACHINE_BOOT_DONE (0x3fffffd) #define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0) #define RGF_USER_USER_CPU_0 (0x8801e0)
@ -612,6 +614,8 @@ struct wil6210_priv {
u16 channel; /* relevant in AP mode */ u16 channel; /* relevant in AP mode */
int sinfo_gen; int sinfo_gen;
u32 ap_isolate; /* no intra-BSS communication */ u32 ap_isolate; /* no intra-BSS communication */
struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
int locally_generated_disc; /* relevant in STA mode */
/* interrupt moderation */ /* interrupt moderation */
u32 tx_max_burst_duration; u32 tx_max_burst_duration;
u32 tx_interframe_timeout; u32 tx_interframe_timeout;
@ -657,6 +661,7 @@ struct wil6210_priv {
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_sta_info sta[WIL6210_MAX_CID]; struct wil_sta_info sta[WIL6210_MAX_CID];
int bcast_vring; int bcast_vring;
bool use_extended_dma_addr; /* indicates whether we are using 48 bits */
/* scan */ /* scan */
struct cfg80211_scan_request *scan_request; struct cfg80211_scan_request *scan_request;
@ -764,6 +769,12 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val)
print_hex_dump_debug("DBG[ WMI]" prefix_str,\ print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \ prefix_type, rowsize, \
groupsize, buf, len, ascii) groupsize, buf, len, ascii)
#define wil_hex_dump_misc(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
print_hex_dump_debug("DBG[MISC]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
#else /* defined(CONFIG_DYNAMIC_DEBUG) */ #else /* defined(CONFIG_DYNAMIC_DEBUG) */
static inline static inline
void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize, void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize,
@ -776,6 +787,12 @@ void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii) int groupsize, const void *buf, size_t len, bool ascii)
{ {
} }
static inline
void wil_hex_dump_misc(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii)
{
}
#endif /* defined(CONFIG_DYNAMIC_DEBUG) */ #endif /* defined(CONFIG_DYNAMIC_DEBUG) */
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
@ -899,7 +916,7 @@ int wmi_pcp_stop(struct wil6210_priv *wil);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable); int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
int wmi_abort_scan(struct wil6210_priv *wil); int wmi_abort_scan(struct wil6210_priv *wil);
void wil_abort_scan(struct wil6210_priv *wil, bool sync); void wil_abort_scan(struct wil6210_priv *wil, bool sync);
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event); u16 reason_code, bool from_event);
void wil_probe_client_flush(struct wil6210_priv *wil); void wil_probe_client_flush(struct wil6210_priv *wil);

View File

@ -565,6 +565,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (rc) { if (rc) {
netif_carrier_off(ndev); netif_carrier_off(ndev);
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
wil_err(wil, "cfg80211_connect_result with failure\n"); wil_err(wil, "cfg80211_connect_result with failure\n");
cfg80211_connect_result(ndev, evt->bssid, NULL, 0, cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
NULL, 0, NULL, 0,
@ -572,12 +573,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
GFP_KERNEL); GFP_KERNEL);
goto out; goto out;
} else { } else {
cfg80211_connect_result(ndev, evt->bssid, struct wiphy *wiphy = wil_to_wiphy(wil);
assoc_req_ie, assoc_req_ielen,
assoc_resp_ie, assoc_resp_ielen, cfg80211_ref_bss(wiphy, wil->bss);
WLAN_STATUS_SUCCESS, cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
GFP_KERNEL); assoc_req_ie, assoc_req_ielen,
assoc_resp_ie, assoc_resp_ielen,
WLAN_STATUS_SUCCESS, GFP_KERNEL,
NL80211_TIMEOUT_UNSPECIFIED);
} }
wil->bss = NULL;
} else if ((wdev->iftype == NL80211_IFTYPE_AP) || } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) { (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
if (rc) { if (rc) {
@ -1492,6 +1497,7 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason); wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
wil->locally_generated_disc = true;
if (del_sta) { if (del_sta) {
ether_addr_copy(del_sta_cmd.dst_mac, mac); ether_addr_copy(del_sta_cmd.dst_mac, mac);
rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd, rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
@ -1733,14 +1739,19 @@ int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
void wmi_event_flush(struct wil6210_priv *wil) void wmi_event_flush(struct wil6210_priv *wil)
{ {
ulong flags;
struct pending_wmi_event *evt, *t; struct pending_wmi_event *evt, *t;
wil_dbg_wmi(wil, "event_flush\n"); wil_dbg_wmi(wil, "event_flush\n");
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
list_del(&evt->list); list_del(&evt->list);
kfree(evt); kfree(evt);
} }
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
} }
static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,