Commit d9378080 authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from ath.git

Major changes:

wil6210:

* add modparam for bcast ring size
* support hidden SSID
* add per-MCS Rx stats
parents ed8e0ed5 3e2d8e1b
...@@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ...@@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.name = "qca988x hw2.0", .name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7, .uart_pin = 7,
.has_shifted_cc_wraparound = true,
.fw = { .fw = {
.dir = QCA988X_HW_2_0_FW_DIR, .dir = QCA988X_HW_2_0_FW_DIR,
.fw = QCA988X_HW_2_0_FW_FILE, .fw = QCA988X_HW_2_0_FW_FILE,
...@@ -1084,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) ...@@ -1084,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
if (status) if (status)
goto err; goto err;
/* Some of of qca988x solutions are having global reset issue
* during target initialization. Bypassing PLL setting before
* downloading firmware and letting the SoC run on REF_CLK is
* fixing the problem. Corresponding firmware change is also needed
* to set the clock source once the target is initialized.
*/
if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
ar->fw_features)) {
status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);
if (status) {
ath10k_err(ar, "could not write to skip_clock_init: %d\n",
status);
goto err;
}
}
status = ath10k_download_fw(ar, mode); status = ath10k_download_fw(ar, mode);
if (status) if (status)
goto err; goto err;
......
...@@ -284,15 +284,6 @@ struct ath10k_sta { ...@@ -284,15 +284,6 @@ struct ath10k_sta {
#endif #endif
}; };
struct ath10k_chanctx {
/* Used to story copy of chanctx_conf to avoid inconsistencies. Ideally
* mac80211 should allow some sort of explicit locking to guarantee
* that the publicly available chanctx_conf can be accessed safely at
* all times.
*/
struct ieee80211_chanctx_conf conf;
};
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
enum ath10k_beacon_state { enum ath10k_beacon_state {
...@@ -468,6 +459,9 @@ enum ath10k_fw_features { ...@@ -468,6 +459,9 @@ enum ath10k_fw_features {
*/ */
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
/* Firmware supports bypassing PLL setting on init. */
ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9,
/* keep last */ /* keep last */
ATH10K_FW_FEATURE_COUNT, ATH10K_FW_FEATURE_COUNT,
}; };
...@@ -577,6 +571,13 @@ struct ath10k { ...@@ -577,6 +571,13 @@ struct ath10k {
u32 patch_load_addr; u32 patch_load_addr;
int uart_pin; int uart_pin;
/* This is true if given HW chip has a quirky Cycle Counter
* wraparound which resets to 0x7fffffff instead of 0. All
* other CC related counters (e.g. Rx Clear Count) are divided
* by 2 so they never wraparound themselves.
*/
bool has_shifted_cc_wraparound;
struct ath10k_hw_params_fw { struct ath10k_hw_params_fw {
const char *dir; const char *dir;
const char *fw; const char *fw;
...@@ -694,6 +695,14 @@ struct ath10k { ...@@ -694,6 +695,14 @@ struct ath10k {
u32 survey_last_cycle_count; u32 survey_last_cycle_count;
struct survey_info survey[ATH10K_NUM_CHANS]; struct survey_info survey[ATH10K_NUM_CHANS];
/* Channel info events are expected to come in pairs without and with
* COMPLETE flag set respectively for each channel visit during scan.
*
* However there are deviations from this rule. This flag is used to
* avoid reporting garbage data.
*/
bool ch_info_can_report_survey;
struct dfs_pattern_detector *dfs_detector; struct dfs_pattern_detector *dfs_detector;
unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */ unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include "core.h"
#include "hw.h" #include "hw.h"
const struct ath10k_hw_regs qca988x_regs = { const struct ath10k_hw_regs qca988x_regs = {
...@@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = { ...@@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = {
.soc_chip_id_address = 0x000f0, .soc_chip_id_address = 0x000f0,
.scratch_3_address = 0x0028, .scratch_3_address = 0x0028,
}; };
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_fix = 0;
survey->filled |= SURVEY_INFO_TIME |
SURVEY_INFO_TIME_BUSY;
if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) {
cc_fix = 0x7fffffff;
survey->filled &= ~SURVEY_INFO_TIME_BUSY;
}
cc -= cc_prev - cc_fix;
rcc -= rcc_prev;
survey->time = CCNT_TO_MSEC(cc);
survey->time_busy = CCNT_TO_MSEC(rcc);
}
...@@ -169,6 +169,9 @@ struct ath10k_hw_regs { ...@@ -169,6 +169,9 @@ struct ath10k_hw_regs {
extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca988x_regs;
extern const struct ath10k_hw_regs qca6174_regs; extern const struct ath10k_hw_regs qca6174_regs;
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
...@@ -449,6 +452,9 @@ enum ath10k_hw_rate_cck { ...@@ -449,6 +452,9 @@ enum ath10k_hw_rate_cck {
#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
#define CPU_INTR_ADDRESS 0x0010 #define CPU_INTR_ADDRESS 0x0010
/* Cycle counters are running at 88MHz */
#define CCNT_TO_MSEC(x) ((x) / 88000)
/* Firmware indications to the Host via SCRATCH_3 register. */ /* Firmware indications to the Host via SCRATCH_3 register. */
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
#define FW_IND_EVENT_PENDING 1 #define FW_IND_EVENT_PENDING 1
......
...@@ -3949,83 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar) ...@@ -3949,83 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar)
return ret; return ret;
} }
static void ath10k_mac_chan_reconfigure(struct ath10k *ar)
{
struct ath10k_vif *arvif;
struct cfg80211_chan_def def;
int ret;
lockdep_assert_held(&ar->conf_mutex);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chan reconfigure\n");
/* First stop monitor interface. Some FW versions crash if there's a
* lone monitor interface. */
if (ar->monitor_started)
ath10k_monitor_stop(ar);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
continue;
if (!arvif->is_up)
continue;
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret) {
ath10k_warn(ar, "failed to down vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
}
/* all vdevs are downed now - attempt to restart and re-up them */
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
continue;
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
ret = ath10k_mac_setup_bcn_tmpl(arvif);
if (ret)
ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
ret);
ret = ath10k_mac_setup_prb_tmpl(arvif);
if (ret)
ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
ret);
if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
continue;
ret = ath10k_vdev_restart(arvif, &def);
if (ret) {
ath10k_warn(ar, "failed to restart vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
if (!arvif->is_up)
continue;
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
arvif->vdev_id, ret);
continue;
}
}
ath10k_monitor_recalc(ar);
}
static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
{ {
int ret; int ret;
...@@ -6144,7 +6067,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw, ...@@ -6144,7 +6067,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
} }
static void static void
ath10k_mac_update_rx_channel(struct ath10k *ar) ath10k_mac_update_rx_channel(struct ath10k *ar,
struct ieee80211_chanctx_conf *ctx,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs)
{ {
struct cfg80211_chan_def *def = NULL; struct cfg80211_chan_def *def = NULL;
...@@ -6154,6 +6080,9 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) ...@@ -6154,6 +6080,9 @@ ath10k_mac_update_rx_channel(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
lockdep_assert_held(&ar->data_lock); lockdep_assert_held(&ar->data_lock);
WARN_ON(ctx && vifs);
WARN_ON(vifs && n_vifs != 1);
/* 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
* ppdu on Rx may reduce performance on low-end systems. It should be * ppdu on Rx may reduce performance on low-end systems. It should be
...@@ -6165,36 +6094,28 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) ...@@ -6165,36 +6094,28 @@ ath10k_mac_update_rx_channel(struct ath10k *ar)
* affected much. * affected much.
*/ */
rcu_read_lock(); rcu_read_lock();
if (ath10k_mac_num_chanctxs(ar) == 1) { if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) {
ieee80211_iter_chan_contexts_atomic(ar->hw, ieee80211_iter_chan_contexts_atomic(ar->hw,
ath10k_mac_get_any_chandef_iter, ath10k_mac_get_any_chandef_iter,
&def); &def);
if (vifs)
def = &vifs[0].new_ctx->def;
ar->rx_channel = def->chan; ar->rx_channel = def->chan;
} else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) {
ar->rx_channel = ctx->def.chan;
} else { } else {
ar->rx_channel = NULL; ar->rx_channel = NULL;
} }
rcu_read_unlock(); rcu_read_unlock();
} }
static void
ath10k_mac_chan_ctx_init(struct ath10k *ar,
struct ath10k_chanctx *arctx,
struct ieee80211_chanctx_conf *conf)
{
lockdep_assert_held(&ar->conf_mutex);
lockdep_assert_held(&ar->data_lock);
memset(arctx, 0, sizeof(*arctx));
arctx->conf = *conf;
}
static int static int
ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx) struct ieee80211_chanctx_conf *ctx)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_chanctx *arctx = (void *)ctx->drv_priv;
ath10k_dbg(ar, ATH10K_DBG_MAC, ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac chanctx add freq %hu width %d ptr %p\n", "mac chanctx add freq %hu width %d ptr %p\n",
...@@ -6203,8 +6124,7 @@ ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, ...@@ -6203,8 +6124,7 @@ ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ath10k_mac_chan_ctx_init(ar, arctx, ctx); ath10k_mac_update_rx_channel(ar, ctx, NULL, 0);
ath10k_mac_update_rx_channel(ar);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
ath10k_recalc_radar_detection(ar); ath10k_recalc_radar_detection(ar);
...@@ -6228,7 +6148,7 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw, ...@@ -6228,7 +6148,7 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ath10k_mac_update_rx_channel(ar); ath10k_mac_update_rx_channel(ar, NULL, NULL, 0);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
ath10k_recalc_radar_detection(ar); ath10k_recalc_radar_detection(ar);
...@@ -6243,16 +6163,12 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, ...@@ -6243,16 +6163,12 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
u32 changed) u32 changed)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_chanctx *arctx = (void *)ctx->drv_priv;
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
ath10k_dbg(ar, ATH10K_DBG_MAC, ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac chanctx change freq %hu->%hu width %d->%d ptr %p changed %x\n", "mac chanctx change freq %hu width %d ptr %p changed %x\n",
arctx->conf.def.chan->center_freq, ctx->def.chan->center_freq, ctx->def.width, ctx, changed);
ctx->def.chan->center_freq,
arctx->conf.def.width, ctx->def.width,
ctx, changed);
/* This shouldn't really happen because channel switching should use /* This shouldn't really happen because channel switching should use
* switch_vif_chanctx(). * switch_vif_chanctx().
...@@ -6260,10 +6176,6 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, ...@@ -6260,10 +6176,6 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
goto unlock; goto unlock;
spin_lock_bh(&ar->data_lock);
arctx->conf = *ctx;
spin_unlock_bh(&ar->data_lock);
ath10k_recalc_radar_detection(ar); ath10k_recalc_radar_detection(ar);
/* FIXME: How to configure Rx chains properly? */ /* FIXME: How to configure Rx chains properly? */
...@@ -6283,7 +6195,6 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, ...@@ -6283,7 +6195,6 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx) struct ieee80211_chanctx_conf *ctx)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_chanctx *arctx = (void *)ctx->drv_priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv;
int ret; int ret;
...@@ -6298,11 +6209,11 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, ...@@ -6298,11 +6209,11 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
return -EBUSY; return -EBUSY;
} }
ret = ath10k_vdev_start(arvif, &arctx->conf.def); ret = ath10k_vdev_start(arvif, &ctx->def);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n", ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n",
arvif->vdev_id, vif->addr, arvif->vdev_id, vif->addr,
arctx->conf.def.chan->center_freq, ret); ctx->def.chan->center_freq, ret);
goto err; goto err;
} }
...@@ -6377,7 +6288,7 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, ...@@ -6377,7 +6288,7 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif; struct ath10k_vif *arvif;
struct ath10k_chanctx *arctx_new, *arctx_old; int ret;
int i; int i;
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
...@@ -6386,38 +6297,81 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, ...@@ -6386,38 +6297,81 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
"mac chanctx switch n_vifs %d mode %d\n", "mac chanctx switch n_vifs %d mode %d\n",
n_vifs, mode); n_vifs, mode);
spin_lock_bh(&ar->data_lock); /* First stop monitor interface. Some FW versions crash if there's a
* lone monitor interface.
*/
if (ar->monitor_started)
ath10k_monitor_stop(ar);
for (i = 0; i < n_vifs; i++) { for (i = 0; i < n_vifs; i++) {
arvif = ath10k_vif_to_arvif(vifs[i].vif); arvif = ath10k_vif_to_arvif(vifs[i].vif);
arctx_new = (void *)vifs[i].new_ctx->drv_priv;
arctx_old = (void *)vifs[i].old_ctx->drv_priv;
ath10k_dbg(ar, ATH10K_DBG_MAC, ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d ptr %p->%p\n", "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
arvif->vdev_id, arvif->vdev_id,
vifs[i].old_ctx->def.chan->center_freq, vifs[i].old_ctx->def.chan->center_freq,
vifs[i].new_ctx->def.chan->center_freq, vifs[i].new_ctx->def.chan->center_freq,
vifs[i].old_ctx->def.width, vifs[i].old_ctx->def.width,
vifs[i].new_ctx->def.width, vifs[i].new_ctx->def.width);
arctx_old, arctx_new);
if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { if (WARN_ON(!arvif->is_started))
ath10k_mac_chan_ctx_init(ar, arctx_new, continue;
vifs[i].new_ctx);
}
arctx_new->conf = *vifs[i].new_ctx; if (WARN_ON(!arvif->is_up))
continue;
/* FIXME: ath10k_mac_chan_reconfigure() uses current, i.e. not ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
* yet updated chanctx_conf pointer. if (ret) {
*/ ath10k_warn(ar, "failed to down vdev %d: %d\n",
arctx_old->conf = *vifs[i].new_ctx; arvif->vdev_id, ret);
continue;
}
} }
ath10k_mac_update_rx_channel(ar);
/* All relevant vdevs are downed and associated channel resources
* should be available for the channel switch now.
*/
spin_lock_bh(&ar->data_lock);
ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
/* FIXME: Reconfigure only affected vifs */ for (i = 0; i < n_vifs; i++) {
ath10k_mac_chan_reconfigure(ar); arvif = ath10k_vif_to_arvif(vifs[i].vif);
if (WARN_ON(!arvif->is_started))
continue;
if (WARN_ON(!arvif->is_up))
continue;
ret = ath10k_mac_setup_bcn_tmpl(arvif);
if (ret)
ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
ret);
ret = ath10k_mac_setup_prb_tmpl(arvif);
if (ret)
ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
ret);
ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
if (ret) {
ath10k_warn(ar, "failed to restart vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
arvif->vdev_id, ret);
continue;
}
}
ath10k_monitor_recalc(ar);
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
return 0; return 0;
...@@ -6914,7 +6868,6 @@ int ath10k_mac_register(struct ath10k *ar) ...@@ -6914,7 +6868,6 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->vif_data_size = sizeof(struct ath10k_vif); ar->hw->vif_data_size = sizeof(struct ath10k_vif);
ar->hw->sta_data_size = sizeof(struct ath10k_sta); ar->hw->sta_data_size = sizeof(struct ath10k_sta);
ar->hw->chanctx_data_size = sizeof(struct ath10k_chanctx);
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
......
...@@ -1424,7 +1424,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) ...@@ -1424,7 +1424,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
struct ath10k_ce_ring *ce_ring; struct ath10k_ce_ring *ce_ring;
struct ce_desc *ce_desc; struct ce_desc *ce_desc;
struct sk_buff *skb; struct sk_buff *skb;
unsigned int id;
int i; int i;
ar = pci_pipe->hif_ce_state; ar = pci_pipe->hif_ce_state;
...@@ -1448,8 +1447,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) ...@@ -1448,8 +1447,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
continue; continue;
ce_ring->per_transfer_context[i] = NULL; ce_ring->per_transfer_context[i] = NULL;
id = MS(__le16_to_cpu(ce_desc[i].flags),
CE_DESC_FLAGS_META_DATA);
ar_pci->msg_callbacks_current.tx_completion(ar, skb); ar_pci->msg_callbacks_current.tx_completion(ar, skb);
} }
...@@ -2850,6 +2847,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2850,6 +2847,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ath10k_pci_free_pipes(ar); ath10k_pci_free_pipes(ar);
err_sleep: err_sleep:
ath10k_pci_sleep_sync(ar);
ath10k_pci_release(ar); ath10k_pci_release(ar);
err_core_destroy: err_core_destroy:
...@@ -2927,8 +2925,10 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); ...@@ -2927,8 +2925,10 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
/* QCA6174 2.1 firmware files */ /* QCA6174 2.1 firmware files */
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE);
/* QCA6174 3.1 firmware files */ /* QCA6174 3.1 firmware files */
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
...@@ -402,7 +402,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -402,7 +402,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
return; goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len); trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
...@@ -521,6 +521,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -521,6 +521,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
break; break;
} }
out:
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "testmode.h" #include "testmode.h"
#include "wmi-ops.h" #include "wmi-ops.h"
#include "p2p.h" #include "p2p.h"
#include "hw.h"
/* MAIN WMI cmd track */ /* MAIN WMI cmd track */
static struct wmi_cmd_map wmi_cmd_map = { static struct wmi_cmd_map wmi_cmd_map = {
...@@ -1450,6 +1451,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -1450,6 +1451,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg); ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret); ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
dev_kfree_skb(skb);
return ret; return ret;
} }
...@@ -1636,20 +1638,22 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) ...@@ -1636,20 +1638,22 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
} }
if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) { if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
/* During scanning chan info is reported twice for each if (ar->ch_info_can_report_survey) {
* visited channel. The reported cycle count is global survey = &ar->survey[idx];
* and per-channel cycle count must be calculated */ survey->noise = noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM;
cycle_count -= ar->survey_last_cycle_count;
rx_clear_count -= ar->survey_last_rx_clear_count; ath10k_hw_fill_survey_time(ar,
survey,
survey = &ar->survey[idx]; cycle_count,
survey->time = WMI_CHAN_INFO_MSEC(cycle_count); rx_clear_count,
survey->time_busy = WMI_CHAN_INFO_MSEC(rx_clear_count); ar->survey_last_cycle_count,
survey->noise = noise_floor; ar->survey_last_rx_clear_count);
survey->filled = SURVEY_INFO_TIME | }
SURVEY_INFO_TIME_BUSY |
SURVEY_INFO_NOISE_DBM; ar->ch_info_can_report_survey = false;
} else {
ar->ch_info_can_report_survey = true;
} }
ar->survey_last_rx_clear_count = rx_clear_count; ar->survey_last_rx_clear_count = rx_clear_count;
...@@ -3219,7 +3223,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -3219,7 +3223,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
return; goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len); trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
...@@ -3323,6 +3327,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -3323,6 +3327,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
break; break;
} }
out:
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
...@@ -3336,7 +3341,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -3336,7 +3341,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
return; goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len); trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
...@@ -3459,7 +3464,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -3459,7 +3464,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
return; goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len); trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
...@@ -3567,6 +3572,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -3567,6 +3572,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
break; break;
} }
out:
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
......
...@@ -4665,7 +4665,6 @@ struct wmi_peer_sta_kickout_event { ...@@ -4665,7 +4665,6 @@ struct wmi_peer_sta_kickout_event {
} __packed; } __packed;
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
#define WMI_CHAN_INFO_MSEC(x) ((x) / 88000)
/* Beacon filter wmi command info */ /* Beacon filter wmi command info */
#define BCN_FLT_MAX_SUPPORTED_IES 256 #define BCN_FLT_MAX_SUPPORTED_IES 256
......
...@@ -1527,8 +1527,8 @@ struct wmi_connect_event { ...@@ -1527,8 +1527,8 @@ struct wmi_connect_event {
__le32 nw_type; __le32 nw_type;
} sta; } sta;
struct { struct {
u8 phymode;
u8 aid; u8 aid;
u8 phymode;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
u8 auth; u8 auth;
u8 keymgmt; u8 keymgmt;
......
...@@ -289,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, ...@@ -289,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
} }
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
for (i = 0; i < request->n_ssids; i++) {
wil_dbg_misc(wil, "SSID[%d]", i);
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
request->ssids[i].ssid,
request->ssids[i].ssid_len);
}
if (request->n_ssids)
rc = wmi_set_ssid(wil, request->ssids[0].ssid_len,
request->ssids[0].ssid);
else
rc = wmi_set_ssid(wil, 0, NULL);
if (rc) {
wil_err(wil, "set SSID for scan request failed: %d\n", rc);
return rc;
}
wil->scan_request = request; wil->scan_request = request;
mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
...@@ -778,6 +798,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, ...@@ -778,6 +798,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
const u8 *pr_ies = NULL; const u8 *pr_ies = NULL;
size_t pr_ies_len = 0; size_t pr_ies_len = 0;
u8 hidden_ssid;
wil_dbg_misc(wil, "%s()\n", __func__); wil_dbg_misc(wil, "%s()\n", __func__);
...@@ -790,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, ...@@ -790,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
channel->center_freq, info->privacy ? "secure" : "open"); channel->center_freq, info->privacy ? "secure" : "open");
wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", wil_dbg_misc(wil, "Privacy: %d auth_type %d\n",
info->privacy, info->auth_type); info->privacy, info->auth_type);
wil_dbg_misc(wil, "Hidden SSID mode: %d\n",
info->hidden_ssid);
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);
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
...@@ -835,10 +858,28 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, ...@@ -835,10 +858,28 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil->privacy = info->privacy; wil->privacy = info->privacy;
switch (info->hidden_ssid) {
case NL80211_HIDDEN_SSID_NOT_IN_USE:
hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
break;
case NL80211_HIDDEN_SSID_ZERO_LEN:
hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY;
break;
case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
hidden_ssid = WMI_HIDDEN_SSID_CLEAR;
break;
default:
rc = -EOPNOTSUPP;
goto out;
}
netif_carrier_on(ndev); netif_carrier_on(ndev);
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
channel->hw_value); channel->hw_value, hidden_ssid);
if (rc) if (rc)
goto err_pcp_start; goto err_pcp_start;
...@@ -1023,8 +1064,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { ...@@ -1023,8 +1064,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
static void wil_wiphy_init(struct wiphy *wiphy) static void wil_wiphy_init(struct wiphy *wiphy)
{ {
/* TODO: set real value */ wiphy->max_scan_ssids = 1;
wiphy->max_scan_ssids = 10;
wiphy->max_scan_ie_len = WMI_MAX_IE_LEN; wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
wiphy->max_num_pmkids = 0 /* TODO: */; wiphy->max_num_pmkids = 0 /* TODO: */;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
......
...@@ -1360,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) ...@@ -1360,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
{ {
struct wil6210_priv *wil = s->private; struct wil6210_priv *wil = s->private;
int i, tid; int i, tid, mcs;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i]; struct wil_sta_info *p = &wil->sta[i];
...@@ -1390,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) ...@@ -1390,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
} }
} }
spin_unlock_bh(&p->tid_rx_lock); spin_unlock_bh(&p->tid_rx_lock);
seq_puts(s, "Rx/MCS:");
for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
mcs++)
seq_printf(s, " %lld",
p->stats.rx_per_mcs[mcs]);
seq_puts(s, "\n");
} }
} }
......
...@@ -100,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO); ...@@ -100,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order"); MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO); module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO);
MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
......
...@@ -132,7 +132,7 @@ static void wil_dev_setup(struct net_device *dev) ...@@ -132,7 +132,7 @@ static void wil_dev_setup(struct net_device *dev)
dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
} }
void *wil_if_alloc(struct device *dev, void __iomem *csr) void *wil_if_alloc(struct device *dev)
{ {
struct net_device *ndev; struct net_device *ndev;
struct wireless_dev *wdev; struct wireless_dev *wdev;
...@@ -147,7 +147,6 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ...@@ -147,7 +147,6 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
} }
wil = wdev_to_wil(wdev); wil = wdev_to_wil(wdev);
wil->csr = csr;
wil->wdev = wdev; wil->wdev = wdev;
wil_dbg_misc(wil, "%s()\n", __func__); wil_dbg_misc(wil, "%s()\n", __func__);
......
...@@ -163,7 +163,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -163,7 +163,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct wil6210_priv *wil; struct wil6210_priv *wil;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
void __iomem *csr;
int rc; int rc;
/* check HW */ /* check HW */
...@@ -178,9 +177,28 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -178,9 +177,28 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENODEV; return -ENODEV;
} }
wil = wil_if_alloc(dev);
if (IS_ERR(wil)) {
rc = (int)PTR_ERR(wil);
dev_err(dev, "wil_if_alloc failed: %d\n", rc);
return rc;
}
wil->pdev = pdev;
pci_set_drvdata(pdev, wil);
/* rollback to if_free */
wil->platform_handle =
wil_platform_init(&pdev->dev, &wil->platform_ops);
if (!wil->platform_handle) {
rc = -ENODEV;
wil_err(wil, "wil_platform_init failed\n");
goto if_free;
}
/* rollback to err_plat */
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) { if (rc) {
dev_err(&pdev->dev, wil_err(wil,
"pci_enable_device failed, retry with MSI only\n"); "pci_enable_device failed, retry with MSI only\n");
/* Work around for platforms that can't allocate IRQ: /* Work around for platforms that can't allocate IRQ:
* retry with MSI only * retry with MSI only
...@@ -188,47 +206,37 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -188,47 +206,37 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->msi_enabled = 1; pdev->msi_enabled = 1;
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
} }
if (rc) if (rc) {
return -ENODEV; wil_err(wil,
"pci_enable_device failed, even with MSI only\n");
goto err_plat;
}
/* rollback to err_disable_pdev */ /* rollback to err_disable_pdev */
rc = pci_request_region(pdev, 0, WIL_NAME); rc = pci_request_region(pdev, 0, WIL_NAME);
if (rc) { if (rc) {
dev_err(&pdev->dev, "pci_request_region failed\n"); wil_err(wil, "pci_request_region failed\n");
goto err_disable_pdev; goto err_disable_pdev;
} }
/* rollback to err_release_reg */ /* rollback to err_release_reg */
csr = pci_ioremap_bar(pdev, 0); wil->csr = pci_ioremap_bar(pdev, 0);
if (!csr) { if (!wil->csr) {
dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); wil_err(wil, "pci_ioremap_bar failed\n");
rc = -ENODEV; rc = -ENODEV;
goto err_release_reg; goto err_release_reg;
} }
/* rollback to err_iounmap */ /* rollback to err_iounmap */
dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr); wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
wil = wil_if_alloc(dev, csr);
if (IS_ERR(wil)) {
rc = (int)PTR_ERR(wil);
dev_err(dev, "wil_if_alloc failed: %d\n", rc);
goto err_iounmap;
}
/* rollback to if_free */
pci_set_drvdata(pdev, wil);
wil->pdev = pdev;
wil_set_capabilities(wil); wil_set_capabilities(wil);
wil6210_clear_irq(wil); wil6210_clear_irq(wil);
wil->platform_handle =
wil_platform_init(&pdev->dev, &wil->platform_ops);
/* FW should raise IRQ when ready */ /* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil); rc = wil_if_pcie_enable(wil);
if (rc) { if (rc) {
wil_err(wil, "Enable device failed\n"); wil_err(wil, "Enable device failed\n");
goto if_free; goto err_iounmap;
} }
/* rollback to bus_disable */ /* rollback to bus_disable */
...@@ -243,18 +251,19 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -243,18 +251,19 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0; return 0;
bus_disable: bus_disable:
wil_if_pcie_disable(wil); wil_if_pcie_disable(wil);
if_free: err_iounmap:
pci_iounmap(pdev, wil->csr);
err_release_reg:
pci_release_region(pdev, 0);
err_disable_pdev:
pci_disable_device(pdev);
err_plat:
if (wil->platform_ops.uninit) if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle); wil->platform_ops.uninit(wil->platform_handle);
if_free:
wil_if_free(wil); wil_if_free(wil);
err_iounmap:
pci_iounmap(pdev, csr);
err_release_reg:
pci_release_region(pdev, 0);
err_disable_pdev:
pci_disable_device(pdev);
return rc; return rc;
} }
...@@ -269,12 +278,12 @@ static void wil_pcie_remove(struct pci_dev *pdev) ...@@ -269,12 +278,12 @@ static void wil_pcie_remove(struct pci_dev *pdev)
wil6210_debugfs_remove(wil); wil6210_debugfs_remove(wil);
wil_if_remove(wil); wil_if_remove(wil);
wil_if_pcie_disable(wil); wil_if_pcie_disable(wil);
if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
pci_iounmap(pdev, csr); pci_iounmap(pdev, csr);
pci_release_region(pdev, 0); pci_release_region(pdev, 0);
pci_disable_device(pdev); pci_disable_device(pdev);
if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
} }
static const struct pci_device_id wil6210_pcie_ids[] = { static const struct pci_device_id wil6210_pcie_ids[] = {
...@@ -291,7 +300,27 @@ static struct pci_driver wil6210_driver = { ...@@ -291,7 +300,27 @@ static struct pci_driver wil6210_driver = {
.name = WIL_NAME, .name = WIL_NAME,
}; };
module_pci_driver(wil6210_driver); static int __init wil6210_driver_init(void)
{
int rc;
rc = wil_platform_modinit();
if (rc)
return rc;
rc = pci_register_driver(&wil6210_driver);
if (rc)
wil_platform_modexit();
return rc;
}
module_init(wil6210_driver_init);
static void __exit wil6210_driver_exit(void)
{
pci_unregister_driver(&wil6210_driver);
wil_platform_modexit();
}
module_exit(wil6210_driver_exit);
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
......
...@@ -427,6 +427,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -427,6 +427,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
cid = wil_rxdesc_cid(d); cid = wil_rxdesc_cid(d);
stats = &wil->sta[cid].stats; stats = &wil->sta[cid].stats;
stats->last_mcs_rx = wil_rxdesc_mcs(d); stats->last_mcs_rx = wil_rxdesc_mcs(d);
if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
stats->rx_per_mcs[stats->last_mcs_rx]++;
/* use radiotap header only if required */ /* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
......
...@@ -281,7 +281,7 @@ struct fw_map { ...@@ -281,7 +281,7 @@ struct fw_map {
}; };
/* array size should be in sync with actual definition in the wmi.c */ /* array size should be in sync with actual definition in the wmi.c */
extern const struct fw_map fw_mapping[7]; extern const struct fw_map fw_mapping[8];
/** /**
* mk_cidxtid - construct @cidxtid field * mk_cidxtid - construct @cidxtid field
...@@ -464,6 +464,7 @@ enum wil_sta_status { ...@@ -464,6 +464,7 @@ enum wil_sta_status {
}; };
#define WIL_STA_TID_NUM (16) #define WIL_STA_TID_NUM (16)
#define WIL_MCS_MAX (12) /* Maximum MCS supported */
struct wil_net_stats { struct wil_net_stats {
unsigned long rx_packets; unsigned long rx_packets;
...@@ -473,6 +474,7 @@ struct wil_net_stats { ...@@ -473,6 +474,7 @@ struct wil_net_stats {
unsigned long tx_errors; unsigned long tx_errors;
unsigned long rx_dropped; unsigned long rx_dropped;
u16 last_mcs_rx; u16 last_mcs_rx;
u64 rx_per_mcs[WIL_MCS_MAX + 1];
}; };
/** /**
...@@ -684,7 +686,7 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, ...@@ -684,7 +686,7 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count); size_t count);
void *wil_if_alloc(struct device *dev, void __iomem *csr); void *wil_if_alloc(struct device *dev);
void wil_if_free(struct wil6210_priv *wil); void wil_if_free(struct wil6210_priv *wil);
int wil_if_add(struct wil6210_priv *wil); int wil_if_add(struct wil6210_priv *wil);
void wil_if_remove(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil);
...@@ -762,7 +764,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev); ...@@ -762,7 +764,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev);
void wil_wdev_free(struct wil6210_priv *wil); void wil_wdev_free(struct wil6210_priv *wil);
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
u8 chan, u8 hidden_ssid);
int wmi_pcp_stop(struct wil6210_priv *wil); int wmi_pcp_stop(struct wil6210_priv *wil);
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);
......
...@@ -17,6 +17,15 @@ ...@@ -17,6 +17,15 @@
#include "linux/device.h" #include "linux/device.h"
#include "wil_platform.h" #include "wil_platform.h"
int __init wil_platform_modinit(void)
{
return 0;
}
void wil_platform_modexit(void)
{
}
/** /**
* wil_platform_init() - wil6210 platform module init * wil_platform_init() - wil6210 platform module init
* *
...@@ -26,10 +35,11 @@ ...@@ -26,10 +35,11 @@
*/ */
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
{ {
void *handle = NULL; void *handle = ops; /* to return some non-NULL for 'void' impl. */
if (!ops) { if (!ops) {
dev_err(dev, "Invalid parameter. Cannot init platform module\n"); dev_err(dev,
"Invalid parameter. Cannot init platform module\n");
return NULL; return NULL;
} }
......
...@@ -31,4 +31,7 @@ struct wil_platform_ops { ...@@ -31,4 +31,7 @@ struct wil_platform_ops {
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops); void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
int __init wil_platform_modinit(void);
void wil_platform_modexit(void);
#endif /* __WIL_PLATFORM_H__ */ #endif /* __WIL_PLATFORM_H__ */
...@@ -85,6 +85,7 @@ const struct fw_map fw_mapping[] = { ...@@ -85,6 +85,7 @@ const struct fw_map fw_mapping[] = {
{0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */ {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */
{0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */ {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */
{0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */ {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */
{0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf 512b */
{0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */ {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */
/* /*
* 920000..930000 ucode code RAM * 920000..930000 ucode code RAM
...@@ -824,7 +825,8 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) ...@@ -824,7 +825,8 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
} }
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
u8 chan, u8 hidden_ssid)
{ {
int rc; int rc;
...@@ -834,6 +836,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) ...@@ -834,6 +836,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.disable_sec_offload = 1, .disable_sec_offload = 1,
.channel = chan - 1, .channel = chan - 1,
.pcp_max_assoc_sta = max_assoc_sta, .pcp_max_assoc_sta = max_assoc_sta,
.hidden_ssid = hidden_ssid,
}; };
struct { struct {
struct wil6210_mbox_hdr_wmi wmi; struct wil6210_mbox_hdr_wmi wmi;
......
...@@ -495,10 +495,18 @@ struct wmi_power_mgmt_cfg_cmd { ...@@ -495,10 +495,18 @@ struct wmi_power_mgmt_cfg_cmd {
/* /*
* WMI_PCP_START_CMDID * WMI_PCP_START_CMDID
*/ */
enum wmi_hidden_ssid {
WMI_HIDDEN_SSID_DISABLED = 0,
WMI_HIDDEN_SSID_SEND_EMPTY = 1,
WMI_HIDDEN_SSID_CLEAR = 2,
};
struct wmi_pcp_start_cmd { struct wmi_pcp_start_cmd {
__le16 bcon_interval; __le16 bcon_interval;
u8 pcp_max_assoc_sta; u8 pcp_max_assoc_sta;
u8 reserved0[9]; u8 hidden_ssid;
u8 reserved0[8];
u8 network_type; u8 network_type;
u8 channel; u8 channel;
u8 disable_sec_offload; u8 disable_sec_offload;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment