wireless-drivers patches for 4.7
Major changes: iwlwifi * remove IWLWIFI_DEBUG_EXPERIMENTAL_UCODE kconfig option * work for RX multiqueue continues * dynamic queue allocation work continues * add Luca as maintainer * a bunch of fixes and improvements all over brcmfmac * add 4356 sdio support ath6kl * add ability to set debug uart baud rate with a module parameter wil6210 * add debugfs file to configure firmware led functionality -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJXNbEBAAoJEG4XJFUm622bKfAH/2CnQV7dBCT5QwEiKYoOdsCR eTiH7OYjTPw/rjKaG3laFgFbecnfUnHoGt55WKqRY58JycLza+SPTTv57hFTnOl+ 4kDhUEjUggxMs5BRb3H7wtcnQVs/pTkgqKqwUrmFNkG6idENQgorK6DG4SNCwIdf JrmxiHcN73xSATxlduoA9bGpluW3OvnFfRrJfyT6UBWZaFqFe3qsoKDx08S2WU2z kUI9ZUO9Ht7Q85QdLfPQI7xo54dXo9a+8v3yc7fNFbcu1s8cqeYuofXfypjK7H/B DEY96mubDnmDt8YE8yR9wStVzTr5zf39urE3o+/xSKSKhQxmNo8+x2TBSm5nFSQ= =0HKi -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-next-for-davem-2016-05-13' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next Kalle Valo says: ==================== wireless-drivers patches for 4.7 Major changes: iwlwifi * remove IWLWIFI_DEBUG_EXPERIMENTAL_UCODE kconfig option * work for RX multiqueue continues * dynamic queue allocation work continues * add Luca as maintainer * a bunch of fixes and improvements all over brcmfmac * add 4356 sdio support ath6kl * add ability to set debug uart baud rate with a module parameter wil6210 * add debugfs file to configure firmware led functionality ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
56025caa82
|
@ -5895,6 +5895,7 @@ F: drivers/net/wireless/intel/iwlegacy/
|
|||
INTEL WIRELESS WIFI LINK (iwlwifi)
|
||||
M: Johannes Berg <johannes.berg@intel.com>
|
||||
M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||||
M: Luca Coelho <luciano.coelho@intel.com>
|
||||
M: Intel Linux Wireless <linuxwifi@intel.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://intellinuxwireless.org
|
||||
|
|
|
@ -202,6 +202,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.name = "qca4019 hw1.0",
|
||||
.patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,
|
||||
.uart_pin = 7,
|
||||
.has_shifted_cc_wraparound = true,
|
||||
.otp_exe_param = 0x0010000,
|
||||
.continuous_frag_desc = true,
|
||||
.channel_counters_freq_hz = 125000,
|
||||
|
@ -686,6 +687,9 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
|||
if (!IS_ERR(ar->cal_file))
|
||||
release_firmware(ar->cal_file);
|
||||
|
||||
if (!IS_ERR(ar->pre_cal_file))
|
||||
release_firmware(ar->pre_cal_file);
|
||||
|
||||
ath10k_swap_code_seg_release(ar);
|
||||
|
||||
ar->normal_mode_fw.fw_file.otp_data = NULL;
|
||||
|
@ -696,6 +700,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
|||
ar->normal_mode_fw.fw_file.firmware_len = 0;
|
||||
|
||||
ar->cal_file = NULL;
|
||||
ar->pre_cal_file = NULL;
|
||||
}
|
||||
|
||||
static int ath10k_fetch_cal_file(struct ath10k *ar)
|
||||
|
@ -1392,6 +1397,7 @@ static void ath10k_core_restart(struct work_struct *work)
|
|||
complete_all(&ar->install_key_done);
|
||||
complete_all(&ar->vdev_setup_done);
|
||||
complete_all(&ar->thermal.wmi_sync);
|
||||
complete_all(&ar->bss_survey_done);
|
||||
wake_up(&ar->htt.empty_tx_wq);
|
||||
wake_up(&ar->wmi.tx_credits_wq);
|
||||
wake_up(&ar->peer_mapping_wq);
|
||||
|
@ -1724,6 +1730,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
|||
if (ath10k_peer_stats_enabled(ar))
|
||||
val = WMI_10_4_PEER_STATS;
|
||||
|
||||
if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
|
||||
val |= WMI_10_4_BSS_CHANNEL_INFO_64;
|
||||
|
||||
status = ath10k_mac_ext_resource_config(ar, val);
|
||||
if (status) {
|
||||
ath10k_err(ar,
|
||||
|
@ -1758,6 +1767,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
|||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
|
||||
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
|
||||
/* we don't care about HTT in UTF mode */
|
||||
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
|
||||
status = ath10k_htt_setup(&ar->htt);
|
||||
|
@ -1771,10 +1784,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
|||
if (status)
|
||||
goto err_hif_stop;
|
||||
|
||||
ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
|
||||
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
|
||||
return 0;
|
||||
|
||||
err_hif_stop:
|
||||
|
@ -2085,6 +2094,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
|||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
init_completion(&ar->thermal.wmi_sync);
|
||||
init_completion(&ar->bss_survey_done);
|
||||
|
||||
INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
|
||||
|
||||
|
|
|
@ -876,6 +876,7 @@ struct ath10k {
|
|||
* avoid reporting garbage data.
|
||||
*/
|
||||
bool ch_info_can_report_survey;
|
||||
struct completion bss_survey_done;
|
||||
|
||||
struct dfs_pattern_detector *dfs_detector;
|
||||
|
||||
|
@ -883,8 +884,6 @@ struct ath10k {
|
|||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
struct ath10k_debug debug;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
/* relay(fs) channel for spectral scan */
|
||||
struct rchan *rfs_chan_spec_scan;
|
||||
|
@ -893,6 +892,7 @@ struct ath10k {
|
|||
enum ath10k_spectral_mode mode;
|
||||
struct ath10k_spec_scan config;
|
||||
} spectral;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
/* protected by conf_mutex */
|
||||
|
|
|
@ -4278,9 +4278,6 @@ static void ath10k_mac_setup_ht_vht_cap(struct ath10k *ar)
|
|||
if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) {
|
||||
band = &ar->mac.sbands[NL80211_BAND_2GHZ];
|
||||
band->ht_cap = ht_cap;
|
||||
|
||||
/* Enable the VHT support at 2.4 GHz */
|
||||
band->vht_cap = vht_cap;
|
||||
}
|
||||
if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
|
||||
band = &ar->mac.sbands[NL80211_BAND_5GHZ];
|
||||
|
@ -4346,7 +4343,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
|||
|
||||
/*
|
||||
* This makes sense only when restarting hw. It is harmless to call
|
||||
* uncoditionally. This is necessary to make sure no HTT/WMI tx
|
||||
* unconditionally. This is necessary to make sure no HTT/WMI tx
|
||||
* commands will be submitted while restarting.
|
||||
*/
|
||||
ath10k_drain_tx(ar);
|
||||
|
@ -6407,6 +6404,39 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
|
|||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_mac_update_bss_chan_survey(struct ath10k *ar,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
int ret;
|
||||
enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (!test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map) ||
|
||||
(ar->rx_channel != channel))
|
||||
return;
|
||||
|
||||
if (ar->scan.state != ATH10K_SCAN_IDLE) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "ignoring bss chan info request while scanning..\n");
|
||||
return;
|
||||
}
|
||||
|
||||
reinit_completion(&ar->bss_survey_done);
|
||||
|
||||
ret = ath10k_wmi_pdev_bss_chan_info_request(ar, type);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to send pdev bss chan info request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->bss_survey_done, 3 * HZ);
|
||||
if (!ret) {
|
||||
ath10k_warn(ar, "bss channel survey timed out\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
|
@ -6431,6 +6461,8 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_mac_update_bss_chan_survey(ar, survey->channel);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
memcpy(survey, ar_survey, sizeof(*survey));
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
|
|
@ -191,6 +191,9 @@ struct wmi_ops {
|
|||
u32 fw_feature_bitmap);
|
||||
int (*get_vdev_subtype)(struct ath10k *ar,
|
||||
enum wmi_vdev_subtype subtype);
|
||||
struct sk_buff *(*gen_pdev_bss_chan_info_req)
|
||||
(struct ath10k *ar,
|
||||
enum wmi_bss_survey_req_type type);
|
||||
};
|
||||
|
||||
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
|
||||
|
@ -1361,4 +1364,22 @@ ath10k_wmi_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype)
|
|||
return ar->wmi.ops->get_vdev_subtype(ar, subtype);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_pdev_bss_chan_info_request(struct ath10k *ar,
|
||||
enum wmi_bss_survey_req_type type)
|
||||
{
|
||||
struct ath10k_wmi *wmi = &ar->wmi;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!wmi->ops->gen_pdev_bss_chan_info_req)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
skb = wmi->ops->gen_pdev_bss_chan_info_req(ar, type);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb,
|
||||
wmi->cmd->pdev_bss_chan_info_request_cmdid);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -521,7 +521,8 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
|
|||
.vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_bss_chan_info_request_cmdid =
|
||||
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
|
||||
};
|
||||
|
||||
/* 10.4 WMI cmd track */
|
||||
|
@ -1633,6 +1634,7 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
|
|||
ch->max_power = arg->max_power;
|
||||
ch->reg_power = arg->max_reg_power;
|
||||
ch->antenna_max = arg->max_antenna_gain;
|
||||
ch->max_tx_power = arg->max_power;
|
||||
|
||||
/* mode & flags share storage */
|
||||
ch->mode = arg->mode;
|
||||
|
@ -4792,6 +4794,58 @@ static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_event_pdev_bss_chan_info(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct wmi_pdev_bss_chan_info_event *ev;
|
||||
struct survey_info *survey;
|
||||
u64 busy, total, tx, rx, rx_bss;
|
||||
u32 freq, noise_floor;
|
||||
u32 cc_freq_hz = ar->hw_params.channel_counters_freq_hz;
|
||||
int idx;
|
||||
|
||||
ev = (struct wmi_pdev_bss_chan_info_event *)skb->data;
|
||||
if (WARN_ON(skb->len < sizeof(*ev)))
|
||||
return -EPROTO;
|
||||
|
||||
freq = __le32_to_cpu(ev->freq);
|
||||
noise_floor = __le32_to_cpu(ev->noise_floor);
|
||||
busy = __le64_to_cpu(ev->cycle_busy);
|
||||
total = __le64_to_cpu(ev->cycle_total);
|
||||
tx = __le64_to_cpu(ev->cycle_tx);
|
||||
rx = __le64_to_cpu(ev->cycle_rx);
|
||||
rx_bss = __le64_to_cpu(ev->cycle_rx_bss);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi event pdev bss chan info:\n freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n",
|
||||
freq, noise_floor, busy, total, tx, rx, rx_bss);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
idx = freq_to_idx(ar, freq);
|
||||
if (idx >= ARRAY_SIZE(ar->survey)) {
|
||||
ath10k_warn(ar, "bss chan info: invalid frequency %d (idx %d out of bounds)\n",
|
||||
freq, idx);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
survey = &ar->survey[idx];
|
||||
|
||||
survey->noise = noise_floor;
|
||||
survey->time = div_u64(total, cc_freq_hz);
|
||||
survey->time_busy = div_u64(busy, cc_freq_hz);
|
||||
survey->time_rx = div_u64(rx_bss, cc_freq_hz);
|
||||
survey->time_tx = div_u64(tx, cc_freq_hz);
|
||||
survey->filled |= (SURVEY_INFO_NOISE_DBM |
|
||||
SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_TX);
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
complete(&ar->bss_survey_done);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct wmi_cmd_hdr *cmd_hdr;
|
||||
|
@ -5135,6 +5189,9 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
case WMI_10_2_PDEV_TEMPERATURE_EVENTID:
|
||||
ath10k_wmi_event_temperature(ar, skb);
|
||||
break;
|
||||
case WMI_10_2_PDEV_BSS_CHAN_INFO_EVENTID:
|
||||
ath10k_wmi_event_pdev_bss_chan_info(ar, skb);
|
||||
break;
|
||||
case WMI_10_2_RTT_KEEPALIVE_EVENTID:
|
||||
case WMI_10_2_GPIO_INPUT_EVENTID:
|
||||
case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
|
||||
|
@ -5212,6 +5269,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
ath10k_wmi_event_vdev_stopped(ar, skb);
|
||||
break;
|
||||
case WMI_10_4_WOW_WAKEUP_HOST_EVENTID:
|
||||
case WMI_10_4_PEER_RATECODE_LIST_EVENTID:
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"received event id %d not implemented\n", id);
|
||||
break;
|
||||
|
@ -5221,6 +5279,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
case WMI_10_4_PDEV_TEMPERATURE_EVENTID:
|
||||
ath10k_wmi_event_temperature(ar, skb);
|
||||
break;
|
||||
case WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID:
|
||||
ath10k_wmi_event_pdev_bss_chan_info(ar, skb);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "Unknown eventid: %d\n", id);
|
||||
break;
|
||||
|
@ -5606,6 +5667,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
|
|||
if (ath10k_peer_stats_enabled(ar))
|
||||
features |= WMI_10_2_PEER_STATS;
|
||||
|
||||
if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
|
||||
features |= WMI_10_2_BSS_CHAN_INFO;
|
||||
|
||||
cmd->resource_config.feature_mask = __cpu_to_le32(features);
|
||||
|
||||
memcpy(&cmd->resource_config.common, &config, sizeof(config));
|
||||
|
@ -6636,6 +6700,26 @@ ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar)
|
|||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_10_2_op_gen_pdev_bss_chan_info(struct ath10k *ar,
|
||||
enum wmi_bss_survey_req_type type)
|
||||
{
|
||||
struct wmi_pdev_chan_info_req_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cmd = (struct wmi_pdev_chan_info_req_cmd *)skb->data;
|
||||
cmd->type = __cpu_to_le32(type);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi pdev bss info request type %d\n", type);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
/* This function assumes the beacon is already DMA mapped */
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn,
|
||||
|
@ -7735,6 +7819,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
|
|||
.gen_init = ath10k_wmi_10_2_op_gen_init,
|
||||
.gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
|
||||
.gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
|
||||
.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
|
||||
|
||||
/* shared with 10.1 */
|
||||
.map_svc = wmi_10x_svc_map,
|
||||
|
@ -7861,6 +7946,7 @@ static const struct wmi_ops wmi_10_4_ops = {
|
|||
.gen_request_stats = ath10k_wmi_op_gen_request_stats,
|
||||
.gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
|
||||
.get_vdev_subtype = ath10k_wmi_10_4_op_get_vdev_subtype,
|
||||
.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
|
||||
};
|
||||
|
||||
int ath10k_wmi_attach(struct ath10k *ar)
|
||||
|
|
|
@ -1444,6 +1444,7 @@ enum wmi_10_2_cmd_id {
|
|||
WMI_10_2_MU_CAL_START_CMDID,
|
||||
WMI_10_2_SET_LTEU_CONFIG_CMDID,
|
||||
WMI_10_2_SET_CCA_PARAMS,
|
||||
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
|
||||
WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
|
||||
};
|
||||
|
||||
|
@ -1487,6 +1488,8 @@ enum wmi_10_2_event_id {
|
|||
WMI_10_2_WDS_PEER_EVENTID,
|
||||
WMI_10_2_PEER_STA_PS_STATECHG_EVENTID,
|
||||
WMI_10_2_PDEV_TEMPERATURE_EVENTID,
|
||||
WMI_10_2_MU_REPORT_EVENTID,
|
||||
WMI_10_2_PDEV_BSS_CHAN_INFO_EVENTID,
|
||||
WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
|
||||
};
|
||||
|
||||
|
@ -1795,6 +1798,7 @@ struct wmi_channel {
|
|||
__le32 reginfo1;
|
||||
struct {
|
||||
u8 antenna_max;
|
||||
u8 max_tx_power;
|
||||
} __packed;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
@ -2450,6 +2454,7 @@ enum wmi_10_2_feature_mask {
|
|||
WMI_10_2_RX_BATCH_MODE = BIT(0),
|
||||
WMI_10_2_ATF_CONFIG = BIT(1),
|
||||
WMI_10_2_COEX_GPIO = BIT(3),
|
||||
WMI_10_2_BSS_CHAN_INFO = BIT(6),
|
||||
WMI_10_2_PEER_STATS = BIT(7),
|
||||
};
|
||||
|
||||
|
@ -6280,6 +6285,17 @@ struct wmi_pdev_temperature_event {
|
|||
__le32 temperature;
|
||||
} __packed;
|
||||
|
||||
struct wmi_pdev_bss_chan_info_event {
|
||||
__le32 freq;
|
||||
__le32 noise_floor;
|
||||
__le64 cycle_busy;
|
||||
__le64 cycle_total;
|
||||
__le64 cycle_tx;
|
||||
__le64 cycle_rx;
|
||||
__le64 cycle_rx_bss;
|
||||
__le32 reserved;
|
||||
} __packed;
|
||||
|
||||
/* WOW structures */
|
||||
enum wmi_wow_wakeup_event {
|
||||
WOW_BMISS_EVENT = 0,
|
||||
|
@ -6483,6 +6499,16 @@ enum wmi_host_platform_type {
|
|||
WMI_HOST_PLATFORM_LOW_PERF,
|
||||
};
|
||||
|
||||
enum wmi_bss_survey_req_type {
|
||||
WMI_BSS_SURVEY_REQ_TYPE_READ = 1,
|
||||
WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR,
|
||||
};
|
||||
|
||||
struct wmi_pdev_chan_info_req_cmd {
|
||||
__le32 type;
|
||||
__le32 reserved;
|
||||
} __packed;
|
||||
|
||||
struct ath10k;
|
||||
struct ath10k_vif;
|
||||
struct ath10k_fw_stats_pdev;
|
||||
|
|
|
@ -31,6 +31,7 @@ unsigned int debug_mask;
|
|||
static unsigned int suspend_mode;
|
||||
static unsigned int wow_mode;
|
||||
static unsigned int uart_debug;
|
||||
static unsigned int uart_rate = 115200;
|
||||
static unsigned int ath6kl_p2p;
|
||||
static unsigned int testmode;
|
||||
static unsigned int recovery_enable;
|
||||
|
@ -40,6 +41,7 @@ module_param(debug_mask, uint, 0644);
|
|||
module_param(suspend_mode, uint, 0644);
|
||||
module_param(wow_mode, uint, 0644);
|
||||
module_param(uart_debug, uint, 0644);
|
||||
module_param(uart_rate, uint, 0644);
|
||||
module_param(ath6kl_p2p, uint, 0644);
|
||||
module_param(testmode, uint, 0644);
|
||||
module_param(recovery_enable, uint, 0644);
|
||||
|
@ -180,6 +182,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
|
|||
|
||||
if (uart_debug)
|
||||
ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
|
||||
ar->hw.uarttx_rate = uart_rate;
|
||||
|
||||
set_bit(FIRST_BOOT, &ar->flag);
|
||||
|
||||
|
|
|
@ -781,6 +781,7 @@ struct ath6kl {
|
|||
u32 board_addr;
|
||||
u32 refclk_hz;
|
||||
u32 uarttx_pin;
|
||||
u32 uarttx_rate;
|
||||
u32 testscript_addr;
|
||||
u8 tx_ant;
|
||||
u8 rx_ant;
|
||||
|
|
|
@ -173,6 +173,7 @@ static const struct ath6kl_hw hw_list[] = {
|
|||
.reserved_ram_size = 7168,
|
||||
.board_addr = 0x436400,
|
||||
.testscript_addr = 0,
|
||||
.uarttx_pin = 11,
|
||||
.flags = 0,
|
||||
|
||||
.fw = {
|
||||
|
@ -650,6 +651,14 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
/* Only set the baud rate if we're actually doing debug */
|
||||
if (ar->conf_flags & ATH6KL_CONF_UART_DEBUG) {
|
||||
status = ath6kl_bmi_write_hi32(ar, hi_desired_baud_rate,
|
||||
ar->hw.uarttx_rate);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Configure target refclk_hz */
|
||||
if (ar->hw.refclk_hz != 0) {
|
||||
status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz,
|
||||
|
|
|
@ -75,6 +75,26 @@ config ATH9K_STATION_STATISTICS
|
|||
---help---
|
||||
This option enables detailed statistics for association stations.
|
||||
|
||||
config ATH9K_TX99
|
||||
bool "Atheros ath9k TX99 testing support"
|
||||
depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
|
||||
default n
|
||||
---help---
|
||||
Say N. This should only be enabled on systems undergoing
|
||||
certification testing and evaluation in a controlled environment.
|
||||
Enabling this will only enable TX99 support, all other modes of
|
||||
operation will be disabled.
|
||||
|
||||
TX99 support enables Specific Absorption Rate (SAR) testing.
|
||||
SAR is the unit of measurement for the amount of radio frequency(RF)
|
||||
absorbed by the body when using a wireless device. The RF exposure
|
||||
limits used are expressed in the terms of SAR, which is a measure
|
||||
of the electric and magnetic field strength and power density for
|
||||
transmitters operating at frequencies from 300 kHz to 100 GHz.
|
||||
Regulatory bodies around the world require that wireless device
|
||||
be evaluated to meet the RF exposure limits set forth in the
|
||||
governmental SAR regulations.
|
||||
|
||||
config ATH9K_DFS_CERTIFIED
|
||||
bool "Atheros DFS support for certified platforms"
|
||||
depends on ATH9K && CFG80211_CERTIFICATION_ONUS
|
||||
|
@ -103,26 +123,6 @@ config ATH9K_DYNACK
|
|||
based on ACK frame RX timestamp, TX frame timestamp and frame
|
||||
duration
|
||||
|
||||
config ATH9K_TX99
|
||||
bool "Atheros ath9k TX99 testing support"
|
||||
depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
|
||||
default n
|
||||
---help---
|
||||
Say N. This should only be enabled on systems undergoing
|
||||
certification testing and evaluation in a controlled environment.
|
||||
Enabling this will only enable TX99 support, all other modes of
|
||||
operation will be disabled.
|
||||
|
||||
TX99 support enables Specific Absorption Rate (SAR) testing.
|
||||
SAR is the unit of measurement for the amount of radio frequency(RF)
|
||||
absorbed by the body when using a wireless device. The RF exposure
|
||||
limits used are expressed in the terms of SAR, which is a measure
|
||||
of the electric and magnetic field strength and power density for
|
||||
transmitters operating at frequencies from 300 kHz to 100 GHz.
|
||||
Regulatory bodies around the world require that wireless device
|
||||
be evaluated to meet the RF exposure limits set forth in the
|
||||
governmental SAR regulations.
|
||||
|
||||
config ATH9K_WOW
|
||||
bool "Wake on Wireless LAN support (EXPERIMENTAL)"
|
||||
depends on ATH9K && PM
|
||||
|
|
|
@ -4402,7 +4402,7 @@ static void ar9003_hw_selfgen_tpc_txpower(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
/* Set tx power registers to array of values passed in */
|
||||
static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
||||
int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
||||
{
|
||||
#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
|
||||
/* make sure forced gain is not set */
|
||||
|
|
|
@ -355,5 +355,6 @@ unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
|
|||
struct ath9k_channel *chan);
|
||||
|
||||
void ar9003_hw_internal_regulator_apply(struct ath_hw *ah);
|
||||
int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/export.h>
|
||||
#include "hw.h"
|
||||
#include "ar9003_phy.h"
|
||||
#include "ar9003_eeprom.h"
|
||||
|
||||
#define AR9300_OFDM_RATES 8
|
||||
#define AR9300_HT_SS_RATES 8
|
||||
|
@ -1009,7 +1010,7 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
|
|||
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
|
||||
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
|
||||
|
||||
if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
|
||||
if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
|
||||
REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
|
||||
AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 3);
|
||||
|
||||
|
@ -1840,73 +1841,14 @@ static void ar9003_hw_tx99_stop(struct ath_hw *ah)
|
|||
|
||||
static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower)
|
||||
{
|
||||
static s16 p_pwr_array[ar9300RateSize] = { 0 };
|
||||
static u8 p_pwr_array[ar9300RateSize] = { 0 };
|
||||
unsigned int i;
|
||||
|
||||
if (txpower <= MAX_RATE_POWER) {
|
||||
for (i = 0; i < ar9300RateSize; i++)
|
||||
p_pwr_array[i] = txpower;
|
||||
} else {
|
||||
for (i = 0; i < ar9300RateSize; i++)
|
||||
p_pwr_array[i] = MAX_RATE_POWER;
|
||||
}
|
||||
txpower = txpower <= MAX_RATE_POWER ? txpower : MAX_RATE_POWER;
|
||||
for (i = 0; i < ar9300RateSize; i++)
|
||||
p_pwr_array[i] = txpower;
|
||||
|
||||
REG_WRITE(ah, 0xa458, 0);
|
||||
|
||||
REG_WRITE(ah, 0xa3c0,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0));
|
||||
REG_WRITE(ah, 0xa3c4,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0));
|
||||
REG_WRITE(ah, 0xa3c8,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0));
|
||||
REG_WRITE(ah, 0xa3cc,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 0));
|
||||
REG_WRITE(ah, 0xa3d0,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_5], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_4], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19], 8)|
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16], 0));
|
||||
REG_WRITE(ah, 0xa3d4,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_12], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_7], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_6], 0));
|
||||
REG_WRITE(ah, 0xa3e4,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_20], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_15], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_14], 0));
|
||||
REG_WRITE(ah, 0xa3e8,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_22], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_23], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_22], 0));
|
||||
REG_WRITE(ah, 0xa3d8,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_4], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16], 0));
|
||||
REG_WRITE(ah, 0xa3dc,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_12], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_7], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_6], 0));
|
||||
REG_WRITE(ah, 0xa3ec,
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_20], 16) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_15], 8) |
|
||||
ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0));
|
||||
ar9003_hw_tx_power_regwrite(ah, p_pwr_array);
|
||||
}
|
||||
|
||||
static void ar9003_hw_init_txpower_cck(struct ath_hw *ah, u8 *rate_array)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#define WCN36XX_HAL_BUF_SIZE 4096
|
||||
|
||||
#define HAL_MSG_TIMEOUT 500
|
||||
#define HAL_MSG_TIMEOUT 10000
|
||||
#define WCN36XX_SMSM_WLAN_TX_ENABLE 0x00000400
|
||||
#define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
|
||||
/* The PNO version info be contained in the rsp msg */
|
||||
|
|
|
@ -375,8 +375,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* scan on P2P_DEVICE is handled as p2p search */
|
||||
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
/* social scan on P2P_DEVICE is handled as p2p search */
|
||||
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
|
||||
wil_p2p_is_social_scan(request)) {
|
||||
wil->scan_request = request;
|
||||
wil->radio_wdev = wdev;
|
||||
rc = wil_p2p_search(wil, request);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "wil6210.h"
|
||||
#include "trace.h"
|
||||
|
||||
void wil_err(struct wil6210_priv *wil, const char *fmt, ...)
|
||||
void __wil_err(struct wil6210_priv *wil, const char *fmt, ...)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct va_format vaf = {
|
||||
|
@ -32,7 +32,7 @@ void wil_err(struct wil6210_priv *wil, const char *fmt, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
|
||||
void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
|
||||
{
|
||||
if (net_ratelimit()) {
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
@ -49,7 +49,23 @@ void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
|
|||
}
|
||||
}
|
||||
|
||||
void wil_info(struct wil6210_priv *wil, const char *fmt, ...)
|
||||
void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (!net_ratelimit())
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
netdev_dbg(wil_to_ndev(wil), "%pV", &vaf);
|
||||
trace_wil6210_log_dbg(&vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void __wil_info(struct wil6210_priv *wil, const char *fmt, ...)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct va_format vaf = {
|
||||
|
|
|
@ -171,6 +171,8 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
|
|||
int rsize;
|
||||
uint i;
|
||||
|
||||
wil_halp_vote(wil);
|
||||
|
||||
wil_memcpy_fromio_32(&r, off, sizeof(r));
|
||||
wil_mbox_ring_le2cpus(&r);
|
||||
/*
|
||||
|
@ -236,6 +238,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
|
|||
}
|
||||
out:
|
||||
seq_puts(s, "}\n");
|
||||
wil_halp_unvote(wil);
|
||||
}
|
||||
|
||||
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
|
||||
|
@ -500,9 +503,9 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
enum { max_count = 4096 };
|
||||
struct debugfs_blob_wrapper *blob = file->private_data;
|
||||
struct wil_blob_wrapper *wil_blob = file->private_data;
|
||||
loff_t pos = *ppos;
|
||||
size_t available = blob->size;
|
||||
size_t available = wil_blob->blob.size;
|
||||
void *buf;
|
||||
size_t ret;
|
||||
|
||||
|
@ -521,8 +524,9 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
|
||||
pos, count);
|
||||
wil_memcpy_fromio_halp_vote(wil_blob->wil, buf,
|
||||
(const volatile void __iomem *)
|
||||
wil_blob->blob.data + pos, count);
|
||||
|
||||
ret = copy_to_user(user_buf, buf, count);
|
||||
kfree(buf);
|
||||
|
@ -545,9 +549,9 @@ static
|
|||
struct dentry *wil_debugfs_create_ioblob(const char *name,
|
||||
umode_t mode,
|
||||
struct dentry *parent,
|
||||
struct debugfs_blob_wrapper *blob)
|
||||
struct wil_blob_wrapper *wil_blob)
|
||||
{
|
||||
return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
|
||||
return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
|
||||
}
|
||||
|
||||
/*---reset---*/
|
||||
|
@ -1437,6 +1441,118 @@ static const struct file_operations fops_sta = {
|
|||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[80];
|
||||
int n;
|
||||
|
||||
n = snprintf(buf, sizeof(buf),
|
||||
"led_id is set to %d, echo 1 to enable, 0 to disable\n",
|
||||
led_id);
|
||||
|
||||
n = min_t(int, n, sizeof(buf));
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
buf, n);
|
||||
}
|
||||
|
||||
static ssize_t wil_write_file_led_cfg(struct file *file,
|
||||
const char __user *buf_,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
int val;
|
||||
int rc;
|
||||
|
||||
rc = kstrtoint_from_user(buf_, count, 0, &val);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid argument\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
|
||||
rc = wmi_led_cfg(wil, val);
|
||||
if (rc) {
|
||||
wil_info(wil, "%s led %d failed\n",
|
||||
val ? "Enabling" : "Disabling", led_id);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_led_cfg = {
|
||||
.read = wil_read_file_led_cfg,
|
||||
.write = wil_write_file_led_cfg,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
/* led_blink_time, write:
|
||||
* "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
|
||||
*/
|
||||
static ssize_t wil_write_led_blink_time(struct file *file,
|
||||
const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
int rc;
|
||||
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
|
||||
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
|
||||
if (rc != len) {
|
||||
kfree(kbuf);
|
||||
return rc >= 0 ? -EIO : rc;
|
||||
}
|
||||
|
||||
kbuf[len] = '\0';
|
||||
rc = sscanf(kbuf, "%d %d %d %d %d %d",
|
||||
&led_blink_time[WIL_LED_TIME_SLOW].on_ms,
|
||||
&led_blink_time[WIL_LED_TIME_SLOW].off_ms,
|
||||
&led_blink_time[WIL_LED_TIME_MED].on_ms,
|
||||
&led_blink_time[WIL_LED_TIME_MED].off_ms,
|
||||
&led_blink_time[WIL_LED_TIME_FAST].on_ms,
|
||||
&led_blink_time[WIL_LED_TIME_FAST].off_ms);
|
||||
kfree(kbuf);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc < 6)
|
||||
return -EINVAL;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
static char text[400];
|
||||
|
||||
snprintf(text, sizeof(text),
|
||||
"To set led blink on/off time variables write:\n"
|
||||
"<blink_on_slow> <blink_off_slow> <blink_on_med> "
|
||||
"<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
|
||||
"The current values are:\n"
|
||||
"%d %d %d %d %d %d\n",
|
||||
led_blink_time[WIL_LED_TIME_SLOW].on_ms,
|
||||
led_blink_time[WIL_LED_TIME_SLOW].off_ms,
|
||||
led_blink_time[WIL_LED_TIME_MED].on_ms,
|
||||
led_blink_time[WIL_LED_TIME_MED].off_ms,
|
||||
led_blink_time[WIL_LED_TIME_FAST].on_ms,
|
||||
led_blink_time[WIL_LED_TIME_FAST].off_ms);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, text,
|
||||
sizeof(text));
|
||||
}
|
||||
|
||||
static const struct file_operations fops_led_blink_time = {
|
||||
.read = wil_read_led_blink_time,
|
||||
.write = wil_write_led_blink_time,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
/*----------------*/
|
||||
static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
|
||||
struct dentry *dbg)
|
||||
|
@ -1445,16 +1561,18 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
|
|||
char name[32];
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
|
||||
struct debugfs_blob_wrapper *blob = &wil->blobs[i];
|
||||
struct wil_blob_wrapper *wil_blob = &wil->blobs[i];
|
||||
struct debugfs_blob_wrapper *blob = &wil_blob->blob;
|
||||
const struct fw_map *map = &fw_mapping[i];
|
||||
|
||||
if (!map->name)
|
||||
continue;
|
||||
|
||||
wil_blob->wil = wil;
|
||||
blob->data = (void * __force)wil->csr + HOSTADDR(map->host);
|
||||
blob->size = map->to - map->from;
|
||||
snprintf(name, sizeof(name), "blob_%s", map->name);
|
||||
wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob);
|
||||
wil_debugfs_create_ioblob(name, S_IRUGO, dbg, wil_blob);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1483,6 +1601,8 @@ static const struct {
|
|||
{"link", S_IRUGO, &fops_link},
|
||||
{"info", S_IRUGO, &fops_info},
|
||||
{"recovery", S_IRUGO | S_IWUSR, &fops_recovery},
|
||||
{"led_cfg", S_IRUGO | S_IWUSR, &fops_led_cfg},
|
||||
{"led_blink_time", S_IRUGO | S_IWUSR, &fops_led_blink_time},
|
||||
};
|
||||
|
||||
static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
|
||||
|
@ -1545,6 +1665,7 @@ static const struct dbg_off dbg_statics[] = {
|
|||
{"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
|
||||
{"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh,
|
||||
doff_u32},
|
||||
{"led_polarity", S_IRUGO | S_IWUSR, (ulong)&led_polarity, doff_u8},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -35,15 +35,19 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
|
||||
#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
|
||||
#define WIL6210_IRQ_DISABLE_NO_HALP (0xF7FFFFFFUL)
|
||||
#define WIL6210_IMC_RX (BIT_DMA_EP_RX_ICR_RX_DONE | \
|
||||
BIT_DMA_EP_RX_ICR_RX_HTRSH)
|
||||
#define WIL6210_IMC_RX_NO_RX_HTRSH (WIL6210_IMC_RX & \
|
||||
(~(BIT_DMA_EP_RX_ICR_RX_HTRSH)))
|
||||
#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
|
||||
BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
|
||||
#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \
|
||||
ISR_MISC_MBOX_EVT | \
|
||||
ISR_MISC_FW_ERROR)
|
||||
|
||||
#define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \
|
||||
ISR_MISC_MBOX_EVT | \
|
||||
ISR_MISC_FW_ERROR)
|
||||
#define WIL6210_IMC_MISC (WIL6210_IMC_MISC_NO_HALP | \
|
||||
BIT_DMA_EP_MISC_ICR_HALP)
|
||||
#define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
|
||||
BIT_DMA_PSEUDO_CAUSE_TX | \
|
||||
BIT_DMA_PSEUDO_CAUSE_MISC))
|
||||
|
@ -51,6 +55,7 @@
|
|||
#if defined(CONFIG_WIL6210_ISR_COR)
|
||||
/* configure to Clear-On-Read mode */
|
||||
#define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL)
|
||||
#define WIL_ICR_ICC_MISC_VALUE (0xF7FFFFFFUL)
|
||||
|
||||
static inline void wil_icr_clear(u32 x, void __iomem *addr)
|
||||
{
|
||||
|
@ -58,6 +63,7 @@ static inline void wil_icr_clear(u32 x, void __iomem *addr)
|
|||
#else /* defined(CONFIG_WIL6210_ISR_COR) */
|
||||
/* configure to Write-1-to-Clear mode */
|
||||
#define WIL_ICR_ICC_VALUE (0UL)
|
||||
#define WIL_ICR_ICC_MISC_VALUE (0UL)
|
||||
|
||||
static inline void wil_icr_clear(u32 x, void __iomem *addr)
|
||||
{
|
||||
|
@ -86,10 +92,21 @@ static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
|
|||
WIL6210_IRQ_DISABLE);
|
||||
}
|
||||
|
||||
static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
|
||||
static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp)
|
||||
{
|
||||
wil_dbg_irq(wil, "%s: mask_halp(%s)\n", __func__,
|
||||
mask_halp ? "true" : "false");
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
|
||||
WIL6210_IRQ_DISABLE);
|
||||
mask_halp ? WIL6210_IRQ_DISABLE : WIL6210_IRQ_DISABLE_NO_HALP);
|
||||
}
|
||||
|
||||
static void wil6210_mask_halp(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_irq(wil, "%s()\n", __func__);
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
|
||||
BIT_DMA_EP_MISC_ICR_HALP);
|
||||
}
|
||||
|
||||
static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
|
||||
|
@ -109,14 +126,27 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
|
|||
|
||||
void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
|
||||
{
|
||||
bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status);
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
|
||||
WIL6210_IMC_RX);
|
||||
unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
|
||||
}
|
||||
|
||||
static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
|
||||
static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp)
|
||||
{
|
||||
wil_dbg_irq(wil, "%s: unmask_halp(%s)\n", __func__,
|
||||
unmask_halp ? "true" : "false");
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
|
||||
WIL6210_IMC_MISC);
|
||||
unmask_halp ? WIL6210_IMC_MISC : WIL6210_IMC_MISC_NO_HALP);
|
||||
}
|
||||
|
||||
static void wil6210_unmask_halp(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_irq(wil, "%s()\n", __func__);
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
|
||||
BIT_DMA_EP_MISC_ICR_HALP);
|
||||
}
|
||||
|
||||
static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
|
||||
|
@ -134,7 +164,7 @@ void wil_mask_irq(struct wil6210_priv *wil)
|
|||
|
||||
wil6210_mask_irq_tx(wil);
|
||||
wil6210_mask_irq_rx(wil);
|
||||
wil6210_mask_irq_misc(wil);
|
||||
wil6210_mask_irq_misc(wil, true);
|
||||
wil6210_mask_irq_pseudo(wil);
|
||||
}
|
||||
|
||||
|
@ -147,12 +177,12 @@ void wil_unmask_irq(struct wil6210_priv *wil)
|
|||
wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC),
|
||||
WIL_ICR_ICC_VALUE);
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC),
|
||||
WIL_ICR_ICC_VALUE);
|
||||
WIL_ICR_ICC_MISC_VALUE);
|
||||
|
||||
wil6210_unmask_irq_pseudo(wil);
|
||||
wil6210_unmask_irq_tx(wil);
|
||||
wil6210_unmask_irq_rx(wil);
|
||||
wil6210_unmask_irq_misc(wil);
|
||||
wil6210_unmask_irq_misc(wil, true);
|
||||
}
|
||||
|
||||
void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
|
||||
|
@ -228,11 +258,8 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
|
|||
*/
|
||||
if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE |
|
||||
BIT_DMA_EP_RX_ICR_RX_HTRSH))) {
|
||||
wil_dbg_irq(wil, "RX done\n");
|
||||
|
||||
if (unlikely(isr & BIT_DMA_EP_RX_ICR_RX_HTRSH))
|
||||
wil_err_ratelimited(wil,
|
||||
"Received \"Rx buffer is in risk of overflow\" interrupt\n");
|
||||
wil_dbg_irq(wil, "RX done / RX_HTRSH received, ISR (0x%x)\n",
|
||||
isr);
|
||||
|
||||
isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
|
||||
BIT_DMA_EP_RX_ICR_RX_HTRSH);
|
||||
|
@ -344,7 +371,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
wil6210_mask_irq_misc(wil);
|
||||
wil6210_mask_irq_misc(wil, false);
|
||||
|
||||
if (isr & ISR_MISC_FW_ERROR) {
|
||||
u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE);
|
||||
|
@ -372,12 +399,19 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
|||
isr &= ~ISR_MISC_FW_READY;
|
||||
}
|
||||
|
||||
if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
|
||||
wil_dbg_irq(wil, "%s: HALP IRQ invoked\n", __func__);
|
||||
wil6210_mask_halp(wil);
|
||||
isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
|
||||
complete(&wil->halp.comp);
|
||||
}
|
||||
|
||||
wil->isr_misc = isr;
|
||||
|
||||
if (isr) {
|
||||
return IRQ_WAKE_THREAD;
|
||||
} else {
|
||||
wil6210_unmask_irq_misc(wil);
|
||||
wil6210_unmask_irq_misc(wil, false);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
@ -414,7 +448,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
|
|||
|
||||
wil->isr_misc = 0;
|
||||
|
||||
wil6210_unmask_irq_misc(wil);
|
||||
wil6210_unmask_irq_misc(wil, false);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -556,6 +590,23 @@ void wil6210_clear_irq(struct wil6210_priv *wil)
|
|||
wmb(); /* make sure write completed */
|
||||
}
|
||||
|
||||
void wil6210_set_halp(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICS),
|
||||
BIT_DMA_EP_MISC_ICR_HALP);
|
||||
}
|
||||
|
||||
void wil6210_clear_halp(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICR),
|
||||
BIT_DMA_EP_MISC_ICR_HALP);
|
||||
wil6210_unmask_halp(wil);
|
||||
}
|
||||
|
||||
int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
|
||||
{
|
||||
int rc;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "wmi.h"
|
||||
#include "boot_loader.h"
|
||||
|
||||
#define WAIT_FOR_HALP_VOTE_MS 100
|
||||
|
||||
bool debug_fw; /* = false; */
|
||||
module_param(debug_fw, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
|
||||
|
@ -132,6 +134,14 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
|
|||
*d++ = __raw_readl(s++);
|
||||
}
|
||||
|
||||
void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst,
|
||||
const volatile void __iomem *src, size_t count)
|
||||
{
|
||||
wil_halp_vote(wil);
|
||||
wil_memcpy_fromio_32(dst, src, count);
|
||||
wil_halp_unvote(wil);
|
||||
}
|
||||
|
||||
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
||||
size_t count)
|
||||
{
|
||||
|
@ -142,6 +152,15 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
|||
__raw_writel(*s++, d++);
|
||||
}
|
||||
|
||||
void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil,
|
||||
volatile void __iomem *dst,
|
||||
const void *src, size_t count)
|
||||
{
|
||||
wil_halp_vote(wil);
|
||||
wil_memcpy_toio_32(dst, src, count);
|
||||
wil_halp_unvote(wil);
|
||||
}
|
||||
|
||||
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
|
||||
u16 reason_code, bool from_event)
|
||||
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
|
@ -194,6 +213,18 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
memset(&sta->stats, 0, sizeof(sta->stats));
|
||||
}
|
||||
|
||||
static bool wil_ap_is_connected(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if (wil->sta[i].status == wil_sta_connected)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
u16 reason_code, bool from_event)
|
||||
{
|
||||
|
@ -247,6 +278,11 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
|||
}
|
||||
clear_bit(wil_status_fwconnecting, wil->status);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (!wil_ap_is_connected(wil))
|
||||
clear_bit(wil_status_fwconnected, wil->status);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -457,9 +493,11 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
mutex_init(&wil->wmi_mutex);
|
||||
mutex_init(&wil->probe_client_mutex);
|
||||
mutex_init(&wil->p2p_wdev_mutex);
|
||||
mutex_init(&wil->halp.lock);
|
||||
|
||||
init_completion(&wil->wmi_ready);
|
||||
init_completion(&wil->wmi_call);
|
||||
init_completion(&wil->halp.comp);
|
||||
|
||||
wil->bcast_vring = -1;
|
||||
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
|
||||
|
@ -555,11 +593,10 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
|
|||
static void wil_set_oob_mode(struct wil6210_priv *wil, bool enable)
|
||||
{
|
||||
wil_info(wil, "%s: enable=%d\n", __func__, enable);
|
||||
if (enable) {
|
||||
if (enable)
|
||||
wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
|
||||
} else {
|
||||
else
|
||||
wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_target_reset(struct wil6210_priv *wil)
|
||||
|
@ -804,6 +841,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil_bcast_fini(wil);
|
||||
|
||||
/* Disable device led before reset*/
|
||||
wmi_led_cfg(wil, false);
|
||||
|
||||
/* prevent NAPI from being scheduled and prevent wmi commands */
|
||||
mutex_lock(&wil->wmi_mutex);
|
||||
bitmap_zero(wil->status, wil_status_last);
|
||||
|
@ -871,6 +911,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
wil->ap_isolate = 0;
|
||||
reinit_completion(&wil->wmi_ready);
|
||||
reinit_completion(&wil->wmi_call);
|
||||
reinit_completion(&wil->halp.comp);
|
||||
|
||||
if (load_fw) {
|
||||
wil_configure_interrupt_moderation(wil);
|
||||
|
@ -1061,3 +1102,51 @@ int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_halp_vote(struct wil6210_priv *wil)
|
||||
{
|
||||
unsigned long rc;
|
||||
unsigned long to_jiffies = msecs_to_jiffies(WAIT_FOR_HALP_VOTE_MS);
|
||||
|
||||
mutex_lock(&wil->halp.lock);
|
||||
|
||||
wil_dbg_misc(wil, "%s: start, HALP ref_cnt (%d)\n", __func__,
|
||||
wil->halp.ref_cnt);
|
||||
|
||||
if (++wil->halp.ref_cnt == 1) {
|
||||
wil6210_set_halp(wil);
|
||||
rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
|
||||
if (!rc)
|
||||
wil_err(wil, "%s: HALP vote timed out\n", __func__);
|
||||
else
|
||||
wil_dbg_misc(wil,
|
||||
"%s: HALP vote completed after %d ms\n",
|
||||
__func__,
|
||||
jiffies_to_msecs(to_jiffies - rc));
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "%s: end, HALP ref_cnt (%d)\n", __func__,
|
||||
wil->halp.ref_cnt);
|
||||
|
||||
mutex_unlock(&wil->halp.lock);
|
||||
}
|
||||
|
||||
void wil_halp_unvote(struct wil6210_priv *wil)
|
||||
{
|
||||
WARN_ON(wil->halp.ref_cnt == 0);
|
||||
|
||||
mutex_lock(&wil->halp.lock);
|
||||
|
||||
wil_dbg_misc(wil, "%s: start, HALP ref_cnt (%d)\n", __func__,
|
||||
wil->halp.ref_cnt);
|
||||
|
||||
if (--wil->halp.ref_cnt == 0) {
|
||||
wil6210_clear_halp(wil);
|
||||
wil_dbg_misc(wil, "%s: HALP unvote\n", __func__);
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "%s: end, HALP ref_cnt (%d)\n", __func__,
|
||||
wil->halp.ref_cnt);
|
||||
|
||||
mutex_unlock(&wil->halp.lock);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
#define P2P_SEARCH_DURATION_MS 500
|
||||
#define P2P_DEFAULT_BI 100
|
||||
|
||||
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
|
||||
{
|
||||
return (request->n_channels == 1) &&
|
||||
(request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
|
||||
}
|
||||
|
||||
void wil_p2p_discovery_timer_fn(ulong x)
|
||||
{
|
||||
struct wil6210_priv *wil = (void *)x;
|
||||
|
|
|
@ -1759,7 +1759,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
goto drop;
|
||||
}
|
||||
if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) {
|
||||
wil_err_ratelimited(wil, "FW not connected\n");
|
||||
wil_dbg_ratelimited(wil, "FW not connected, packet dropped\n");
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) {
|
||||
|
|
|
@ -168,6 +168,7 @@ struct RGF_ICR {
|
|||
#define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */
|
||||
#define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0)
|
||||
#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
|
||||
#define BIT_DMA_EP_MISC_ICR_HALP BIT(27)
|
||||
#define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */
|
||||
|
||||
/* Legacy interrupt moderation control (before Sparrow v2)*/
|
||||
|
@ -534,6 +535,41 @@ struct pmc_ctx {
|
|||
int descriptor_size;
|
||||
};
|
||||
|
||||
struct wil_halp {
|
||||
struct mutex lock; /* protect halp ref_cnt */
|
||||
unsigned int ref_cnt;
|
||||
struct completion comp;
|
||||
};
|
||||
|
||||
struct wil_blob_wrapper {
|
||||
struct wil6210_priv *wil;
|
||||
struct debugfs_blob_wrapper blob;
|
||||
};
|
||||
|
||||
#define WIL_LED_MAX_ID (2)
|
||||
#define WIL_LED_INVALID_ID (0xF)
|
||||
#define WIL_LED_BLINK_ON_SLOW_MS (300)
|
||||
#define WIL_LED_BLINK_OFF_SLOW_MS (300)
|
||||
#define WIL_LED_BLINK_ON_MED_MS (200)
|
||||
#define WIL_LED_BLINK_OFF_MED_MS (200)
|
||||
#define WIL_LED_BLINK_ON_FAST_MS (100)
|
||||
#define WIL_LED_BLINK_OFF_FAST_MS (100)
|
||||
enum {
|
||||
WIL_LED_TIME_SLOW = 0,
|
||||
WIL_LED_TIME_MED,
|
||||
WIL_LED_TIME_FAST,
|
||||
WIL_LED_TIME_LAST,
|
||||
};
|
||||
|
||||
struct blink_on_off_time {
|
||||
u32 on_ms;
|
||||
u32 off_ms;
|
||||
};
|
||||
|
||||
extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
|
||||
extern u8 led_id;
|
||||
extern u8 led_polarity;
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
struct wireless_dev *wdev;
|
||||
|
@ -606,7 +642,7 @@ struct wil6210_priv {
|
|||
atomic_t isr_count_rx, isr_count_tx;
|
||||
/* debugfs */
|
||||
struct dentry *debug;
|
||||
struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
|
||||
struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
|
||||
u8 discovery_mode;
|
||||
|
||||
void *platform_handle;
|
||||
|
@ -622,6 +658,10 @@ struct wil6210_priv {
|
|||
struct wireless_dev *p2p_wdev;
|
||||
struct mutex p2p_wdev_mutex; /* protect @p2p_wdev */
|
||||
struct wireless_dev *radio_wdev;
|
||||
|
||||
/* High Access Latency Policy voting */
|
||||
struct wil_halp halp;
|
||||
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wdev->wiphy)
|
||||
|
@ -635,11 +675,13 @@ struct wil6210_priv {
|
|||
__printf(2, 3)
|
||||
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
__printf(2, 3)
|
||||
void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
void __wil_err(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
__printf(2, 3)
|
||||
void wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
__printf(2, 3)
|
||||
void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
void __wil_info(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
__printf(2, 3)
|
||||
void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...);
|
||||
#define wil_dbg(wil, fmt, arg...) do { \
|
||||
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
|
||||
wil_dbg_trace(wil, fmt, ##arg); \
|
||||
|
@ -650,6 +692,10 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
|
|||
#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
|
||||
#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
|
||||
#define wil_dbg_pm(wil, fmt, arg...) wil_dbg(wil, "DBG[ PM ]" fmt, ##arg)
|
||||
#define wil_err(wil, fmt, arg...) __wil_err(wil, "%s: " fmt, __func__, ##arg)
|
||||
#define wil_info(wil, fmt, arg...) __wil_info(wil, "%s: " fmt, __func__, ##arg)
|
||||
#define wil_err_ratelimited(wil, fmt, arg...) \
|
||||
__wil_err_ratelimited(wil, "%s: " fmt, __func__, ##arg)
|
||||
|
||||
/* target operations */
|
||||
/* register read */
|
||||
|
@ -707,6 +753,12 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
|
|||
size_t count);
|
||||
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
||||
size_t count);
|
||||
void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst,
|
||||
const volatile void __iomem *src,
|
||||
size_t count);
|
||||
void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil,
|
||||
volatile void __iomem *dst,
|
||||
const void *src, size_t count);
|
||||
|
||||
void *wil_if_alloc(struct device *dev);
|
||||
void wil_if_free(struct wil6210_priv *wil);
|
||||
|
@ -772,6 +824,7 @@ void wil_disable_irq(struct wil6210_priv *wil);
|
|||
void wil_enable_irq(struct wil6210_priv *wil);
|
||||
|
||||
/* P2P */
|
||||
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
|
||||
void wil_p2p_discovery_timer_fn(ulong x);
|
||||
int wil_p2p_search(struct wil6210_priv *wil,
|
||||
struct cfg80211_scan_request *request);
|
||||
|
@ -805,6 +858,7 @@ 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, u8 hidden_ssid, u8 is_go);
|
||||
int wmi_pcp_stop(struct wil6210_priv *wil);
|
||||
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
u16 reason_code, bool from_event);
|
||||
void wil_probe_client_flush(struct wil6210_priv *wil);
|
||||
|
@ -842,4 +896,9 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime);
|
|||
int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size);
|
||||
void wil_fw_core_dump(struct wil6210_priv *wil);
|
||||
|
||||
void wil_halp_vote(struct wil6210_priv *wil);
|
||||
void wil_halp_unvote(struct wil6210_priv *wil);
|
||||
void wil6210_set_halp(struct wil6210_priv *wil);
|
||||
void wil6210_clear_halp(struct wil6210_priv *wil);
|
||||
|
||||
#endif /* __WIL6210_H__ */
|
||||
|
|
|
@ -32,6 +32,11 @@ module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
|
|||
MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
|
||||
" 0 - use default; < 0 - don't auto-establish");
|
||||
|
||||
u8 led_id = WIL_LED_INVALID_ID;
|
||||
module_param(led_id, byte, S_IRUGO);
|
||||
MODULE_PARM_DESC(led_id,
|
||||
" 60G device led enablement. Set the led ID (0-2) to enable");
|
||||
|
||||
/**
|
||||
* WMI event receiving - theory of operations
|
||||
*
|
||||
|
@ -94,6 +99,14 @@ const struct fw_map fw_mapping[] = {
|
|||
*/
|
||||
};
|
||||
|
||||
struct blink_on_off_time led_blink_time[] = {
|
||||
{WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
|
||||
{WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
|
||||
{WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
|
||||
};
|
||||
|
||||
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
|
||||
|
||||
/**
|
||||
* return AHB address for given firmware/ucode internal (linker) address
|
||||
* @x - internal address
|
||||
|
@ -194,6 +207,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
void __iomem *dst;
|
||||
void __iomem *head = wmi_addr(wil, r->head);
|
||||
uint retry;
|
||||
int rc = 0;
|
||||
|
||||
if (sizeof(cmd) + len > r->entry_size) {
|
||||
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
|
||||
|
@ -212,6 +226,9 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_halp_vote(wil);
|
||||
|
||||
/* read Tx head till it is not busy */
|
||||
for (retry = 5; retry > 0; retry--) {
|
||||
wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
|
||||
|
@ -221,7 +238,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
}
|
||||
if (d_head.sync != 0) {
|
||||
wil_err(wil, "WMI head busy\n");
|
||||
return -EBUSY;
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
/* next head */
|
||||
next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
|
||||
|
@ -230,7 +248,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
for (retry = 5; retry > 0; retry--) {
|
||||
if (!test_bit(wil_status_fwready, wil->status)) {
|
||||
wil_err(wil, "WMI: cannot send command while FW not ready\n");
|
||||
return -EAGAIN;
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
r->tail = wil_r(wil, RGF_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, tx.tail));
|
||||
|
@ -240,13 +259,15 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
}
|
||||
if (next_head == r->tail) {
|
||||
wil_err(wil, "WMI ring full\n");
|
||||
return -EBUSY;
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
dst = wmi_buffer(wil, d_head.addr);
|
||||
if (!dst) {
|
||||
wil_err(wil, "invalid WMI buffer: 0x%08x\n",
|
||||
le32_to_cpu(d_head.addr));
|
||||
return -EINVAL;
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
|
||||
/* set command */
|
||||
|
@ -269,7 +290,9 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS),
|
||||
SW_INT_MBOX);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
wil_halp_unvote(wil);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
|
@ -961,6 +984,60 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
|
|||
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wmi_led_cfg_cmd cmd = {
|
||||
.led_mode = enable,
|
||||
.id = led_id,
|
||||
.slow_blink_cfg.blink_on =
|
||||
cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].on_ms),
|
||||
.slow_blink_cfg.blink_off =
|
||||
cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].off_ms),
|
||||
.medium_blink_cfg.blink_on =
|
||||
cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].on_ms),
|
||||
.medium_blink_cfg.blink_off =
|
||||
cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].off_ms),
|
||||
.fast_blink_cfg.blink_on =
|
||||
cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].on_ms),
|
||||
.fast_blink_cfg.blink_off =
|
||||
cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].off_ms),
|
||||
.led_polarity = led_polarity,
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_led_cfg_done_event evt;
|
||||
} __packed reply;
|
||||
|
||||
if (led_id == WIL_LED_INVALID_ID)
|
||||
goto out;
|
||||
|
||||
if (led_id > WIL_LED_MAX_ID) {
|
||||
wil_err(wil, "Invalid led id %d\n", led_id);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil,
|
||||
"%s led %d\n",
|
||||
enable ? "enabling" : "disabling", led_id);
|
||||
|
||||
rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
|
||||
100);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (reply.evt.status) {
|
||||
wil_err(wil, "led %d cfg failed with status %d\n",
|
||||
led_id, le32_to_cpu(reply.evt.status));
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
|
||||
u8 chan, u8 hidden_ssid, u8 is_go)
|
||||
{
|
||||
|
@ -1003,11 +1080,21 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
|
|||
if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
|
||||
rc = -EINVAL;
|
||||
|
||||
if (wmi_nettype != WMI_NETTYPE_P2P)
|
||||
/* Don't fail due to error in the led configuration */
|
||||
wmi_led_cfg(wil, true);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_pcp_stop(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = wmi_led_cfg(wil, false);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
|
||||
WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ enum wmi_command_id {
|
|||
WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855,
|
||||
WMI_OTP_READ_CMDID = 0x856,
|
||||
WMI_OTP_WRITE_CMDID = 0x857,
|
||||
WMI_LED_CFG_CMDID = 0x858,
|
||||
/* Performance monitoring commands */
|
||||
WMI_BF_CTRL_CMDID = 0x862,
|
||||
WMI_NOTIFY_REQ_CMDID = 0x863,
|
||||
|
@ -868,6 +869,7 @@ enum wmi_event_id {
|
|||
WMI_RX_MGMT_PACKET_EVENTID = 0x1840,
|
||||
WMI_TX_MGMT_PACKET_EVENTID = 0x1841,
|
||||
WMI_OTP_READ_RESULT_EVENTID = 0x1856,
|
||||
WMI_LED_CFG_DONE_EVENTID = 0x1858,
|
||||
/* Performance monitoring events */
|
||||
WMI_DATA_PORT_OPEN_EVENTID = 0x1860,
|
||||
WMI_WBE_LINK_DOWN_EVENTID = 0x1861,
|
||||
|
@ -1349,4 +1351,63 @@ enum wmi_hidden_ssid {
|
|||
WMI_HIDDEN_SSID_CLEAR = 0xFE,
|
||||
};
|
||||
|
||||
/* WMI_LED_CFG_CMDID
|
||||
*
|
||||
* Configure LED On\Off\Blinking operation
|
||||
*
|
||||
* Returned events:
|
||||
* - WMI_LED_CFG_DONE_EVENTID
|
||||
*/
|
||||
enum led_mode {
|
||||
LED_DISABLE = 0x00,
|
||||
LED_ENABLE = 0x01,
|
||||
};
|
||||
|
||||
/* The names of the led as
|
||||
* described on HW schemes.
|
||||
*/
|
||||
enum wmi_led_id {
|
||||
WMI_LED_WLAN = 0x00,
|
||||
WMI_LED_WPAN = 0x01,
|
||||
WMI_LED_WWAN = 0x02,
|
||||
};
|
||||
|
||||
/* Led polarity mode. */
|
||||
enum wmi_led_polarity {
|
||||
LED_POLARITY_HIGH_ACTIVE = 0x00,
|
||||
LED_POLARITY_LOW_ACTIVE = 0x01,
|
||||
};
|
||||
|
||||
/* Combination of on and off
|
||||
* creates the blinking period
|
||||
*/
|
||||
struct wmi_led_blink_mode {
|
||||
__le32 blink_on;
|
||||
__le32 blink_off;
|
||||
} __packed;
|
||||
|
||||
/* WMI_LED_CFG_CMDID */
|
||||
struct wmi_led_cfg_cmd {
|
||||
/* enum led_mode_e */
|
||||
u8 led_mode;
|
||||
/* enum wmi_led_id_e */
|
||||
u8 id;
|
||||
/* slow speed blinking combination */
|
||||
struct wmi_led_blink_mode slow_blink_cfg;
|
||||
/* medium speed blinking combination */
|
||||
struct wmi_led_blink_mode medium_blink_cfg;
|
||||
/* high speed blinking combination */
|
||||
struct wmi_led_blink_mode fast_blink_cfg;
|
||||
/* polarity of the led */
|
||||
u8 led_polarity;
|
||||
/* reserved */
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
/* WMI_LED_CFG_DONE_EVENTID */
|
||||
struct wmi_led_cfg_done_event {
|
||||
/* led config status */
|
||||
__le32 status;
|
||||
} __packed;
|
||||
|
||||
#endif /* __WILOCITY_WMI_H__ */
|
||||
|
|
|
@ -2275,7 +2275,7 @@ static int atmel_set_freq(struct net_device *dev,
|
|||
fwrq->m = ieee80211_frequency_to_channel(f);
|
||||
}
|
||||
/* Setting by channel number */
|
||||
if ((fwrq->m > 1000) || (fwrq->e > 0))
|
||||
if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0)
|
||||
rc = -EOPNOTSUPP;
|
||||
else {
|
||||
int channel = fwrq->m;
|
||||
|
|
|
@ -1098,6 +1098,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
|
|||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
|
||||
|
|
|
@ -1333,6 +1333,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
|
|||
|
||||
switch (pub->chip) {
|
||||
case BRCM_CC_4354_CHIP_ID:
|
||||
case BRCM_CC_4356_CHIP_ID:
|
||||
/* explicitly check SR engine enable bit */
|
||||
pmu_cc3_mask = BIT(2);
|
||||
/* fall-through */
|
||||
|
|
|
@ -609,6 +609,7 @@ BRCMF_FW_NVRAM_DEF(4339, "brcmfmac4339-sdio.bin", "brcmfmac4339-sdio.txt");
|
|||
BRCMF_FW_NVRAM_DEF(43430, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt");
|
||||
|
||||
static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
|
||||
|
@ -624,7 +625,8 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
|
|||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, 43430),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354)
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356)
|
||||
};
|
||||
|
||||
static void pkt_align(struct sk_buff *p, int len, int align)
|
||||
|
|
|
@ -5794,7 +5794,7 @@ static int airo_set_freq(struct net_device *dev,
|
|||
fwrq->m = ieee80211_frequency_to_channel(f);
|
||||
}
|
||||
/* Setting by channel number */
|
||||
if((fwrq->m > 1000) || (fwrq->e > 0))
|
||||
if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0)
|
||||
rc = -EOPNOTSUPP;
|
||||
else {
|
||||
int channel = fwrq->m;
|
||||
|
|
|
@ -134,12 +134,6 @@ config IWLWIFI_DEBUGFS
|
|||
is a low-impact option that allows getting insight into the
|
||||
driver's state at runtime.
|
||||
|
||||
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
||||
bool "Experimental uCode support"
|
||||
depends on IWLWIFI_DEBUG
|
||||
---help---
|
||||
Enable use of experimental ucode for testing and debugging.
|
||||
|
||||
config IWLWIFI_DEVICE_TRACING
|
||||
bool "iwlwifi device access tracing"
|
||||
depends on EVENT_TRACING
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
static const struct iwl_base_params iwl1000_base_params = {
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
|
||||
.pll_cfg = true,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
|
||||
.shadow_ram_support = false,
|
||||
.led_compensation = 51,
|
||||
|
|
|
@ -62,7 +62,6 @@
|
|||
static const struct iwl_base_params iwl2000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 51,
|
||||
|
@ -76,7 +75,6 @@ static const struct iwl_base_params iwl2000_base_params = {
|
|||
static const struct iwl_base_params iwl2030_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
static const struct iwl_base_params iwl5000_base_params = {
|
||||
.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
|
||||
.pll_cfg = true,
|
||||
.led_compensation = 51,
|
||||
.wd_timeout = IWL_WATCHDOG_DISABLED,
|
||||
.max_event_log_size = 512,
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
static const struct iwl_base_params iwl6000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 51,
|
||||
|
@ -84,7 +83,6 @@ static const struct iwl_base_params iwl6000_base_params = {
|
|||
static const struct iwl_base_params iwl6050_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 51,
|
||||
|
@ -97,7 +95,6 @@ static const struct iwl_base_params iwl6050_base_params = {
|
|||
static const struct iwl_base_params iwl6000_g2_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
|
|
|
@ -122,7 +122,6 @@
|
|||
static const struct iwl_base_params iwl7000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_7000,
|
||||
.num_of_queues = 31,
|
||||
.pll_cfg_val = 0,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
.wd_timeout = IWL_LONG_WD_TIMEOUT,
|
||||
|
|
|
@ -112,7 +112,6 @@
|
|||
static const struct iwl_base_params iwl8000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000,
|
||||
.num_of_queues = 31,
|
||||
.pll_cfg_val = 0,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
.wd_timeout = IWL_LONG_WD_TIMEOUT,
|
||||
|
@ -237,6 +236,20 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
|
|||
.max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl8265_2ac_sdio_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless-AC 8265",
|
||||
.fw_name_pre = IWL8265_FW_PRE,
|
||||
IWL_DEVICE_8265,
|
||||
.ht_params = &iwl8000_ht_params,
|
||||
.nvm_ver = IWL8000_NVM_VERSION,
|
||||
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
|
||||
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
|
||||
.max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO,
|
||||
.disable_dummy_notification = true,
|
||||
.max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
|
||||
.max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless-AC 4165",
|
||||
.fw_name_pre = IWL8000_FW_PRE,
|
||||
|
|
|
@ -72,16 +72,21 @@
|
|||
#define IWL9000_SMEM_OFFSET 0x400000
|
||||
#define IWL9000_SMEM_LEN 0x68000
|
||||
|
||||
#define IWL9000_FW_PRE "iwlwifi-9000-"
|
||||
#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-lc-a0-"
|
||||
#define IWL9260_FW_PRE "iwlwifi-9260-th-a0-jf-a0-"
|
||||
#define IWL9260LC_FW_PRE "iwlwifi-9260-th-a0-lc-a0-"
|
||||
#define IWL9000_MODULE_FIRMWARE(api) \
|
||||
IWL9000_FW_PRE "-" __stringify(api) ".ucode"
|
||||
#define IWL9260_MODULE_FIRMWARE(api) \
|
||||
IWL9260_FW_PRE "-" __stringify(api) ".ucode"
|
||||
#define IWL9260LC_MODULE_FIRMWARE(api) \
|
||||
IWL9260LC_FW_PRE "-" __stringify(api) ".ucode"
|
||||
|
||||
#define NVM_HW_SECTION_NUM_FAMILY_9000 10
|
||||
|
||||
static const struct iwl_base_params iwl9000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_9000,
|
||||
.num_of_queues = 31,
|
||||
.pll_cfg_val = 0,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
.wd_timeout = IWL_LONG_WD_TIMEOUT,
|
||||
|
@ -138,11 +143,26 @@ static const struct iwl_tt_params iwl9000_tt_params = {
|
|||
.apmg_not_supported = true, \
|
||||
.mq_rx_supported = true, \
|
||||
.vht_mu_mimo_supported = true, \
|
||||
.mac_addr_from_csr = true
|
||||
.mac_addr_from_csr = true, \
|
||||
.rf_id = true
|
||||
|
||||
const struct iwl_cfg iwl9560_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC 9560",
|
||||
.fw_name_pre = IWL9000_FW_PRE,
|
||||
const struct iwl_cfg iwl9260_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC 9260",
|
||||
.fw_name_pre = IWL9260_FW_PRE,
|
||||
IWL_DEVICE_9000,
|
||||
.ht_params = &iwl9000_ht_params,
|
||||
.nvm_ver = IWL9000_NVM_VERSION,
|
||||
.nvm_calib_ver = IWL9000_TX_POWER_VERSION,
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO the struct below is for internal testing only this should be
|
||||
* removed by EO 2016~
|
||||
*/
|
||||
const struct iwl_cfg iwl9260lc_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC 9260",
|
||||
.fw_name_pre = IWL9260LC_FW_PRE,
|
||||
IWL_DEVICE_9000,
|
||||
.ht_params = &iwl9000_ht_params,
|
||||
.nvm_ver = IWL9000_NVM_VERSION,
|
||||
|
@ -161,3 +181,5 @@ const struct iwl_cfg iwl5165_2ac_cfg = {
|
|||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL9260_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL9260LC_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -31,6 +32,7 @@
|
|||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2016 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -165,20 +167,22 @@ static inline u8 num_of_ant(u8 mask)
|
|||
* @scd_chain_ext_wa: should the chain extension feature in SCD be disabled.
|
||||
*/
|
||||
struct iwl_base_params {
|
||||
int eeprom_size;
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
/* for iwl_pcie_apm_init() */
|
||||
u32 pll_cfg_val;
|
||||
|
||||
const u16 max_ll_items;
|
||||
const bool shadow_ram_support;
|
||||
u16 led_compensation;
|
||||
unsigned int wd_timeout;
|
||||
u32 max_event_log_size;
|
||||
const bool shadow_reg_enable;
|
||||
const bool pcie_l1_allowed;
|
||||
const bool apmg_wake_up_wa;
|
||||
const bool scd_chain_ext_wa;
|
||||
|
||||
u16 eeprom_size;
|
||||
u16 max_event_log_size;
|
||||
|
||||
u8 pll_cfg:1, /* for iwl_pcie_apm_init() */
|
||||
shadow_ram_support:1,
|
||||
shadow_reg_enable:1,
|
||||
pcie_l1_allowed:1,
|
||||
apmg_wake_up_wa:1,
|
||||
scd_chain_ext_wa:1;
|
||||
|
||||
u8 num_of_queues; /* def: HW dependent */
|
||||
|
||||
u8 max_ll_items;
|
||||
u8 led_compensation;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -189,10 +193,10 @@ struct iwl_base_params {
|
|||
*/
|
||||
struct iwl_ht_params {
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
const bool ht_greenfield_support; /* if used set to true */
|
||||
const bool stbc;
|
||||
const bool ldpc;
|
||||
bool use_rts_for_aggregation;
|
||||
u8 ht_greenfield_support:1,
|
||||
stbc:1,
|
||||
ldpc:1,
|
||||
use_rts_for_aggregation:1;
|
||||
u8 ht40_bands;
|
||||
};
|
||||
|
||||
|
@ -233,10 +237,10 @@ struct iwl_tt_params {
|
|||
u32 tx_protection_entry;
|
||||
u32 tx_protection_exit;
|
||||
struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
|
||||
bool support_ct_kill;
|
||||
bool support_dynamic_smps;
|
||||
bool support_tx_protection;
|
||||
bool support_tx_backoff;
|
||||
u8 support_ct_kill:1,
|
||||
support_dynamic_smps:1,
|
||||
support_tx_protection:1,
|
||||
support_tx_backoff:1;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -314,6 +318,7 @@ struct iwl_pwr_tx_backoff {
|
|||
* @smem_len: the length of SMEM
|
||||
* @mq_rx_supported: multi-queue rx support
|
||||
* @vht_mu_mimo_supported: VHT MU-MIMO support
|
||||
* @rf_id: need to read rf_id to determine the firmware image
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt. hardware features.
|
||||
* API differences in uCode shouldn't be handled here but through TLVs
|
||||
|
@ -323,50 +328,51 @@ struct iwl_cfg {
|
|||
/* params specific to an individual device within a device family */
|
||||
const char *name;
|
||||
const char *fw_name_pre;
|
||||
const unsigned int ucode_api_max;
|
||||
const unsigned int ucode_api_min;
|
||||
const enum iwl_device_family device_family;
|
||||
const u32 max_data_size;
|
||||
const u32 max_inst_size;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u8 non_shared_ant;
|
||||
bool bt_shared_single_ant;
|
||||
u16 nvm_ver;
|
||||
u16 nvm_calib_ver;
|
||||
/* params not likely to change within a device family */
|
||||
const struct iwl_base_params *base_params;
|
||||
/* params likely to change within a device family */
|
||||
const struct iwl_ht_params *ht_params;
|
||||
const struct iwl_eeprom_params *eeprom_params;
|
||||
enum iwl_led_mode led_mode;
|
||||
const bool rx_with_siso_diversity;
|
||||
const bool internal_wimax_coex;
|
||||
const bool host_interrupt_operation_mode;
|
||||
bool high_temp;
|
||||
u8 nvm_hw_section_num;
|
||||
bool mac_addr_from_csr;
|
||||
bool lp_xtal_workaround;
|
||||
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
|
||||
bool no_power_up_nic_in_init;
|
||||
const char *default_nvm_file_B_step;
|
||||
const char *default_nvm_file_C_step;
|
||||
netdev_features_t features;
|
||||
unsigned int max_rx_agg_size;
|
||||
bool disable_dummy_notification;
|
||||
unsigned int max_tx_agg_size;
|
||||
unsigned int max_ht_ampdu_exponent;
|
||||
unsigned int max_vht_ampdu_exponent;
|
||||
const u32 dccm_offset;
|
||||
const u32 dccm_len;
|
||||
const u32 dccm2_offset;
|
||||
const u32 dccm2_len;
|
||||
const u32 smem_offset;
|
||||
const u32 smem_len;
|
||||
const struct iwl_tt_params *thermal_params;
|
||||
bool apmg_not_supported;
|
||||
bool mq_rx_supported;
|
||||
bool vht_mu_mimo_supported;
|
||||
enum iwl_device_family device_family;
|
||||
enum iwl_led_mode led_mode;
|
||||
u32 max_data_size;
|
||||
u32 max_inst_size;
|
||||
netdev_features_t features;
|
||||
u32 dccm_offset;
|
||||
u32 dccm_len;
|
||||
u32 dccm2_offset;
|
||||
u32 dccm2_len;
|
||||
u32 smem_offset;
|
||||
u32 smem_len;
|
||||
u16 nvm_ver;
|
||||
u16 nvm_calib_ver;
|
||||
u16 rx_with_siso_diversity:1,
|
||||
bt_shared_single_ant:1,
|
||||
internal_wimax_coex:1,
|
||||
host_interrupt_operation_mode:1,
|
||||
high_temp:1,
|
||||
mac_addr_from_csr:1,
|
||||
lp_xtal_workaround:1,
|
||||
no_power_up_nic_in_init:1,
|
||||
disable_dummy_notification:1,
|
||||
apmg_not_supported:1,
|
||||
mq_rx_supported:1,
|
||||
vht_mu_mimo_supported:1,
|
||||
rf_id:1;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u8 non_shared_ant;
|
||||
u8 nvm_hw_section_num;
|
||||
u8 max_rx_agg_size;
|
||||
u8 max_tx_agg_size;
|
||||
u8 max_ht_ampdu_exponent;
|
||||
u8 max_vht_ampdu_exponent;
|
||||
u8 ucode_api_max;
|
||||
u8 ucode_api_min;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -437,8 +443,10 @@ extern const struct iwl_cfg iwl8260_2ac_cfg;
|
|||
extern const struct iwl_cfg iwl8265_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl4165_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
|
||||
extern const struct iwl_cfg iwl8265_2ac_sdio_cfg;
|
||||
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
|
||||
extern const struct iwl_cfg iwl9560_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl9260_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl9260lc_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl5165_2ac_cfg;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
|
|
|
@ -107,6 +107,17 @@
|
|||
*/
|
||||
#define CSR_HW_REV (CSR_BASE+0x028)
|
||||
|
||||
/*
|
||||
* RF ID revision info
|
||||
* Bit fields:
|
||||
* 31:24: Reserved (set to 0x0)
|
||||
* 23:12: Type
|
||||
* 11:8: Step (A - 0x0, B - 0x1, etc)
|
||||
* 7:4: Dash
|
||||
* 3:0: Flavor
|
||||
*/
|
||||
#define CSR_HW_RF_ID (CSR_BASE+0x09c)
|
||||
|
||||
/*
|
||||
* EEPROM and OTP (one-time-programmable) memory reads
|
||||
*
|
||||
|
@ -333,6 +344,10 @@ enum {
|
|||
#define CSR_HW_REV_TYPE_7265D (0x0000210)
|
||||
#define CSR_HW_REV_TYPE_NONE (0x00001F0)
|
||||
|
||||
/* RF_ID value */
|
||||
#define CSR_HW_RF_ID_TYPE_JF (0x00105000)
|
||||
#define CSR_HW_RF_ID_TYPE_LC (0x00101000)
|
||||
|
||||
/* EEPROM REG */
|
||||
#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
|
||||
#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
|
||||
|
|
|
@ -117,7 +117,7 @@ struct iwl_drv {
|
|||
const struct iwl_cfg *cfg;
|
||||
|
||||
int fw_index; /* firmware we're trying to load */
|
||||
char firmware_name[32]; /* name of firmware file to load */
|
||||
char firmware_name[64]; /* name of firmware file to load */
|
||||
|
||||
struct completion request_firmware_complete;
|
||||
|
||||
|
@ -211,20 +211,12 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
|
|||
static void iwl_req_fw_callback(const struct firmware *ucode_raw,
|
||||
void *context);
|
||||
|
||||
#define UCODE_EXPERIMENTAL_INDEX 100
|
||||
#define UCODE_EXPERIMENTAL_TAG "exp"
|
||||
|
||||
static int iwl_request_firmware(struct iwl_drv *drv, bool first)
|
||||
{
|
||||
const char *name_pre = drv->cfg->fw_name_pre;
|
||||
char tag[8];
|
||||
|
||||
if (first) {
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
||||
drv->fw_index = UCODE_EXPERIMENTAL_INDEX;
|
||||
strcpy(tag, UCODE_EXPERIMENTAL_TAG);
|
||||
} else if (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
|
||||
#endif
|
||||
drv->fw_index = drv->cfg->ucode_api_max;
|
||||
sprintf(tag, "%d", drv->fw_index);
|
||||
} else {
|
||||
|
@ -240,9 +232,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
|
|||
snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode",
|
||||
name_pre, tag);
|
||||
|
||||
IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n",
|
||||
(drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
||||
? "EXPERIMENTAL " : "",
|
||||
IWL_DEBUG_INFO(drv, "attempting to load firmware '%s'\n",
|
||||
drv->firmware_name);
|
||||
|
||||
return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name,
|
||||
|
@ -541,9 +531,7 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
|
|||
}
|
||||
|
||||
if (build)
|
||||
sprintf(buildstr, " build %u%s", build,
|
||||
(drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
||||
? " (EXP)" : "");
|
||||
sprintf(buildstr, " build %u", build);
|
||||
else
|
||||
buildstr[0] = '\0';
|
||||
|
||||
|
@ -627,9 +615,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
build = le32_to_cpu(ucode->build);
|
||||
|
||||
if (build)
|
||||
sprintf(buildstr, " build %u%s", build,
|
||||
(drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
||||
? " (EXP)" : "");
|
||||
sprintf(buildstr, " build %u", build);
|
||||
else
|
||||
buildstr[0] = '\0';
|
||||
|
||||
|
@ -1277,15 +1263,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
|||
* firmware filename ... but we don't check for that and only rely
|
||||
* on the API version read from firmware header from here on forward
|
||||
*/
|
||||
/* no api version check required for experimental uCode */
|
||||
if (drv->fw_index != UCODE_EXPERIMENTAL_INDEX) {
|
||||
if (api_ver < api_min || api_ver > api_max) {
|
||||
IWL_ERR(drv,
|
||||
"Driver unable to support your firmware API. "
|
||||
"Driver supports v%u, firmware is v%u.\n",
|
||||
api_max, api_ver);
|
||||
goto try_again;
|
||||
}
|
||||
if (api_ver < api_min || api_ver > api_max) {
|
||||
IWL_ERR(drv,
|
||||
"Driver unable to support your firmware API. "
|
||||
"Driver supports v%u, firmware is v%u.\n",
|
||||
api_max, api_ver);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1744,4 +1727,4 @@ MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)");
|
|||
|
||||
module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool,
|
||||
S_IRUGO);
|
||||
MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities");
|
||||
MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities (default: false)");
|
||||
|
|
|
@ -98,6 +98,7 @@ struct iwl_nvm_data {
|
|||
s8 max_tx_pwr_half_dbm;
|
||||
|
||||
bool lar_enabled;
|
||||
bool vht160_supported;
|
||||
struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
|
||||
struct ieee80211_channel channels[];
|
||||
};
|
||||
|
|
|
@ -321,6 +321,9 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
|
|||
/* Write index table */
|
||||
#define RFH_Q0_FRBDCB_WIDX 0xA08080
|
||||
#define RFH_Q_FRBDCB_WIDX(q) (RFH_Q0_FRBDCB_WIDX + (q) * 4)
|
||||
/* Write index table - shadow registers */
|
||||
#define RFH_Q0_FRBDCB_WIDX_TRG 0x1C80
|
||||
#define RFH_Q_FRBDCB_WIDX_TRG(q) (RFH_Q0_FRBDCB_WIDX_TRG + (q) * 4)
|
||||
/* Read index table */
|
||||
#define RFH_Q0_FRBDCB_RIDX 0xA080C0
|
||||
#define RFH_Q_FRBDCB_RIDX(q) (RFH_Q0_FRBDCB_RIDX + (q) * 4)
|
||||
|
|
|
@ -288,6 +288,9 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
|||
!data->sku_cap_band_52GHz_enable)
|
||||
continue;
|
||||
|
||||
if (ch_flags & NVM_CHANNEL_160MHZ)
|
||||
data->vht160_supported = true;
|
||||
|
||||
if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
|
||||
/*
|
||||
* Channels might become valid later if lar is
|
||||
|
@ -331,17 +334,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
|||
channel->flags = 0;
|
||||
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
|
||||
"Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n",
|
||||
channel->hw_value,
|
||||
is_5ghz ? "5.2" : "2.4",
|
||||
ch_flags,
|
||||
CHECK_AND_PRINT_I(VALID),
|
||||
CHECK_AND_PRINT_I(IBSS),
|
||||
CHECK_AND_PRINT_I(ACTIVE),
|
||||
CHECK_AND_PRINT_I(RADAR),
|
||||
CHECK_AND_PRINT_I(WIDE),
|
||||
CHECK_AND_PRINT_I(INDOOR_ONLY),
|
||||
CHECK_AND_PRINT_I(GO_CONCURRENT),
|
||||
ch_flags,
|
||||
CHECK_AND_PRINT_I(WIDE),
|
||||
CHECK_AND_PRINT_I(40MHZ),
|
||||
CHECK_AND_PRINT_I(80MHZ),
|
||||
CHECK_AND_PRINT_I(160MHZ),
|
||||
channel->max_power,
|
||||
((ch_flags & NVM_CHANNEL_IBSS) &&
|
||||
!(ch_flags & NVM_CHANNEL_RADAR))
|
||||
|
@ -370,6 +376,10 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
|||
max_ampdu_exponent <<
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
||||
|
||||
if (data->vht160_supported)
|
||||
vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160;
|
||||
|
||||
if (cfg->vht_mu_mimo_supported)
|
||||
vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -72,8 +73,6 @@
|
|||
#include "iwl-trans.h"
|
||||
|
||||
#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */
|
||||
#define IWL_NUM_PAPD_CH_GROUPS 9
|
||||
#define IWL_NUM_TXP_CH_GROUPS 9
|
||||
|
||||
struct iwl_phy_db_entry {
|
||||
u16 size;
|
||||
|
@ -86,14 +85,18 @@ struct iwl_phy_db_entry {
|
|||
* @cfg: phy configuration.
|
||||
* @calib_nch: non channel specific calibration data.
|
||||
* @calib_ch: channel specific calibration data.
|
||||
* @n_group_papd: number of entries in papd channel group.
|
||||
* @calib_ch_group_papd: calibration data related to papd channel group.
|
||||
* @n_group_txp: number of entries in tx power channel group.
|
||||
* @calib_ch_group_txp: calibration data related to tx power chanel group.
|
||||
*/
|
||||
struct iwl_phy_db {
|
||||
struct iwl_phy_db_entry cfg;
|
||||
struct iwl_phy_db_entry calib_nch;
|
||||
struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS];
|
||||
struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS];
|
||||
int n_group_papd;
|
||||
struct iwl_phy_db_entry *calib_ch_group_papd;
|
||||
int n_group_txp;
|
||||
struct iwl_phy_db_entry *calib_ch_group_txp;
|
||||
|
||||
struct iwl_trans *trans;
|
||||
};
|
||||
|
@ -143,6 +146,9 @@ struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
|
|||
|
||||
phy_db->trans = trans;
|
||||
|
||||
phy_db->n_group_txp = -1;
|
||||
phy_db->n_group_papd = -1;
|
||||
|
||||
/* TODO: add default values of the phy db. */
|
||||
return phy_db;
|
||||
}
|
||||
|
@ -166,11 +172,11 @@ iwl_phy_db_get_section(struct iwl_phy_db *phy_db,
|
|||
case IWL_PHY_DB_CALIB_NCH:
|
||||
return &phy_db->calib_nch;
|
||||
case IWL_PHY_DB_CALIB_CHG_PAPD:
|
||||
if (chg_id >= IWL_NUM_PAPD_CH_GROUPS)
|
||||
if (chg_id >= phy_db->n_group_papd)
|
||||
return NULL;
|
||||
return &phy_db->calib_ch_group_papd[chg_id];
|
||||
case IWL_PHY_DB_CALIB_CHG_TXP:
|
||||
if (chg_id >= IWL_NUM_TXP_CH_GROUPS)
|
||||
if (chg_id >= phy_db->n_group_txp)
|
||||
return NULL;
|
||||
return &phy_db->calib_ch_group_txp[chg_id];
|
||||
default:
|
||||
|
@ -202,17 +208,21 @@ void iwl_phy_db_free(struct iwl_phy_db *phy_db)
|
|||
|
||||
iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0);
|
||||
iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0);
|
||||
for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++)
|
||||
|
||||
for (i = 0; i < phy_db->n_group_papd; i++)
|
||||
iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i);
|
||||
for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++)
|
||||
kfree(phy_db->calib_ch_group_papd);
|
||||
|
||||
for (i = 0; i < phy_db->n_group_txp; i++)
|
||||
iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i);
|
||||
kfree(phy_db->calib_ch_group_txp);
|
||||
|
||||
kfree(phy_db);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_phy_db_free);
|
||||
|
||||
int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
|
||||
gfp_t alloc_ctx)
|
||||
int iwl_phy_db_set_section(struct iwl_phy_db *phy_db,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_calib_res_notif_phy_db *phy_db_notif =
|
||||
(struct iwl_calib_res_notif_phy_db *)pkt->data;
|
||||
|
@ -224,16 +234,42 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
|
|||
if (!phy_db)
|
||||
return -EINVAL;
|
||||
|
||||
if (type == IWL_PHY_DB_CALIB_CHG_PAPD ||
|
||||
type == IWL_PHY_DB_CALIB_CHG_TXP)
|
||||
if (type == IWL_PHY_DB_CALIB_CHG_PAPD) {
|
||||
chg_id = le16_to_cpup((__le16 *)phy_db_notif->data);
|
||||
if (phy_db && !phy_db->calib_ch_group_papd) {
|
||||
/*
|
||||
* Firmware sends the largest index first, so we can use
|
||||
* it to know how much we should allocate.
|
||||
*/
|
||||
phy_db->calib_ch_group_papd = kcalloc(chg_id + 1,
|
||||
sizeof(struct iwl_phy_db_entry),
|
||||
GFP_ATOMIC);
|
||||
if (!phy_db->calib_ch_group_papd)
|
||||
return -ENOMEM;
|
||||
phy_db->n_group_papd = chg_id + 1;
|
||||
}
|
||||
} else if (type == IWL_PHY_DB_CALIB_CHG_TXP) {
|
||||
chg_id = le16_to_cpup((__le16 *)phy_db_notif->data);
|
||||
if (phy_db && !phy_db->calib_ch_group_txp) {
|
||||
/*
|
||||
* Firmware sends the largest index first, so we can use
|
||||
* it to know how much we should allocate.
|
||||
*/
|
||||
phy_db->calib_ch_group_txp = kcalloc(chg_id + 1,
|
||||
sizeof(struct iwl_phy_db_entry),
|
||||
GFP_ATOMIC);
|
||||
if (!phy_db->calib_ch_group_txp)
|
||||
return -ENOMEM;
|
||||
phy_db->n_group_txp = chg_id + 1;
|
||||
}
|
||||
}
|
||||
|
||||
entry = iwl_phy_db_get_section(phy_db, type, chg_id);
|
||||
if (!entry)
|
||||
return -EINVAL;
|
||||
|
||||
kfree(entry->data);
|
||||
entry->data = kmemdup(phy_db_notif->data, size, alloc_ctx);
|
||||
entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC);
|
||||
if (!entry->data) {
|
||||
entry->size = 0;
|
||||
return -ENOMEM;
|
||||
|
@ -296,7 +332,7 @@ static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id)
|
|||
if (ch_index == 0xff)
|
||||
return 0xff;
|
||||
|
||||
for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) {
|
||||
for (i = 0; i < phy_db->n_group_txp; i++) {
|
||||
txp_chg = (void *)phy_db->calib_ch_group_txp[i].data;
|
||||
if (!txp_chg)
|
||||
return 0xff;
|
||||
|
@ -447,7 +483,7 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
|
|||
/* Send all the TXP channel specific data */
|
||||
err = iwl_phy_db_send_all_channel_groups(phy_db,
|
||||
IWL_PHY_DB_CALIB_CHG_PAPD,
|
||||
IWL_NUM_PAPD_CH_GROUPS);
|
||||
phy_db->n_group_papd);
|
||||
if (err) {
|
||||
IWL_ERR(phy_db->trans,
|
||||
"Cannot send channel specific PAPD groups\n");
|
||||
|
@ -457,7 +493,7 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
|
|||
/* Send all the TXP channel specific data */
|
||||
err = iwl_phy_db_send_all_channel_groups(phy_db,
|
||||
IWL_PHY_DB_CALIB_CHG_TXP,
|
||||
IWL_NUM_TXP_CH_GROUPS);
|
||||
phy_db->n_group_txp);
|
||||
if (err) {
|
||||
IWL_ERR(phy_db->trans,
|
||||
"Cannot send channel specific TX power groups\n");
|
||||
|
|
|
@ -73,8 +73,8 @@ struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans);
|
|||
|
||||
void iwl_phy_db_free(struct iwl_phy_db *phy_db);
|
||||
|
||||
int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
|
||||
gfp_t alloc_ctx);
|
||||
int iwl_phy_db_set_section(struct iwl_phy_db *phy_db,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
|
||||
int iwl_send_phy_db_data(struct iwl_phy_db *phy_db);
|
||||
|
|
|
@ -753,6 +753,7 @@ enum iwl_plat_pm_mode {
|
|||
* @dev - pointer to struct device * that represents the device
|
||||
* @max_skb_frags: maximum number of fragments an SKB can have when transmitted.
|
||||
* 0 indicates that frag SKBs (NETIF_F_SG) aren't supported.
|
||||
* @hw_rf_id a u32 with the device RF ID
|
||||
* @hw_id: a u32 with the ID of the device / sub-device.
|
||||
* Set during transport allocation.
|
||||
* @hw_id_str: a string with info about HW ID. Set during transport allocation.
|
||||
|
@ -797,6 +798,7 @@ struct iwl_trans {
|
|||
struct device *dev;
|
||||
u32 max_skb_frags;
|
||||
u32 hw_rev;
|
||||
u32 hw_rf_id;
|
||||
u32 hw_id;
|
||||
char hw_id_str[52];
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
#define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1
|
||||
#define IWL_MVM_TOF_IS_RESPONDER 0
|
||||
#define IWL_MVM_SW_TX_CSUM_OFFLOAD 0
|
||||
#define IWL_MVM_HW_CSUM_DISABLE 0
|
||||
#define IWL_MVM_COLLECT_FW_ERR_DUMP 1
|
||||
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
|
||||
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
|
||||
|
|
|
@ -1804,7 +1804,6 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
struct iwl_wowlan_status *fw_status;
|
||||
int i;
|
||||
bool keep;
|
||||
struct ieee80211_sta *ap_sta;
|
||||
struct iwl_mvm_sta *mvm_ap_sta;
|
||||
|
||||
fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
|
||||
|
@ -1823,13 +1822,10 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
status.wake_packet = fw_status->wake_packet;
|
||||
|
||||
/* still at hard-coded place 0 for D3 image */
|
||||
ap_sta = rcu_dereference_protected(
|
||||
mvm->fw_id_to_mac_id[0],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (IS_ERR_OR_NULL(ap_sta))
|
||||
mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, 0);
|
||||
if (!mvm_ap_sta)
|
||||
goto out_free;
|
||||
|
||||
mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
|
||||
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
|
||||
u16 seq = status.qos_seq_ctr[i];
|
||||
/* firmware stores last-used value, we store next value */
|
||||
|
|
|
@ -281,13 +281,10 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
|
|||
|
||||
if (vif->type == NL80211_IFTYPE_STATION &&
|
||||
ap_sta_id != IWL_MVM_STATION_COUNT) {
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (!IS_ERR_OR_NULL(sta)) {
|
||||
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct iwl_mvm_sta *mvm_sta;
|
||||
|
||||
mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
|
||||
if (mvm_sta) {
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"ap_sta_id %d - reduced Tx power %d\n",
|
||||
ap_sta_id,
|
||||
|
|
|
@ -1309,6 +1309,8 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
|
|||
PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
|
||||
PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
|
||||
PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE);
|
||||
PRINT_MVM_REF(IWL_MVM_REF_SENDING_CMD);
|
||||
PRINT_MVM_REF(IWL_MVM_REF_RX);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
|
|
@ -368,7 +368,7 @@ struct iwl_wowlan_gtk_status {
|
|||
u8 decrypt_key[16];
|
||||
u8 tkip_mic_key[8];
|
||||
struct iwl_wowlan_rsc_tsc_params_cmd rsc;
|
||||
} __packed;
|
||||
} __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */
|
||||
|
||||
struct iwl_wowlan_status {
|
||||
struct iwl_wowlan_gtk_status gtk;
|
||||
|
|
|
@ -437,21 +437,28 @@ struct iwl_rxq_sync_notification {
|
|||
/**
|
||||
* Internal message identifier
|
||||
*
|
||||
* @IWL_MVM_RXQ_EMPTY: empty sync notification
|
||||
* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
|
||||
*/
|
||||
enum iwl_mvm_rxq_notif_type {
|
||||
IWL_MVM_RXQ_EMPTY,
|
||||
IWL_MVM_RXQ_NOTIF_DEL_BA,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
|
||||
* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
|
||||
* FW is agnostic to the payload, so there are no endianity requirements.
|
||||
*
|
||||
* @type: value from &iwl_mvm_rxq_notif_type
|
||||
* @sync: ctrl path is waiting for all notifications to be received
|
||||
* @cookie: internal cookie to identify old notifications
|
||||
* @data: payload
|
||||
*/
|
||||
struct iwl_mvm_internal_rxq_notif {
|
||||
u32 type;
|
||||
u16 type;
|
||||
u16 sync;
|
||||
u32 cookie;
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ enum iwl_sta_key_flag {
|
|||
|
||||
/**
|
||||
* enum iwl_sta_modify_flag - indicate to the fw what flag are being changed
|
||||
* @STA_MODIFY_KEY: this command modifies %key
|
||||
* @STA_MODIFY_QUEUE_REMOVAL: this command removes a queue
|
||||
* @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx
|
||||
* @STA_MODIFY_TX_RATE: unused
|
||||
* @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid
|
||||
|
@ -183,7 +183,7 @@ enum iwl_sta_key_flag {
|
|||
* @STA_MODIFY_QUEUES: modify the queues used by this station
|
||||
*/
|
||||
enum iwl_sta_modify_flag {
|
||||
STA_MODIFY_KEY = BIT(0),
|
||||
STA_MODIFY_QUEUE_REMOVAL = BIT(0),
|
||||
STA_MODIFY_TID_DISABLE_TX = BIT(1),
|
||||
STA_MODIFY_TX_RATE = BIT(2),
|
||||
STA_MODIFY_ADD_BA_TID = BIT(3),
|
||||
|
@ -255,8 +255,10 @@ struct iwl_mvm_keyinfo {
|
|||
__le64 hw_tkip_mic_tx_key;
|
||||
} __packed;
|
||||
|
||||
#define IWL_ADD_STA_STATUS_MASK 0xFF
|
||||
#define IWL_ADD_STA_BAID_MASK 0xFF00
|
||||
#define IWL_ADD_STA_STATUS_MASK 0xFF
|
||||
#define IWL_ADD_STA_BAID_VALID_MASK 0x8000
|
||||
#define IWL_ADD_STA_BAID_MASK 0x7F00
|
||||
#define IWL_ADD_STA_BAID_SHIFT 8
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table.
|
||||
|
|
|
@ -90,6 +90,7 @@ enum {
|
|||
* DQA queue numbers
|
||||
*
|
||||
* @IWL_MVM_DQA_CMD_QUEUE: a queue reserved for sending HCMDs to the FW
|
||||
* @IWL_MVM_DQA_P2P_DEVICE_QUEUE: a queue reserved for P2P device frames
|
||||
* @IWL_MVM_DQA_GCAST_QUEUE: a queue reserved for P2P GO/SoftAP GCAST frames
|
||||
* @IWL_MVM_DQA_BSS_CLIENT_QUEUE: a queue reserved for BSS activity, to ensure
|
||||
* that we are never left without the possibility to connect to an AP.
|
||||
|
@ -97,6 +98,8 @@ enum {
|
|||
* Each MGMT queue is mapped to a single STA
|
||||
* MGMT frames are frames that return true on ieee80211_is_mgmt()
|
||||
* @IWL_MVM_DQA_MAX_MGMT_QUEUE: last TXQ in pool for MGMT frames
|
||||
* @IWL_MVM_DQA_AP_PROBE_RESP_QUEUE: a queue reserved for P2P GO/SoftAP probe
|
||||
* responses
|
||||
* @IWL_MVM_DQA_MIN_DATA_QUEUE: first TXQ in pool for DATA frames.
|
||||
* DATA frames are intended for !ieee80211_is_mgmt() frames, but if
|
||||
* the MGMT TXQ pool is exhausted, mgmt frames can be sent on DATA queues
|
||||
|
@ -105,10 +108,12 @@ enum {
|
|||
*/
|
||||
enum iwl_mvm_dqa_txq {
|
||||
IWL_MVM_DQA_CMD_QUEUE = 0,
|
||||
IWL_MVM_DQA_P2P_DEVICE_QUEUE = 2,
|
||||
IWL_MVM_DQA_GCAST_QUEUE = 3,
|
||||
IWL_MVM_DQA_BSS_CLIENT_QUEUE = 4,
|
||||
IWL_MVM_DQA_MIN_MGMT_QUEUE = 5,
|
||||
IWL_MVM_DQA_MAX_MGMT_QUEUE = 8,
|
||||
IWL_MVM_DQA_AP_PROBE_RESP_QUEUE = 9,
|
||||
IWL_MVM_DQA_MIN_DATA_QUEUE = 10,
|
||||
IWL_MVM_DQA_MAX_DATA_QUEUE = 31,
|
||||
};
|
||||
|
|
|
@ -271,9 +271,6 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
|
|||
for (i = 0;
|
||||
i < ARRAY_SIZE(mvm->shared_mem_cfg.internal_txfifo_size);
|
||||
i++) {
|
||||
/* Mark the number of TXF we're pulling now */
|
||||
iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i);
|
||||
|
||||
fifo_hdr = (void *)(*dump_data)->data;
|
||||
fifo_data = (void *)fifo_hdr->data;
|
||||
fifo_len = mvm->shared_mem_cfg.internal_txfifo_size[i];
|
||||
|
@ -289,6 +286,10 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
|
|||
cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
|
||||
|
||||
fifo_hdr->fifo_num = cpu_to_le32(i);
|
||||
|
||||
/* Mark the number of TXF we're pulling now */
|
||||
iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i);
|
||||
|
||||
fifo_hdr->available_bytes =
|
||||
cpu_to_le32(iwl_trans_read_prph(mvm->trans,
|
||||
TXF_CPU2_FIFO_ITEM_CNT));
|
||||
|
@ -339,9 +340,11 @@ void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
|
|||
#define IWL8260_ICCM_OFFSET 0x44000 /* Only for B-step */
|
||||
#define IWL8260_ICCM_LEN 0xC000 /* Only for B-step */
|
||||
|
||||
static const struct {
|
||||
struct iwl_prph_range {
|
||||
u32 start, end;
|
||||
} iwl_prph_dump_addr[] = {
|
||||
};
|
||||
|
||||
static const struct iwl_prph_range iwl_prph_dump_addr_comm[] = {
|
||||
{ .start = 0x00a00000, .end = 0x00a00000 },
|
||||
{ .start = 0x00a0000c, .end = 0x00a00024 },
|
||||
{ .start = 0x00a0002c, .end = 0x00a0003c },
|
||||
|
@ -439,8 +442,18 @@ static const struct {
|
|||
{ .start = 0x00a44000, .end = 0x00a7bf80 },
|
||||
};
|
||||
|
||||
static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
|
||||
{ .start = 0x00a05c00, .end = 0x00a05c18 },
|
||||
{ .start = 0x00a05400, .end = 0x00a056e8 },
|
||||
{ .start = 0x00a08000, .end = 0x00a098bc },
|
||||
{ .start = 0x00adfc00, .end = 0x00adfd1c },
|
||||
{ .start = 0x00a02400, .end = 0x00a02758 },
|
||||
};
|
||||
|
||||
static u32 iwl_dump_prph(struct iwl_trans *trans,
|
||||
struct iwl_fw_error_dump_data **data)
|
||||
struct iwl_fw_error_dump_data **data,
|
||||
const struct iwl_prph_range *iwl_prph_dump_addr,
|
||||
u32 range_len)
|
||||
{
|
||||
struct iwl_fw_error_dump_prph *prph;
|
||||
unsigned long flags;
|
||||
|
@ -449,7 +462,7 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,
|
|||
if (!iwl_trans_grab_nic_access(trans, &flags))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
|
||||
for (i = 0; i < range_len; i++) {
|
||||
/* The range includes both boundaries */
|
||||
int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
|
||||
iwl_prph_dump_addr[i].start + 4;
|
||||
|
@ -572,16 +585,31 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
|||
}
|
||||
|
||||
/* Make room for PRPH registers */
|
||||
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); i++) {
|
||||
/* The range includes both boundaries */
|
||||
int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
|
||||
iwl_prph_dump_addr[i].start + 4;
|
||||
int num_bytes_in_chunk =
|
||||
iwl_prph_dump_addr_comm[i].end -
|
||||
iwl_prph_dump_addr_comm[i].start + 4;
|
||||
|
||||
prph_len += sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_prph) +
|
||||
num_bytes_in_chunk;
|
||||
}
|
||||
|
||||
if (mvm->cfg->mq_rx_supported) {
|
||||
for (i = 0; i <
|
||||
ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) {
|
||||
/* The range includes both boundaries */
|
||||
int num_bytes_in_chunk =
|
||||
iwl_prph_dump_addr_9000[i].end -
|
||||
iwl_prph_dump_addr_9000[i].start + 4;
|
||||
|
||||
prph_len += sizeof(*dump_data) +
|
||||
sizeof(struct iwl_fw_error_dump_prph) +
|
||||
num_bytes_in_chunk;
|
||||
}
|
||||
}
|
||||
|
||||
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
|
||||
radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
|
||||
}
|
||||
|
@ -769,8 +797,16 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
|||
}
|
||||
}
|
||||
|
||||
if (prph_len)
|
||||
iwl_dump_prph(mvm->trans, &dump_data);
|
||||
if (prph_len) {
|
||||
iwl_dump_prph(mvm->trans, &dump_data,
|
||||
iwl_prph_dump_addr_comm,
|
||||
ARRAY_SIZE(iwl_prph_dump_addr_comm));
|
||||
|
||||
if (mvm->cfg->mq_rx_supported)
|
||||
iwl_dump_prph(mvm->trans, &dump_data,
|
||||
iwl_prph_dump_addr_9000,
|
||||
ARRAY_SIZE(iwl_prph_dump_addr_9000));
|
||||
}
|
||||
|
||||
dump_trans_data:
|
||||
fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans,
|
||||
|
|
|
@ -535,7 +535,7 @@ static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait,
|
|||
return true;
|
||||
}
|
||||
|
||||
WARN_ON(iwl_phy_db_set_section(phy_db, pkt, GFP_ATOMIC));
|
||||
WARN_ON(iwl_phy_db_set_section(phy_db, pkt));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -501,9 +501,11 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_TX_FIFO_VO, 0, wdg_timeout);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_TX_FIFO_VO, 0,
|
||||
wdg_timeout);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, vif->cab_queue,
|
||||
|
@ -533,13 +535,21 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_OFFCHANNEL_QUEUE, IWL_MAX_TID_COUNT,
|
||||
0);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue,
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_disable_txq(mvm,
|
||||
IWL_MVM_DQA_AP_PROBE_RESP_QUEUE,
|
||||
vif->hw_queue[0], IWL_MAX_TID_COUNT,
|
||||
0);
|
||||
/* fall through */
|
||||
default:
|
||||
/*
|
||||
|
|
|
@ -229,7 +229,11 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
|
|||
|
||||
IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
|
||||
spin_lock_bh(&mvm->refs_lock);
|
||||
WARN_ON(!mvm->refs[ref_type]--);
|
||||
if (WARN_ON(!mvm->refs[ref_type])) {
|
||||
spin_unlock_bh(&mvm->refs_lock);
|
||||
return;
|
||||
}
|
||||
mvm->refs[ref_type]--;
|
||||
spin_unlock_bh(&mvm->refs_lock);
|
||||
iwl_trans_unref(mvm->trans);
|
||||
}
|
||||
|
@ -439,11 +443,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
|
||||
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
|
||||
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
|
||||
if (iwl_mvm_has_new_rx_api(mvm))
|
||||
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
|
||||
|
||||
if (mvm->trans->num_rx_queues > 1)
|
||||
ieee80211_hw_set(hw, USES_RSS);
|
||||
|
||||
if (mvm->trans->max_skb_frags)
|
||||
hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
|
||||
|
||||
hw->queues = mvm->first_agg_queue;
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
hw->queues = mvm->first_agg_queue;
|
||||
else
|
||||
hw->queues = IEEE80211_MAX_QUEUES;
|
||||
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
|
||||
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
|
||||
|
@ -848,6 +860,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
u16 *ssn = ¶ms->ssn;
|
||||
u8 buf_size = params->buf_size;
|
||||
bool amsdu = params->amsdu;
|
||||
u16 timeout = params->timeout;
|
||||
|
||||
IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
|
||||
sta->addr, tid, action);
|
||||
|
@ -888,10 +901,12 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size);
|
||||
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size,
|
||||
timeout);
|
||||
break;
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size);
|
||||
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size,
|
||||
timeout);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
if (!iwl_enable_tx_ampdu(mvm->cfg)) {
|
||||
|
@ -4037,6 +4052,55 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_internal_rxq_notif *notif,
|
||||
u32 size)
|
||||
{
|
||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq);
|
||||
u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (!iwl_mvm_has_new_rx_api(mvm))
|
||||
return;
|
||||
|
||||
notif->cookie = mvm->queue_sync_cookie;
|
||||
|
||||
if (notif->sync)
|
||||
atomic_set(&mvm->queue_sync_counter,
|
||||
mvm->trans->num_rx_queues);
|
||||
|
||||
ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif, size);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (notif->sync)
|
||||
ret = wait_event_timeout(notif_waitq,
|
||||
atomic_read(&mvm->queue_sync_counter) == 0,
|
||||
HZ);
|
||||
WARN_ON_ONCE(!ret);
|
||||
|
||||
out:
|
||||
atomic_set(&mvm->queue_sync_counter, 0);
|
||||
mvm->queue_sync_cookie++;
|
||||
}
|
||||
|
||||
static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_internal_rxq_notif data = {
|
||||
.type = IWL_MVM_RXQ_EMPTY,
|
||||
.sync = 1,
|
||||
};
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_sync_rx_queues_internal(mvm, &data, sizeof(data));
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
const struct ieee80211_ops iwl_mvm_hw_ops = {
|
||||
.tx = iwl_mvm_mac_tx,
|
||||
.ampdu_action = iwl_mvm_mac_ampdu_action,
|
||||
|
@ -4093,6 +4157,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
|
|||
|
||||
.event_callback = iwl_mvm_mac_event_callback,
|
||||
|
||||
.sync_rx_queues = iwl_mvm_sync_rx_queues,
|
||||
|
||||
CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -301,6 +301,8 @@ enum iwl_mvm_ref_type {
|
|||
IWL_MVM_REF_PROTECT_CSA,
|
||||
IWL_MVM_REF_FW_DBG_COLLECT,
|
||||
IWL_MVM_REF_INIT_UCODE,
|
||||
IWL_MVM_REF_SENDING_CMD,
|
||||
IWL_MVM_REF_RX,
|
||||
|
||||
/* update debugfs.c when changing this */
|
||||
|
||||
|
@ -613,6 +615,84 @@ struct iwl_mvm_shared_mem_cfg {
|
|||
u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_reorder_buffer - per ra/tid/queue reorder buffer
|
||||
* @head_sn: reorder window head sn
|
||||
* @num_stored: number of mpdus stored in the buffer
|
||||
* @buf_size: the reorder buffer size as set by the last addba request
|
||||
* @sta_id: sta id of this reorder buffer
|
||||
* @queue: queue of this reorder buffer
|
||||
* @last_amsdu: track last ASMDU SN for duplication detection
|
||||
* @last_sub_index: track ASMDU sub frame index for duplication detection
|
||||
* @entries: list of skbs stored
|
||||
* @reorder_time: time the packet was stored in the reorder buffer
|
||||
* @reorder_timer: timer for frames are in the reorder buffer. For AMSDU
|
||||
* it is the time of last received sub-frame
|
||||
* @removed: prevent timer re-arming
|
||||
* @lock: protect reorder buffer internal state
|
||||
* @mvm: mvm pointer, needed for frame timer context
|
||||
*/
|
||||
struct iwl_mvm_reorder_buffer {
|
||||
u16 head_sn;
|
||||
u16 num_stored;
|
||||
u8 buf_size;
|
||||
u8 sta_id;
|
||||
int queue;
|
||||
u16 last_amsdu;
|
||||
u8 last_sub_index;
|
||||
struct sk_buff_head entries[IEEE80211_MAX_AMPDU_BUF];
|
||||
unsigned long reorder_time[IEEE80211_MAX_AMPDU_BUF];
|
||||
struct timer_list reorder_timer;
|
||||
bool removed;
|
||||
spinlock_t lock;
|
||||
struct iwl_mvm *mvm;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_baid_data - BA session data
|
||||
* @sta_id: station id
|
||||
* @tid: tid of the session
|
||||
* @baid baid of the session
|
||||
* @timeout: the timeout set in the addba request
|
||||
* @last_rx: last rx jiffies, updated only if timeout passed from last update
|
||||
* @session_timer: timer to check if BA session expired, runs at 2 * timeout
|
||||
* @mvm: mvm pointer, needed for timer context
|
||||
* @reorder_buf: reorder buffer, allocated per queue
|
||||
*/
|
||||
struct iwl_mvm_baid_data {
|
||||
struct rcu_head rcu_head;
|
||||
u8 sta_id;
|
||||
u8 tid;
|
||||
u8 baid;
|
||||
u16 timeout;
|
||||
unsigned long last_rx;
|
||||
struct timer_list session_timer;
|
||||
struct iwl_mvm *mvm;
|
||||
struct iwl_mvm_reorder_buffer reorder_buf[];
|
||||
};
|
||||
|
||||
/*
|
||||
* enum iwl_mvm_queue_status - queue status
|
||||
* @IWL_MVM_QUEUE_FREE: the queue is not allocated nor reserved
|
||||
* Basically, this means that this queue can be used for any purpose
|
||||
* @IWL_MVM_QUEUE_RESERVED: queue is reserved but not yet in use
|
||||
* This is the state of a queue that has been dedicated for some RATID
|
||||
* (agg'd or not), but that hasn't yet gone through the actual enablement
|
||||
* of iwl_mvm_enable_txq(), and therefore no traffic can go through it yet.
|
||||
* Note that in this state there is no requirement to already know what TID
|
||||
* should be used with this queue, it is just marked as a queue that will
|
||||
* be used, and shouldn't be allocated to anyone else.
|
||||
* @IWL_MVM_QUEUE_READY: queue is ready to be used
|
||||
* This is the state of a queue that has been fully configured (including
|
||||
* SCD pointers, etc), has a specific RA/TID assigned to it, and can be
|
||||
* used to send traffic.
|
||||
*/
|
||||
enum iwl_mvm_queue_status {
|
||||
IWL_MVM_QUEUE_FREE,
|
||||
IWL_MVM_QUEUE_RESERVED,
|
||||
IWL_MVM_QUEUE_READY,
|
||||
};
|
||||
|
||||
struct iwl_mvm {
|
||||
/* for logger access */
|
||||
struct device *dev;
|
||||
|
@ -633,6 +713,8 @@ struct iwl_mvm {
|
|||
|
||||
unsigned long status;
|
||||
|
||||
u32 queue_sync_cookie;
|
||||
atomic_t queue_sync_counter;
|
||||
/*
|
||||
* for beacon filtering -
|
||||
* currently only one interface can be supported
|
||||
|
@ -666,13 +748,8 @@ struct iwl_mvm {
|
|||
u32 hw_queue_to_mac80211;
|
||||
u8 hw_queue_refcount;
|
||||
u8 ra_sta_id; /* The RA this queue is mapped to, if exists */
|
||||
/*
|
||||
* This is to mark that queue is reserved for a STA but not yet
|
||||
* allocated. This is needed to make sure we have at least one
|
||||
* available queue to use when adding a new STA
|
||||
*/
|
||||
bool setup_reserved;
|
||||
u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
|
||||
enum iwl_mvm_queue_status status;
|
||||
} queue_info[IWL_MAX_HW_QUEUES];
|
||||
spinlock_t queue_info_lock; /* For syncing queue mgmt operations */
|
||||
struct work_struct add_stream_wk; /* To add streams to queues */
|
||||
|
@ -920,6 +997,10 @@ struct iwl_mvm {
|
|||
u32 ciphers[6];
|
||||
struct iwl_mvm_tof_data tof_data;
|
||||
|
||||
struct ieee80211_vif *nan_vif;
|
||||
#define IWL_MAX_BAID 32
|
||||
struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID];
|
||||
|
||||
/*
|
||||
* Drop beacons from other APs in AP mode when there are no connected
|
||||
* clients.
|
||||
|
@ -1065,7 +1146,8 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)
|
|||
static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CSUM_SUPPORT);
|
||||
IWL_UCODE_TLV_CAPA_CSUM_SUPPORT) &&
|
||||
!IWL_MVM_HW_CSUM_DISABLE;
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
|
||||
|
@ -1242,7 +1324,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
|
||||
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb, int queue);
|
||||
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
|
||||
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb, int queue);
|
||||
int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
|
||||
const u8 *data, u32 count);
|
||||
|
@ -1566,6 +1648,10 @@ static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
|
|||
void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq);
|
||||
void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq);
|
||||
|
||||
/* Re-configure the SCD for a queue that has already been configured */
|
||||
int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
|
||||
int tid, int frame_limit, u16 ssn);
|
||||
|
||||
/* Thermal management and CT-kill */
|
||||
void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
|
||||
void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp);
|
||||
|
@ -1628,6 +1714,10 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,
|
|||
void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
|
||||
void iwl_mvm_tdls_ch_switch_work(struct work_struct *work);
|
||||
|
||||
void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_internal_rxq_notif *notif,
|
||||
u32 size);
|
||||
void iwl_mvm_reorder_timer_expired(unsigned long data);
|
||||
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
|
||||
|
||||
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
|
||||
|
|
|
@ -554,8 +554,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0;
|
||||
|
||||
mvm->aux_queue = 15;
|
||||
mvm->first_agg_queue = 16;
|
||||
mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1;
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
mvm->first_agg_queue = 16;
|
||||
mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1;
|
||||
} else {
|
||||
mvm->first_agg_queue = IWL_MVM_DQA_MIN_DATA_QUEUE;
|
||||
mvm->last_agg_queue = IWL_MVM_DQA_MAX_DATA_QUEUE;
|
||||
}
|
||||
if (mvm->cfg->base_params->num_of_queues == 16) {
|
||||
mvm->aux_queue = 11;
|
||||
mvm->first_agg_queue = 12;
|
||||
|
@ -586,6 +591,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
skb_queue_head_init(&mvm->d0i3_tx);
|
||||
init_waitqueue_head(&mvm->d0i3_exit_waitq);
|
||||
|
||||
atomic_set(&mvm->queue_sync_counter, 0);
|
||||
|
||||
SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
|
||||
|
||||
/*
|
||||
|
@ -930,7 +937,7 @@ static void iwl_mvm_rx(struct iwl_op_mode *op_mode,
|
|||
if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
|
||||
iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
|
||||
else if (pkt->hdr.cmd == FRAME_RELEASE)
|
||||
iwl_mvm_rx_frame_release(mvm, rxb, 0);
|
||||
iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
|
||||
else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
|
||||
iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
|
||||
else
|
||||
|
@ -1208,7 +1215,6 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm,
|
|||
struct iwl_d0i3_iter_data *iter_data)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct ieee80211_sta *ap_sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
u32 available_tids = 0;
|
||||
u8 tid;
|
||||
|
@ -1217,11 +1223,10 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm,
|
|||
mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
|
||||
return false;
|
||||
|
||||
ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id]);
|
||||
if (IS_ERR_OR_NULL(ap_sta))
|
||||
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id);
|
||||
if (!mvmsta)
|
||||
return false;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(ap_sta);
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
|
||||
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
|
||||
|
@ -1632,7 +1637,7 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
|
|||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
|
||||
if (unlikely(pkt->hdr.cmd == FRAME_RELEASE))
|
||||
iwl_mvm_rx_frame_release(mvm, rxb, queue);
|
||||
iwl_mvm_rx_frame_release(mvm, napi, rxb, queue);
|
||||
else if (unlikely(pkt->hdr.cmd == RX_QUEUES_NOTIFICATION &&
|
||||
pkt->hdr.group_id == DATA_PATH_GROUP))
|
||||
iwl_mvm_rx_queue_notif(mvm, rxb, queue);
|
||||
|
|
|
@ -97,6 +97,7 @@ void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
* Adds the rxb to a new skb and give it to mac80211
|
||||
*/
|
||||
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct napi_struct *napi,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_hdr *hdr, u16 len,
|
||||
|
@ -131,7 +132,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
|
|||
fraglen, rxb->truesize);
|
||||
}
|
||||
|
||||
ieee80211_rx_napi(mvm->hw, NULL, skb, napi);
|
||||
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -271,6 +272,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
u32 rate_n_flags;
|
||||
u32 rx_pkt_status;
|
||||
u8 crypt_len = 0;
|
||||
bool take_ref;
|
||||
|
||||
phy_info = &mvm->last_phy_info;
|
||||
rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
|
||||
|
@ -453,8 +455,26 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED))
|
||||
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
|
||||
|
||||
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status,
|
||||
crypt_len, rxb);
|
||||
if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control)))
|
||||
rx_status->boottime_ns = ktime_get_boot_ns();
|
||||
|
||||
/* Take a reference briefly to kick off a d0i3 entry delay so
|
||||
* we can handle bursts of RX packets without toggling the
|
||||
* state too often. But don't do this for beacons if we are
|
||||
* going to idle because the beacon filtering changes we make
|
||||
* cause the firmware to send us collateral beacons. */
|
||||
take_ref = !(test_bit(STATUS_TRANS_GOING_IDLE, &mvm->trans->status) &&
|
||||
ieee80211_is_beacon(hdr->frame_control));
|
||||
|
||||
if (take_ref)
|
||||
iwl_mvm_ref(mvm, IWL_MVM_REF_RX);
|
||||
|
||||
iwl_mvm_pass_packet_to_mac80211(mvm, sta, napi, skb, hdr, len,
|
||||
ampdu_status, crypt_len, rxb);
|
||||
|
||||
if (take_ref)
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_RX);
|
||||
}
|
||||
|
||||
static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm,
|
||||
|
|
|
@ -210,7 +210,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
|
|||
if (iwl_mvm_check_pn(mvm, skb, queue, sta))
|
||||
kfree_skb(skb);
|
||||
else
|
||||
ieee80211_rx_napi(mvm->hw, NULL, skb, napi);
|
||||
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
|
||||
}
|
||||
|
||||
static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
|
||||
|
@ -395,6 +395,150 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if sn2 - buffer_size < sn1 < sn2.
|
||||
* To be used only in order to compare reorder buffer head with NSSN.
|
||||
* We fully trust NSSN unless it is behind us due to reorder timeout.
|
||||
* Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN.
|
||||
*/
|
||||
static bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size)
|
||||
{
|
||||
return ieee80211_sn_less(sn1, sn2) &&
|
||||
!ieee80211_sn_less(sn1, sn2 - buffer_size);
|
||||
}
|
||||
|
||||
#define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10)
|
||||
|
||||
static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_mvm_reorder_buffer *reorder_buf,
|
||||
u16 nssn)
|
||||
{
|
||||
u16 ssn = reorder_buf->head_sn;
|
||||
|
||||
lockdep_assert_held(&reorder_buf->lock);
|
||||
|
||||
/* ignore nssn smaller than head sn - this can happen due to timeout */
|
||||
if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
|
||||
return;
|
||||
|
||||
while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) {
|
||||
int index = ssn % reorder_buf->buf_size;
|
||||
struct sk_buff_head *skb_list = &reorder_buf->entries[index];
|
||||
struct sk_buff *skb;
|
||||
|
||||
ssn = ieee80211_sn_inc(ssn);
|
||||
|
||||
/* holes are valid since nssn indicates frames were received. */
|
||||
if (skb_queue_empty(skb_list) || !skb_peek_tail(skb_list))
|
||||
continue;
|
||||
/* Empty the list. Will have more than one frame for A-MSDU */
|
||||
while ((skb = __skb_dequeue(skb_list))) {
|
||||
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
|
||||
reorder_buf->queue,
|
||||
sta);
|
||||
reorder_buf->num_stored--;
|
||||
}
|
||||
}
|
||||
reorder_buf->head_sn = nssn;
|
||||
|
||||
if (reorder_buf->num_stored && !reorder_buf->removed) {
|
||||
u16 index = reorder_buf->head_sn % reorder_buf->buf_size;
|
||||
|
||||
while (!skb_peek_tail(&reorder_buf->entries[index]))
|
||||
index = (index + 1) % reorder_buf->buf_size;
|
||||
/* modify timer to match next frame's expiration time */
|
||||
mod_timer(&reorder_buf->reorder_timer,
|
||||
reorder_buf->reorder_time[index] + 1 +
|
||||
RX_REORDER_BUF_TIMEOUT_MQ);
|
||||
} else {
|
||||
del_timer(&reorder_buf->reorder_timer);
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_mvm_reorder_timer_expired(unsigned long data)
|
||||
{
|
||||
struct iwl_mvm_reorder_buffer *buf = (void *)data;
|
||||
int i;
|
||||
u16 sn = 0, index = 0;
|
||||
bool expired = false;
|
||||
|
||||
spin_lock_bh(&buf->lock);
|
||||
|
||||
if (!buf->num_stored || buf->removed) {
|
||||
spin_unlock_bh(&buf->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < buf->buf_size ; i++) {
|
||||
index = (buf->head_sn + i) % buf->buf_size;
|
||||
|
||||
if (!skb_peek_tail(&buf->entries[index]))
|
||||
continue;
|
||||
if (!time_after(jiffies, buf->reorder_time[index] +
|
||||
RX_REORDER_BUF_TIMEOUT_MQ))
|
||||
break;
|
||||
expired = true;
|
||||
sn = ieee80211_sn_add(buf->head_sn, i + 1);
|
||||
}
|
||||
|
||||
if (expired) {
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[buf->sta_id]);
|
||||
/* SN is set to the last expired frame + 1 */
|
||||
iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn);
|
||||
rcu_read_unlock();
|
||||
} else if (buf->num_stored) {
|
||||
/*
|
||||
* If no frame expired and there are stored frames, index is now
|
||||
* pointing to the first unexpired frame - modify timer
|
||||
* accordingly to this frame.
|
||||
*/
|
||||
mod_timer(&buf->reorder_timer,
|
||||
buf->reorder_time[index] +
|
||||
1 + RX_REORDER_BUF_TIMEOUT_MQ);
|
||||
}
|
||||
spin_unlock_bh(&buf->lock);
|
||||
}
|
||||
|
||||
static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue,
|
||||
struct iwl_mvm_delba_data *data)
|
||||
{
|
||||
struct iwl_mvm_baid_data *ba_data;
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_reorder_buffer *reorder_buf;
|
||||
u8 baid = data->baid;
|
||||
|
||||
if (WARN_ON_ONCE(baid >= IWL_RX_REORDER_DATA_INVALID_BAID))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ba_data = rcu_dereference(mvm->baid_map[baid]);
|
||||
if (WARN_ON_ONCE(!ba_data))
|
||||
goto out;
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]);
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
|
||||
goto out;
|
||||
|
||||
reorder_buf = &ba_data->reorder_buf[queue];
|
||||
|
||||
/* release all frames that are in the reorder buffer to the stack */
|
||||
spin_lock_bh(&reorder_buf->lock);
|
||||
iwl_mvm_release_frames(mvm, sta, NULL, reorder_buf,
|
||||
ieee80211_sn_add(reorder_buf->head_sn,
|
||||
reorder_buf->buf_size));
|
||||
spin_unlock_bh(&reorder_buf->lock);
|
||||
del_timer_sync(&reorder_buf->reorder_timer);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
||||
int queue)
|
||||
{
|
||||
|
@ -405,15 +549,182 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
|||
notif = (void *)pkt->data;
|
||||
internal_notif = (void *)notif->payload;
|
||||
|
||||
if (internal_notif->sync) {
|
||||
if (mvm->queue_sync_cookie != internal_notif->cookie) {
|
||||
WARN_ONCE(1,
|
||||
"Received expired RX queue sync message\n");
|
||||
return;
|
||||
}
|
||||
atomic_dec(&mvm->queue_sync_counter);
|
||||
}
|
||||
|
||||
switch (internal_notif->type) {
|
||||
case IWL_MVM_RXQ_EMPTY:
|
||||
break;
|
||||
case IWL_MVM_RXQ_NOTIF_DEL_BA:
|
||||
/* TODO */
|
||||
iwl_mvm_del_ba(mvm, queue, (void *)internal_notif->data);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid identifier %d", internal_notif->type);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the MPDU was buffered\dropped, false if it should be passed
|
||||
* to upper layer.
|
||||
*/
|
||||
static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
||||
struct napi_struct *napi,
|
||||
int queue,
|
||||
struct ieee80211_sta *sta,
|
||||
struct sk_buff *skb,
|
||||
struct iwl_rx_mpdu_desc *desc)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct iwl_mvm_baid_data *baid_data;
|
||||
struct iwl_mvm_reorder_buffer *buffer;
|
||||
struct sk_buff *tail;
|
||||
u32 reorder = le32_to_cpu(desc->reorder_data);
|
||||
bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
|
||||
u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
u8 sub_frame_idx = desc->amsdu_info &
|
||||
IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
|
||||
int index;
|
||||
u16 nssn, sn;
|
||||
u8 baid;
|
||||
|
||||
baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >>
|
||||
IWL_RX_MPDU_REORDER_BAID_SHIFT;
|
||||
|
||||
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
|
||||
return false;
|
||||
|
||||
/* no sta yet */
|
||||
if (WARN_ON(IS_ERR_OR_NULL(sta)))
|
||||
return false;
|
||||
|
||||
/* not a data packet */
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
is_multicast_ether_addr(hdr->addr1))
|
||||
return false;
|
||||
|
||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
||||
return false;
|
||||
|
||||
baid_data = rcu_dereference(mvm->baid_map[baid]);
|
||||
if (WARN(!baid_data,
|
||||
"Received baid %d, but no data exists for this BAID\n", baid))
|
||||
return false;
|
||||
if (WARN(tid != baid_data->tid || mvm_sta->sta_id != baid_data->sta_id,
|
||||
"baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n",
|
||||
baid, baid_data->sta_id, baid_data->tid, mvm_sta->sta_id,
|
||||
tid))
|
||||
return false;
|
||||
|
||||
nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK;
|
||||
sn = (reorder & IWL_RX_MPDU_REORDER_SN_MASK) >>
|
||||
IWL_RX_MPDU_REORDER_SN_SHIFT;
|
||||
|
||||
buffer = &baid_data->reorder_buf[queue];
|
||||
|
||||
spin_lock_bh(&buffer->lock);
|
||||
|
||||
/*
|
||||
* If there was a significant jump in the nssn - adjust.
|
||||
* If the SN is smaller than the NSSN it might need to first go into
|
||||
* the reorder buffer, in which case we just release up to it and the
|
||||
* rest of the function will take of storing it and releasing up to the
|
||||
* nssn
|
||||
*/
|
||||
if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size,
|
||||
buffer->buf_size)) {
|
||||
u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;
|
||||
|
||||
iwl_mvm_release_frames(mvm, sta, napi, buffer, min_sn);
|
||||
}
|
||||
|
||||
/* drop any oudated packets */
|
||||
if (ieee80211_sn_less(sn, buffer->head_sn))
|
||||
goto drop;
|
||||
|
||||
/* release immediately if allowed by nssn and no stored frames */
|
||||
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
|
||||
if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
|
||||
buffer->buf_size))
|
||||
buffer->head_sn = nssn;
|
||||
/* No need to update AMSDU last SN - we are moving the head */
|
||||
spin_unlock_bh(&buffer->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
index = sn % buffer->buf_size;
|
||||
|
||||
/*
|
||||
* Check if we already stored this frame
|
||||
* As AMSDU is either received or not as whole, logic is simple:
|
||||
* If we have frames in that position in the buffer and the last frame
|
||||
* originated from AMSDU had a different SN then it is a retransmission.
|
||||
* If it is the same SN then if the subframe index is incrementing it
|
||||
* is the same AMSDU - otherwise it is a retransmission.
|
||||
*/
|
||||
tail = skb_peek_tail(&buffer->entries[index]);
|
||||
if (tail && !amsdu)
|
||||
goto drop;
|
||||
else if (tail && (sn != buffer->last_amsdu ||
|
||||
buffer->last_sub_index >= sub_frame_idx))
|
||||
goto drop;
|
||||
|
||||
/* put in reorder buffer */
|
||||
__skb_queue_tail(&buffer->entries[index], skb);
|
||||
buffer->num_stored++;
|
||||
buffer->reorder_time[index] = jiffies;
|
||||
|
||||
if (amsdu) {
|
||||
buffer->last_amsdu = sn;
|
||||
buffer->last_sub_index = sub_frame_idx;
|
||||
}
|
||||
|
||||
iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
|
||||
spin_unlock_bh(&buffer->lock);
|
||||
return true;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
spin_unlock_bh(&buffer->lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, u8 baid)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
unsigned long timeout;
|
||||
struct iwl_mvm_baid_data *data;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
data = rcu_dereference(mvm->baid_map[baid]);
|
||||
if (WARN_ON(!data))
|
||||
goto out;
|
||||
|
||||
if (!data->timeout)
|
||||
goto out;
|
||||
|
||||
timeout = data->timeout;
|
||||
/*
|
||||
* Do not update last rx all the time to avoid cache bouncing
|
||||
* between the rx queues.
|
||||
* Update it every timeout. Worst case is the session will
|
||||
* expire after ~ 2 * timeout, which doesn't matter that much.
|
||||
*/
|
||||
if (time_before(data->last_rx + TU_TO_JIFFIES(timeout), now))
|
||||
/* Update is atomic */
|
||||
data->last_rx = now;
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb, int queue)
|
||||
{
|
||||
|
@ -484,6 +795,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
|
||||
if (sta) {
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
|
||||
IWL_RX_MPDU_REORDER_BAID_MASK) >>
|
||||
IWL_RX_MPDU_REORDER_BAID_SHIFT);
|
||||
|
||||
/*
|
||||
* We have tx blocked stations (with CS bit). If we heard
|
||||
|
@ -536,6 +850,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
|
||||
*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
|
||||
}
|
||||
if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
|
||||
iwl_mvm_agg_rx_received(mvm, baid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -593,12 +909,42 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
/* TODO: PHY info - gscan */
|
||||
|
||||
iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
|
||||
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
|
||||
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
|
||||
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
|
||||
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb, int queue)
|
||||
{
|
||||
/* TODO */
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_frame_release *release = (void *)pkt->data;
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_reorder_buffer *reorder_buf;
|
||||
struct iwl_mvm_baid_data *ba_data;
|
||||
|
||||
int baid = release->baid;
|
||||
|
||||
if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ba_data = rcu_dereference(mvm->baid_map[baid]);
|
||||
if (WARN_ON_ONCE(!ba_data))
|
||||
goto out;
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]);
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
|
||||
goto out;
|
||||
|
||||
reorder_buf = &ba_data->reorder_buf[queue];
|
||||
|
||||
spin_lock_bh(&reorder_buf->lock);
|
||||
iwl_mvm_release_frames(mvm, sta, napi, reorder_buf,
|
||||
le16_to_cpu(release->nssn));
|
||||
spin_unlock_bh(&reorder_buf->lock);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -223,6 +223,39 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_agg_session_expired(unsigned long data)
|
||||
{
|
||||
struct iwl_mvm_baid_data __rcu **rcu_ptr = (void *)data;
|
||||
struct iwl_mvm_baid_data *ba_data;
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvm_sta;
|
||||
unsigned long timeout;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ba_data = rcu_dereference(*rcu_ptr);
|
||||
|
||||
if (WARN_ON(!ba_data))
|
||||
goto unlock;
|
||||
|
||||
if (!ba_data->timeout)
|
||||
goto unlock;
|
||||
|
||||
timeout = ba_data->last_rx + TU_TO_JIFFIES(ba_data->timeout * 2);
|
||||
if (time_is_after_jiffies(timeout)) {
|
||||
mod_timer(&ba_data->session_timer, timeout);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Timer expired */
|
||||
sta = rcu_dereference(ba_data->mvm->fw_id_to_mac_id[ba_data->sta_id]);
|
||||
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
ieee80211_stop_rx_ba_session_offl(mvm_sta->vif,
|
||||
sta->addr, ba_data->tid);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
|
@ -293,6 +326,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
u8 mac_queue = mvmsta->vif->hw_queue[ac];
|
||||
int queue = -1;
|
||||
int ssn;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
|
@ -321,8 +355,15 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
if (queue < 0)
|
||||
queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
IWL_MVM_DQA_MAX_DATA_QUEUE);
|
||||
|
||||
/*
|
||||
* Mark TXQ as ready, even though it hasn't been fully configured yet,
|
||||
* to make sure no one else takes it.
|
||||
* This will allow avoiding re-acquiring the lock at the end of the
|
||||
* configuration. On error we'll mark it back as free.
|
||||
*/
|
||||
if (queue >= 0)
|
||||
mvm->queue_info[queue].setup_reserved = false;
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
|
||||
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
|
@ -354,7 +395,16 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
return iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES);
|
||||
ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
iwl_mvm_disable_txq(mvm, queue, mac_queue, tid, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u8 iwl_mvm_tid_to_ac_queue(int tid)
|
||||
|
@ -460,7 +510,8 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
|
|||
/* Make sure we have free resources for this STA */
|
||||
if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls &&
|
||||
!mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].hw_queue_refcount &&
|
||||
!mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].setup_reserved)
|
||||
(mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].status ==
|
||||
IWL_MVM_QUEUE_FREE))
|
||||
queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE;
|
||||
else
|
||||
queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
|
@ -470,7 +521,7 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
|
|||
IWL_ERR(mvm, "No available queues for new station\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
mvm->queue_info[queue].setup_reserved = true;
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED;
|
||||
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
|
@ -1000,6 +1051,33 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
struct iwl_trans_txq_scd_cfg cfg = {
|
||||
.fifo = IWL_MVM_TX_FIFO_VO,
|
||||
.sta_id = mvmvif->bcast_sta.sta_id,
|
||||
.tid = IWL_MAX_TID_COUNT,
|
||||
.aggregate = false,
|
||||
.frame_limit = IWL_FRAME_LIMIT,
|
||||
};
|
||||
unsigned int wdg_timeout =
|
||||
iwl_mvm_get_wd_timeout(mvm, vif, false, false);
|
||||
int queue;
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_AP) &&
|
||||
(mvmvif->bcast_sta.tfd_queue_msk &
|
||||
BIT(IWL_MVM_DQA_AP_PROBE_RESP_QUEUE)))
|
||||
queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
|
||||
else if ((vif->type == NL80211_IFTYPE_P2P_DEVICE) &&
|
||||
(mvmvif->bcast_sta.tfd_queue_msk &
|
||||
BIT(IWL_MVM_DQA_P2P_DEVICE_QUEUE)))
|
||||
queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE;
|
||||
else if (WARN(1, "Missed required TXQ for adding bcast STA\n"))
|
||||
return -EINVAL;
|
||||
|
||||
iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, &cfg,
|
||||
wdg_timeout);
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
baddr = vif->bss_conf.bssid;
|
||||
|
||||
|
@ -1028,20 +1106,28 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
u32 qmask;
|
||||
u32 qmask = 0;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
qmask = iwl_mvm_mac_get_queues_mask(vif);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
qmask = iwl_mvm_mac_get_queues_mask(vif);
|
||||
|
||||
/*
|
||||
* The firmware defines the TFD queue mask to only be relevant
|
||||
* for *unicast* queues, so the multicast (CAB) queue shouldn't
|
||||
* be included.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
/*
|
||||
* The firmware defines the TFD queue mask to only be relevant
|
||||
* for *unicast* queues, so the multicast (CAB) queue shouldn't
|
||||
* be included.
|
||||
*/
|
||||
qmask &= ~BIT(vif->cab_queue);
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
qmask |= BIT(IWL_MVM_DQA_AP_PROBE_RESP_QUEUE);
|
||||
} else if (iwl_mvm_is_dqa_supported(mvm) &&
|
||||
vif->type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
qmask |= BIT(IWL_MVM_DQA_P2P_DEVICE_QUEUE);
|
||||
}
|
||||
|
||||
return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
|
||||
ieee80211_vif_type_p2p(vif));
|
||||
}
|
||||
|
@ -1099,11 +1185,92 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
#define IWL_MAX_RX_BA_SESSIONS 16
|
||||
|
||||
static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm, u8 baid)
|
||||
{
|
||||
struct iwl_mvm_delba_notif notif = {
|
||||
.metadata.type = IWL_MVM_RXQ_NOTIF_DEL_BA,
|
||||
.metadata.sync = 1,
|
||||
.delba.baid = baid,
|
||||
};
|
||||
iwl_mvm_sync_rx_queues_internal(mvm, (void *)¬if, sizeof(notif));
|
||||
};
|
||||
|
||||
static void iwl_mvm_free_reorder(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_baid_data *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
iwl_mvm_sync_rxq_del_ba(mvm, data->baid);
|
||||
|
||||
for (i = 0; i < mvm->trans->num_rx_queues; i++) {
|
||||
int j;
|
||||
struct iwl_mvm_reorder_buffer *reorder_buf =
|
||||
&data->reorder_buf[i];
|
||||
|
||||
spin_lock_bh(&reorder_buf->lock);
|
||||
if (likely(!reorder_buf->num_stored)) {
|
||||
spin_unlock_bh(&reorder_buf->lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This shouldn't happen in regular DELBA since the internal
|
||||
* delBA notification should trigger a release of all frames in
|
||||
* the reorder buffer.
|
||||
*/
|
||||
WARN_ON(1);
|
||||
|
||||
for (j = 0; j < reorder_buf->buf_size; j++)
|
||||
__skb_queue_purge(&reorder_buf->entries[j]);
|
||||
/*
|
||||
* Prevent timer re-arm. This prevents a very far fetched case
|
||||
* where we timed out on the notification. There may be prior
|
||||
* RX frames pending in the RX queue before the notification
|
||||
* that might get processed between now and the actual deletion
|
||||
* and we would re-arm the timer although we are deleting the
|
||||
* reorder buffer.
|
||||
*/
|
||||
reorder_buf->removed = true;
|
||||
spin_unlock_bh(&reorder_buf->lock);
|
||||
del_timer_sync(&reorder_buf->reorder_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm,
|
||||
u32 sta_id,
|
||||
struct iwl_mvm_baid_data *data,
|
||||
u16 ssn, u8 buf_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mvm->trans->num_rx_queues; i++) {
|
||||
struct iwl_mvm_reorder_buffer *reorder_buf =
|
||||
&data->reorder_buf[i];
|
||||
int j;
|
||||
|
||||
reorder_buf->num_stored = 0;
|
||||
reorder_buf->head_sn = ssn;
|
||||
reorder_buf->buf_size = buf_size;
|
||||
/* rx reorder timer */
|
||||
reorder_buf->reorder_timer.function =
|
||||
iwl_mvm_reorder_timer_expired;
|
||||
reorder_buf->reorder_timer.data = (unsigned long)reorder_buf;
|
||||
init_timer(&reorder_buf->reorder_timer);
|
||||
spin_lock_init(&reorder_buf->lock);
|
||||
reorder_buf->mvm = mvm;
|
||||
reorder_buf->queue = i;
|
||||
reorder_buf->sta_id = sta_id;
|
||||
for (j = 0; j < reorder_buf->buf_size; j++)
|
||||
__skb_queue_head_init(&reorder_buf->entries[j]);
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn, bool start, u8 buf_size)
|
||||
int tid, u16 ssn, bool start, u8 buf_size, u16 timeout)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct iwl_mvm_baid_data *baid_data = NULL;
|
||||
int ret;
|
||||
u32 status;
|
||||
|
||||
|
@ -1114,6 +1281,19 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (iwl_mvm_has_new_rx_api(mvm) && start) {
|
||||
/*
|
||||
* Allocate here so if allocation fails we can bail out early
|
||||
* before starting the BA session in the firmware
|
||||
*/
|
||||
baid_data = kzalloc(sizeof(*baid_data) +
|
||||
mvm->trans->num_rx_queues *
|
||||
sizeof(baid_data->reorder_buf[0]),
|
||||
GFP_KERNEL);
|
||||
if (!baid_data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
|
||||
cmd.sta_id = mvm_sta->sta_id;
|
||||
cmd.add_modify = STA_MODE_MODIFY;
|
||||
|
@ -1132,7 +1312,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
iwl_mvm_add_sta_cmd_size(mvm),
|
||||
&cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_free;
|
||||
|
||||
switch (status & IWL_ADD_STA_STATUS_MASK) {
|
||||
case ADD_STA_SUCCESS:
|
||||
|
@ -1150,14 +1330,75 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
if (start)
|
||||
mvm->rx_ba_sessions++;
|
||||
else if (mvm->rx_ba_sessions > 0)
|
||||
/* check that restart flow didn't zero the counter */
|
||||
mvm->rx_ba_sessions--;
|
||||
}
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
if (start) {
|
||||
u8 baid;
|
||||
|
||||
mvm->rx_ba_sessions++;
|
||||
|
||||
if (!iwl_mvm_has_new_rx_api(mvm))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(!(status & IWL_ADD_STA_BAID_VALID_MASK))) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
baid = (u8)((status & IWL_ADD_STA_BAID_MASK) >>
|
||||
IWL_ADD_STA_BAID_SHIFT);
|
||||
baid_data->baid = baid;
|
||||
baid_data->timeout = timeout;
|
||||
baid_data->last_rx = jiffies;
|
||||
init_timer(&baid_data->session_timer);
|
||||
baid_data->session_timer.function =
|
||||
iwl_mvm_rx_agg_session_expired;
|
||||
baid_data->session_timer.data =
|
||||
(unsigned long)&mvm->baid_map[baid];
|
||||
baid_data->mvm = mvm;
|
||||
baid_data->tid = tid;
|
||||
baid_data->sta_id = mvm_sta->sta_id;
|
||||
|
||||
mvm_sta->tid_to_baid[tid] = baid;
|
||||
if (timeout)
|
||||
mod_timer(&baid_data->session_timer,
|
||||
TU_TO_EXP_TIME(timeout * 2));
|
||||
|
||||
iwl_mvm_init_reorder_buffer(mvm, mvm_sta->sta_id,
|
||||
baid_data, ssn, buf_size);
|
||||
/*
|
||||
* protect the BA data with RCU to cover a case where our
|
||||
* internal RX sync mechanism will timeout (not that it's
|
||||
* supposed to happen) and we will free the session data while
|
||||
* RX is being processed in parallel
|
||||
*/
|
||||
WARN_ON(rcu_access_pointer(mvm->baid_map[baid]));
|
||||
rcu_assign_pointer(mvm->baid_map[baid], baid_data);
|
||||
} else if (mvm->rx_ba_sessions > 0) {
|
||||
u8 baid = mvm_sta->tid_to_baid[tid];
|
||||
|
||||
/* check that restart flow didn't zero the counter */
|
||||
mvm->rx_ba_sessions--;
|
||||
if (!iwl_mvm_has_new_rx_api(mvm))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(baid == IWL_RX_REORDER_DATA_INVALID_BAID))
|
||||
return -EINVAL;
|
||||
|
||||
baid_data = rcu_access_pointer(mvm->baid_map[baid]);
|
||||
if (WARN_ON(!baid_data))
|
||||
return -EINVAL;
|
||||
|
||||
/* synchronize all rx queues so we can safely delete */
|
||||
iwl_mvm_free_reorder(mvm, baid_data);
|
||||
del_timer_sync(&baid_data->session_timer);
|
||||
RCU_INIT_POINTER(mvm->baid_map[baid], NULL);
|
||||
kfree_rcu(baid_data, rcu_head);
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
kfree(baid_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1416,9 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
mvm_sta->tfd_queue_msk |= BIT(queue);
|
||||
mvm_sta->tid_disable_agg &= ~BIT(tid);
|
||||
} else {
|
||||
mvm_sta->tfd_queue_msk &= ~BIT(queue);
|
||||
/* In DQA-mode the queue isn't removed on agg termination */
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
mvm_sta->tfd_queue_msk &= ~BIT(queue);
|
||||
mvm_sta->tid_disable_agg |= BIT(tid);
|
||||
}
|
||||
|
||||
|
@ -1258,17 +1501,35 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
|
||||
txq_id = iwl_mvm_find_free_queue(mvm, mvm->first_agg_queue,
|
||||
mvm->last_agg_queue);
|
||||
if (txq_id < 0) {
|
||||
ret = txq_id;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
IWL_ERR(mvm, "Failed to allocate agg queue\n");
|
||||
goto release_locks;
|
||||
/*
|
||||
* Note the possible cases:
|
||||
* 1. In DQA mode with an enabled TXQ - TXQ needs to become agg'ed
|
||||
* 2. Non-DQA mode: the TXQ hasn't yet been enabled, so find a free
|
||||
* one and mark it as reserved
|
||||
* 3. In DQA mode, but no traffic yet on this TID: same treatment as in
|
||||
* non-DQA mode, since the TXQ hasn't yet been allocated
|
||||
*/
|
||||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) ||
|
||||
mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
|
||||
txq_id = iwl_mvm_find_free_queue(mvm, mvm->first_agg_queue,
|
||||
mvm->last_agg_queue);
|
||||
if (txq_id < 0) {
|
||||
ret = txq_id;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
IWL_ERR(mvm, "Failed to allocate agg queue\n");
|
||||
goto release_locks;
|
||||
}
|
||||
|
||||
/* TXQ hasn't yet been enabled, so mark it only as reserved */
|
||||
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED;
|
||||
}
|
||||
mvm->queue_info[txq_id].setup_reserved = true;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"AGG for tid %d will be on queue #%d\n",
|
||||
tid, txq_id);
|
||||
|
||||
tid_data = &mvmsta->tid_data[tid];
|
||||
tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->txq_id = txq_id;
|
||||
|
@ -1303,6 +1564,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
unsigned int wdg_timeout =
|
||||
iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false);
|
||||
int queue, ret;
|
||||
bool alloc_queue = true;
|
||||
u16 ssn;
|
||||
|
||||
struct iwl_trans_txq_scd_cfg cfg = {
|
||||
|
@ -1328,8 +1590,46 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
cfg.fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
|
||||
|
||||
iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[tid_to_mac80211_ac[tid]],
|
||||
ssn, &cfg, wdg_timeout);
|
||||
/* In DQA mode, the existing queue might need to be reconfigured */
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
/* Maybe there is no need to even alloc a queue... */
|
||||
if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY)
|
||||
alloc_queue = false;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/*
|
||||
* Only reconfig the SCD for the queue if the window size has
|
||||
* changed from current (become smaller)
|
||||
*/
|
||||
if (!alloc_queue && buf_size < mvmsta->max_agg_bufsize) {
|
||||
/*
|
||||
* If reconfiguring an existing queue, it first must be
|
||||
* drained
|
||||
*/
|
||||
ret = iwl_trans_wait_tx_queue_empty(mvm->trans,
|
||||
BIT(queue));
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Error draining queue before reconfig\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_reconfig_scd(mvm, queue, cfg.fifo,
|
||||
mvmsta->sta_id, tid,
|
||||
buf_size, ssn);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Error reconfiguring TXQ #%d\n", queue);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_queue)
|
||||
iwl_mvm_enable_txq(mvm, queue,
|
||||
vif->hw_queue[tid_to_mac80211_ac[tid]], ssn,
|
||||
&cfg, wdg_timeout);
|
||||
|
||||
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
|
||||
if (ret)
|
||||
|
@ -1337,7 +1637,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
/* No need to mark as reserved */
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
mvm->queue_info[queue].setup_reserved = false;
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/*
|
||||
|
@ -1384,9 +1684,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
mvmsta->agg_tids &= ~BIT(tid);
|
||||
|
||||
/* No need to mark as reserved anymore */
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
mvm->queue_info[txq_id].setup_reserved = false;
|
||||
/*
|
||||
* The TXQ is marked as reserved only if no traffic came through yet
|
||||
* This means no traffic has been sent on this TID (agg'd or not), so
|
||||
* we no longer have use for the queue. Since it hasn't even been
|
||||
* allocated through iwl_mvm_enable_txq, so we can just mark it back as
|
||||
* free.
|
||||
*/
|
||||
if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED)
|
||||
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
switch (tid_data->state) {
|
||||
|
@ -1412,9 +1719,11 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
|
||||
|
||||
iwl_mvm_disable_txq(mvm, txq_id,
|
||||
vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
|
||||
0);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
int mac_queue = vif->hw_queue[tid_to_mac80211_ac[tid]];
|
||||
|
||||
iwl_mvm_disable_txq(mvm, txq_id, mac_queue, tid, 0);
|
||||
}
|
||||
return 0;
|
||||
case IWL_AGG_STARTING:
|
||||
case IWL_EMPTYING_HW_QUEUE_ADDBA:
|
||||
|
@ -1465,9 +1774,16 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
mvmsta->agg_tids &= ~BIT(tid);
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
/* No need to mark as reserved */
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
mvm->queue_info[txq_id].setup_reserved = false;
|
||||
/*
|
||||
* The TXQ is marked as reserved only if no traffic came through yet
|
||||
* This means no traffic has been sent on this TID (agg'd or not), so
|
||||
* we no longer have use for the queue. Since it hasn't even been
|
||||
* allocated through iwl_mvm_enable_txq, so we can just mark it back as
|
||||
* free.
|
||||
*/
|
||||
if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED)
|
||||
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
if (old_state >= IWL_AGG_ON) {
|
||||
|
@ -1480,9 +1796,12 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
|
||||
|
||||
iwl_mvm_disable_txq(mvm, tid_data->txq_id,
|
||||
vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
|
||||
0);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
int mac_queue = vif->hw_queue[tid_to_mac80211_ac[tid]];
|
||||
|
||||
iwl_mvm_disable_txq(mvm, tid_data->txq_id, mac_queue,
|
||||
tid, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1533,17 +1852,12 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm,
|
|||
mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
|
||||
u8 sta_id = mvmvif->ap_sta_id;
|
||||
|
||||
sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
/*
|
||||
* It is possible that the 'sta' parameter is NULL,
|
||||
* for example when a GTK is removed - the sta_id will then
|
||||
* be the AP ID, and no station was passed by mac80211.
|
||||
*/
|
||||
if (IS_ERR_OR_NULL(sta))
|
||||
return NULL;
|
||||
|
||||
return iwl_mvm_sta_from_mac80211(sta);
|
||||
return iwl_mvm_sta_from_staid_protected(mvm, sta_id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -348,6 +348,15 @@ struct iwl_mvm_key_pn {
|
|||
} ____cacheline_aligned_in_smp q[];
|
||||
};
|
||||
|
||||
struct iwl_mvm_delba_data {
|
||||
u32 baid;
|
||||
} __packed;
|
||||
|
||||
struct iwl_mvm_delba_notif {
|
||||
struct iwl_mvm_internal_rxq_notif metadata;
|
||||
struct iwl_mvm_delba_data delba;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_rxq_dup_data - per station per rx queue data
|
||||
* @last_seq: last sequence per tid for duplicate packet detection
|
||||
|
@ -373,6 +382,7 @@ struct iwl_mvm_rxq_dup_data {
|
|||
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
|
||||
* and from Tx response flow, it needs a spinlock.
|
||||
* @tid_data: per tid data + mgmt. Look at %iwl_mvm_tid_data.
|
||||
* @tid_to_baid: a simple map of TID to baid
|
||||
* @reserved_queue: the queue reserved for this STA for DQA purposes
|
||||
* Every STA has is given one reserved queue to allow it to operate. If no
|
||||
* such queue can be guaranteed, the STA addition will fail.
|
||||
|
@ -406,6 +416,7 @@ struct iwl_mvm_sta {
|
|||
bool next_status_eosp;
|
||||
spinlock_t lock;
|
||||
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT + 1];
|
||||
u8 tid_to_baid[IWL_MAX_TID_COUNT];
|
||||
struct iwl_lq_sta lq_sta;
|
||||
struct ieee80211_vif *vif;
|
||||
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
|
||||
|
@ -487,7 +498,7 @@ void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
|
|||
|
||||
/* AMPDU */
|
||||
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn, bool start, u8 buf_size);
|
||||
int tid, u16 ssn, bool start, u8 buf_size, u16 timeout);
|
||||
int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
|
|
|
@ -359,16 +359,14 @@ static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
|
|||
|
||||
static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
|
||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (IS_ERR_OR_NULL(sta))
|
||||
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i);
|
||||
if (!mvmsta)
|
||||
continue;
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
if (enable == mvmsta->tt_tx_protection)
|
||||
continue;
|
||||
err = iwl_mvm_tx_protection(mvm, mvmsta, enable);
|
||||
|
|
|
@ -475,6 +475,21 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
return dev_cmd;
|
||||
}
|
||||
|
||||
static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
|
||||
struct ieee80211_tx_info *info, __le16 fc)
|
||||
{
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
if (info->control.vif->type == NL80211_IFTYPE_AP &&
|
||||
ieee80211_is_probe_resp(fc))
|
||||
return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
|
||||
else if (ieee80211_is_mgmt(fc) &&
|
||||
info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
return IWL_MVM_DQA_P2P_DEVICE_QUEUE;
|
||||
}
|
||||
|
||||
return info->hw_queue;
|
||||
}
|
||||
|
||||
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
@ -484,6 +499,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
struct iwl_tx_cmd *tx_cmd;
|
||||
u8 sta_id;
|
||||
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
int queue;
|
||||
|
||||
memcpy(&info, skb->cb, sizeof(info));
|
||||
|
||||
|
@ -508,6 +524,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
info.control.vif->type == NL80211_IFTYPE_STATION)
|
||||
IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue;
|
||||
|
||||
queue = info.hw_queue;
|
||||
|
||||
/*
|
||||
* If the interface on which the frame is sent is the P2P_DEVICE
|
||||
* or an AP/GO interface use the broadcast station associated
|
||||
|
@ -523,10 +541,12 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
iwl_mvm_vif_from_mac80211(info.control.vif);
|
||||
|
||||
if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
|
||||
info.control.vif->type == NL80211_IFTYPE_AP)
|
||||
info.control.vif->type == NL80211_IFTYPE_AP) {
|
||||
sta_id = mvmvif->bcast_sta.sta_id;
|
||||
else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
|
||||
is_multicast_ether_addr(hdr->addr1)) {
|
||||
queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,
|
||||
hdr->frame_control);
|
||||
} else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
|
||||
is_multicast_ether_addr(hdr->addr1)) {
|
||||
u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id);
|
||||
|
||||
if (ap_sta_id != IWL_MVM_STATION_COUNT)
|
||||
|
@ -534,7 +554,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info.hw_queue);
|
||||
IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue);
|
||||
|
||||
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id);
|
||||
if (!dev_cmd)
|
||||
|
@ -545,7 +565,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
/* Copy MAC header from skb into command buffer */
|
||||
memcpy(tx_cmd->hdr, hdr, hdrlen);
|
||||
|
||||
if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info.hw_queue)) {
|
||||
if (iwl_trans_tx(mvm->trans, skb, dev_cmd, queue)) {
|
||||
iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
|
||||
return -1;
|
||||
}
|
||||
|
@ -589,9 +609,11 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
|
||||
return -EINVAL;
|
||||
|
||||
dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len);
|
||||
|
||||
if (!sta->max_amsdu_len ||
|
||||
!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
!mvmsta->tlc_amsdu) {
|
||||
(!mvmsta->tlc_amsdu && !dbg_max_amsdu_len)) {
|
||||
num_subframes = 1;
|
||||
pad = 0;
|
||||
goto segment;
|
||||
|
@ -622,7 +644,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
max_amsdu_len = sta->max_amsdu_len;
|
||||
dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len);
|
||||
|
||||
/* the Tx FIFO to which this A-MSDU will be routed */
|
||||
txf = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
|
||||
|
@ -636,7 +657,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
max_amsdu_len = min_t(unsigned int, max_amsdu_len,
|
||||
mvm->shared_mem_cfg.txfifo_size[txf] - 256);
|
||||
|
||||
if (dbg_max_amsdu_len)
|
||||
if (unlikely(dbg_max_amsdu_len))
|
||||
max_amsdu_len = min_t(unsigned int, max_amsdu_len,
|
||||
dbg_max_amsdu_len);
|
||||
|
||||
|
@ -912,7 +933,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
|
||||
spin_unlock(&mvmsta->lock);
|
||||
|
||||
if (txq_id < mvm->first_agg_queue)
|
||||
/* Increase pending frames count if this isn't AMPDU */
|
||||
if (!is_ampdu)
|
||||
atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
|
||||
|
||||
return 0;
|
||||
|
@ -1160,6 +1182,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
u8 skb_freed = 0;
|
||||
u16 next_reclaimed, seq_ctl;
|
||||
bool is_ndp = false;
|
||||
bool txq_agg = false; /* Is this TXQ aggregated */
|
||||
|
||||
__skb_queue_head_init(&skbs);
|
||||
|
||||
|
@ -1290,6 +1313,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
bool send_eosp_ndp = false;
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
txq_agg = (mvmsta->tid_data[tid].state == IWL_AGG_ON);
|
||||
|
||||
if (!is_ndp) {
|
||||
tid_data->next_reclaimed = next_reclaimed;
|
||||
IWL_DEBUG_TX_REPLY(mvm,
|
||||
|
@ -1345,11 +1370,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
* If the txq is not an AMPDU queue, there is no chance we freed
|
||||
* several skbs. Check that out...
|
||||
*/
|
||||
if (txq_id >= mvm->first_agg_queue)
|
||||
if (txq_agg)
|
||||
goto out;
|
||||
|
||||
/* We can't free more than one frame at once on a shared queue */
|
||||
WARN_ON(skb_freed > 1);
|
||||
WARN_ON(!iwl_mvm_is_dqa_supported(mvm) && (skb_freed > 1));
|
||||
|
||||
/* If we have still frames for this STA nothing to do here */
|
||||
if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id]))
|
||||
|
@ -1443,9 +1468,12 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
|
|||
int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
|
||||
int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
|
||||
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
int queue = SEQ_TO_QUEUE(sequence);
|
||||
|
||||
if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < mvm->first_agg_queue))
|
||||
if (WARN_ON_ONCE(queue < mvm->first_agg_queue &&
|
||||
(!iwl_mvm_is_dqa_supported(mvm) ||
|
||||
(queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE))))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
|
||||
|
@ -1455,10 +1483,9 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id);
|
||||
|
||||
if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
if (!WARN_ON_ONCE(!mvmsta)) {
|
||||
mvmsta->tid_data[tid].rate_n_flags =
|
||||
le32_to_cpu(tx_resp->initial_rate);
|
||||
mvmsta->tid_data[tid].tx_time =
|
||||
|
|
|
@ -90,11 +90,17 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
|
|||
* the mutex, this ensures we don't try to send two
|
||||
* (or more) synchronous commands at a time.
|
||||
*/
|
||||
if (!(cmd->flags & CMD_ASYNC))
|
||||
if (!(cmd->flags & CMD_ASYNC)) {
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
if (!(cmd->flags & CMD_SEND_IN_IDLE))
|
||||
iwl_mvm_ref(mvm, IWL_MVM_REF_SENDING_CMD);
|
||||
}
|
||||
|
||||
ret = iwl_trans_send_cmd(mvm->trans, cmd);
|
||||
|
||||
if (!(cmd->flags & (CMD_ASYNC | CMD_SEND_IN_IDLE)))
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SENDING_CMD);
|
||||
|
||||
/*
|
||||
* If the caller wants the SKB, then don't hide any problems, the
|
||||
* caller might access the response buffer which will be NULL if
|
||||
|
@ -581,12 +587,45 @@ int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq)
|
|||
|
||||
for (i = minq; i <= maxq; i++)
|
||||
if (mvm->queue_info[i].hw_queue_refcount == 0 &&
|
||||
!mvm->queue_info[i].setup_reserved)
|
||||
mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE)
|
||||
return i;
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
|
||||
int tid, int frame_limit, u16 ssn)
|
||||
{
|
||||
struct iwl_scd_txq_cfg_cmd cmd = {
|
||||
.scd_queue = queue,
|
||||
.enable = 1,
|
||||
.window = frame_limit,
|
||||
.sta_id = sta_id,
|
||||
.ssn = cpu_to_le16(ssn),
|
||||
.tx_fifo = fifo,
|
||||
.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE ||
|
||||
queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE),
|
||||
.tid = tid,
|
||||
};
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
if (WARN(mvm->queue_info[queue].hw_queue_refcount == 0,
|
||||
"Trying to reconfig unallocated queue %d\n", queue)) {
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
return -ENXIO;
|
||||
}
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Reconfig SCD for TXQ #%d\n", queue);
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd);
|
||||
WARN_ONCE(ret, "Failed to re-configure queue %d on FIFO %d, ret=%d\n",
|
||||
queue, fifo, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
||||
u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
|
||||
unsigned int wdg_timeout)
|
||||
|
@ -682,6 +721,8 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
|||
mvm->queue_info[queue].hw_queue_refcount--;
|
||||
|
||||
cmd.enable = mvm->queue_info[queue].hw_queue_refcount ? 1 : 0;
|
||||
if (!cmd.enable)
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE;
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
|
||||
|
|
|
@ -493,19 +493,20 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x24FD, 0x8130, iwl8265_2ac_cfg)},
|
||||
|
||||
/* 9000 Series */
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9560_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9560_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x2526, 0x1420, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9560_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9560_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9560_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)},
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
{0}
|
||||
|
@ -595,6 +596,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
{
|
||||
const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
|
||||
const struct iwl_cfg *cfg_7265d __maybe_unused = NULL;
|
||||
const struct iwl_cfg *cfg_9260lc __maybe_unused = NULL;
|
||||
struct iwl_trans *iwl_trans;
|
||||
struct iwl_trans_pcie *trans_pcie;
|
||||
int ret;
|
||||
|
@ -622,6 +624,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
cfg = cfg_7265d;
|
||||
iwl_trans->cfg = cfg_7265d;
|
||||
}
|
||||
|
||||
if (iwl_trans->cfg->rf_id) {
|
||||
if (cfg == &iwl9260_2ac_cfg)
|
||||
cfg_9260lc = &iwl9260lc_2ac_cfg;
|
||||
if (cfg_9260lc && iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_LC) {
|
||||
cfg = cfg_9260lc;
|
||||
iwl_trans->cfg = cfg_9260lc;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pci_set_drvdata(pdev, iwl_trans);
|
||||
|
|
|
@ -481,9 +481,6 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
|
|||
struct sk_buff_head *skbs);
|
||||
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
|
||||
|
||||
void iwl_trans_pcie_ref(struct iwl_trans *trans);
|
||||
void iwl_trans_pcie_unref(struct iwl_trans *trans);
|
||||
|
||||
static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
|
||||
{
|
||||
struct iwl_tfd_tb *tb = &tfd->tbs[idx];
|
||||
|
|
|
@ -161,10 +161,11 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr)
|
|||
return cpu_to_le32((u32)(dma_addr >> 8));
|
||||
}
|
||||
|
||||
static void iwl_pcie_write_prph_64(struct iwl_trans *trans, u64 ofs, u64 val)
|
||||
static void iwl_pcie_write_prph_64_no_grab(struct iwl_trans *trans, u64 ofs,
|
||||
u64 val)
|
||||
{
|
||||
iwl_write_prph(trans, ofs, val & 0xffffffff);
|
||||
iwl_write_prph(trans, ofs + 4, val >> 32);
|
||||
iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff);
|
||||
iwl_write_prph_no_grab(trans, ofs + 4, val >> 32);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -208,8 +209,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
|
|||
|
||||
rxq->write_actual = round_down(rxq->write, 8);
|
||||
if (trans->cfg->mq_rx_supported)
|
||||
iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(rxq->id),
|
||||
rxq->write_actual);
|
||||
iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id),
|
||||
rxq->write_actual);
|
||||
/*
|
||||
* write to FH_RSCSR_CHNL0_WPTR register even in MQ as a W/A to
|
||||
* hardware shadow registers bug - writing to RFH_Q_FRBDCB_WIDX will
|
||||
|
@ -698,6 +699,7 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
|
|||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
u32 rb_size;
|
||||
unsigned long flags;
|
||||
const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
|
||||
|
||||
switch (trans_pcie->rx_buf_size) {
|
||||
|
@ -715,23 +717,26 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
|
|||
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
|
||||
}
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, &flags))
|
||||
return;
|
||||
|
||||
/* Stop Rx DMA */
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
|
||||
iwl_write32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
|
||||
/* reset and flush pointers */
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
|
||||
iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
|
||||
iwl_write32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
|
||||
iwl_write32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
|
||||
iwl_write32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
|
||||
|
||||
/* Reset driver's Rx queue write index */
|
||||
iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
|
||||
iwl_write32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
|
||||
|
||||
/* Tell device where to find RBD circular buffer in DRAM */
|
||||
iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
||||
(u32)(rxq->bd_dma >> 8));
|
||||
iwl_write32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
||||
(u32)(rxq->bd_dma >> 8));
|
||||
|
||||
/* Tell device where in DRAM to update its Rx status */
|
||||
iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
||||
rxq->rb_stts_dma >> 4);
|
||||
iwl_write32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
||||
rxq->rb_stts_dma >> 4);
|
||||
|
||||
/* Enable Rx DMA
|
||||
* FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
|
||||
|
@ -741,13 +746,15 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
|
|||
* RB timeout 0x10
|
||||
* 256 RBDs
|
||||
*/
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
|
||||
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
|
||||
FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
|
||||
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
|
||||
rb_size|
|
||||
(RX_RB_TIMEOUT << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
|
||||
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
|
||||
iwl_write32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
|
||||
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
|
||||
FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
|
||||
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
|
||||
rb_size |
|
||||
(RX_RB_TIMEOUT << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) |
|
||||
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
|
||||
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
|
||||
/* Set interrupt coalescing timer to default (2048 usecs) */
|
||||
iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
|
||||
|
@ -761,6 +768,7 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
|||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
u32 rb_size, enabled = 0;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
switch (trans_pcie->rx_buf_size) {
|
||||
|
@ -778,25 +786,31 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
|||
rb_size = RFH_RXF_DMA_RB_SIZE_4K;
|
||||
}
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, &flags))
|
||||
return;
|
||||
|
||||
/* Stop Rx DMA */
|
||||
iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0);
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG, 0);
|
||||
/* disable free amd used rx queue operation */
|
||||
iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, 0);
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, 0);
|
||||
|
||||
for (i = 0; i < trans->num_rx_queues; i++) {
|
||||
/* Tell device where to find RBD free table in DRAM */
|
||||
iwl_pcie_write_prph_64(trans, RFH_Q_FRBDCB_BA_LSB(i),
|
||||
(u64)(trans_pcie->rxq[i].bd_dma));
|
||||
iwl_pcie_write_prph_64_no_grab(trans,
|
||||
RFH_Q_FRBDCB_BA_LSB(i),
|
||||
trans_pcie->rxq[i].bd_dma);
|
||||
/* Tell device where to find RBD used table in DRAM */
|
||||
iwl_pcie_write_prph_64(trans, RFH_Q_URBDCB_BA_LSB(i),
|
||||
(u64)(trans_pcie->rxq[i].used_bd_dma));
|
||||
iwl_pcie_write_prph_64_no_grab(trans,
|
||||
RFH_Q_URBDCB_BA_LSB(i),
|
||||
trans_pcie->rxq[i].used_bd_dma);
|
||||
/* Tell device where in DRAM to update its Rx status */
|
||||
iwl_pcie_write_prph_64(trans, RFH_Q_URBD_STTS_WPTR_LSB(i),
|
||||
trans_pcie->rxq[i].rb_stts_dma);
|
||||
iwl_pcie_write_prph_64_no_grab(trans,
|
||||
RFH_Q_URBD_STTS_WPTR_LSB(i),
|
||||
trans_pcie->rxq[i].rb_stts_dma);
|
||||
/* Reset device indice tables */
|
||||
iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(i), 0);
|
||||
iwl_write_prph(trans, RFH_Q_FRBDCB_RIDX(i), 0);
|
||||
iwl_write_prph(trans, RFH_Q_URBDCB_WIDX(i), 0);
|
||||
iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_WIDX(i), 0);
|
||||
iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_RIDX(i), 0);
|
||||
iwl_write_prph_no_grab(trans, RFH_Q_URBDCB_WIDX(i), 0);
|
||||
|
||||
enabled |= BIT(i) | BIT(i + 16);
|
||||
}
|
||||
|
@ -812,23 +826,26 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
|||
* Drop frames that exceed RB size
|
||||
* 512 RBDs
|
||||
*/
|
||||
iwl_write_prph(trans, RFH_RXF_DMA_CFG,
|
||||
RFH_DMA_EN_ENABLE_VAL |
|
||||
rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK |
|
||||
RFH_RXF_DMA_MIN_RB_4_8 |
|
||||
RFH_RXF_DMA_DROP_TOO_LARGE_MASK |
|
||||
RFH_RXF_DMA_RBDCB_SIZE_512);
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG,
|
||||
RFH_DMA_EN_ENABLE_VAL |
|
||||
rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK |
|
||||
RFH_RXF_DMA_MIN_RB_4_8 |
|
||||
RFH_RXF_DMA_DROP_TOO_LARGE_MASK |
|
||||
RFH_RXF_DMA_RBDCB_SIZE_512);
|
||||
|
||||
/*
|
||||
* Activate DMA snooping.
|
||||
* Set RX DMA chunk size to 64B
|
||||
* Default queue is 0
|
||||
*/
|
||||
iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
|
||||
(DEFAULT_RXQ_NUM << RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
|
||||
RFH_GEN_CFG_SERVICE_DMA_SNOOP);
|
||||
iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
|
||||
(DEFAULT_RXQ_NUM <<
|
||||
RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
|
||||
RFH_GEN_CFG_SERVICE_DMA_SNOOP);
|
||||
/* Enable the relevant rx queues */
|
||||
iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, enabled);
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled);
|
||||
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
|
||||
/* Set interrupt coalescing timer to default (2048 usecs) */
|
||||
iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
|
||||
|
@ -1298,7 +1315,7 @@ static inline void iwl_pcie_clear_irq(struct iwl_trans *trans,
|
|||
* write 1 clear (W1C) register, meaning that it's being clear
|
||||
* by writing 1 to the bit.
|
||||
*/
|
||||
iwl_write_direct32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(entry->entry));
|
||||
iwl_write32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(entry->entry));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1817,13 +1834,13 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
|||
lock_map_acquire(&trans->sync_cmd_lockdep_map);
|
||||
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
inta_fh = iwl_read_direct32(trans, CSR_MSIX_FH_INT_CAUSES_AD);
|
||||
inta_hw = iwl_read_direct32(trans, CSR_MSIX_HW_INT_CAUSES_AD);
|
||||
inta_fh = iwl_read32(trans, CSR_MSIX_FH_INT_CAUSES_AD);
|
||||
inta_hw = iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD);
|
||||
/*
|
||||
* Clear causes registers to avoid being handling the same cause.
|
||||
*/
|
||||
iwl_write_direct32(trans, CSR_MSIX_FH_INT_CAUSES_AD, inta_fh);
|
||||
iwl_write_direct32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw);
|
||||
iwl_write32(trans, CSR_MSIX_FH_INT_CAUSES_AD, inta_fh);
|
||||
iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
if (unlikely(!(inta_fh | inta_hw))) {
|
||||
|
|
|
@ -269,9 +269,8 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
|
|||
iwl_pcie_apm_config(trans);
|
||||
|
||||
/* Configure analog phase-lock-loop before activating to D0A */
|
||||
if (trans->cfg->base_params->pll_cfg_val)
|
||||
iwl_set_bit(trans, CSR_ANA_PLL_CFG,
|
||||
trans->cfg->base_params->pll_cfg_val);
|
||||
if (trans->cfg->base_params->pll_cfg)
|
||||
iwl_set_bit(trans, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
|
||||
|
||||
/*
|
||||
* Set "initialization complete" bit to move adapter from
|
||||
|
@ -361,8 +360,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
|
|||
|
||||
/* Reset entire device - do controller reset (results in SHRD_HW_RST) */
|
||||
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
|
||||
|
||||
udelay(10);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
/*
|
||||
* Set "initialization complete" bit to move adapter from
|
||||
|
@ -408,8 +406,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
|
|||
* SHRD_HW_RST). Turn MAC off before proceeding.
|
||||
*/
|
||||
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
|
||||
|
||||
udelay(10);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
/* Enable LP XTAL by indirect access through CSR */
|
||||
apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG);
|
||||
|
@ -506,8 +503,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
|
|||
|
||||
/* Reset the entire device */
|
||||
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
|
||||
|
||||
udelay(10);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
/*
|
||||
* Clear "initialization complete" bit to move adapter from
|
||||
|
@ -586,7 +582,7 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
|
|||
|
||||
iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
|
||||
CSR_RESET_LINK_PWR_MGMT_DISABLED);
|
||||
msleep(1);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
for (iter = 0; iter < 10; iter++) {
|
||||
/* If HW is not ready, prepare the conditions to check again */
|
||||
|
@ -1074,7 +1070,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
|||
|
||||
/* stop and reset the on-board processor */
|
||||
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
|
||||
udelay(20);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
/*
|
||||
* Upon stop, the APM issues an interrupt if HW RF kill is set.
|
||||
|
@ -1526,8 +1522,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
|
|||
|
||||
/* Reset the entire device */
|
||||
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
|
||||
|
||||
usleep_range(10, 15);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
iwl_pcie_apm_init(trans);
|
||||
|
||||
|
@ -1950,7 +1945,7 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
|
|||
"WR pointer moved while flushing %d -> %d\n",
|
||||
wr_ptr, write_ptr))
|
||||
return -ETIMEDOUT;
|
||||
msleep(1);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
if (q->read_ptr != q->write_ptr) {
|
||||
|
@ -2013,7 +2008,7 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
|
|||
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_ref(struct iwl_trans *trans)
|
||||
static void iwl_trans_pcie_ref(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
|
@ -2028,7 +2023,7 @@ void iwl_trans_pcie_ref(struct iwl_trans *trans)
|
|||
#endif /* CONFIG_PM */
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_unref(struct iwl_trans *trans)
|
||||
static void iwl_trans_pcie_unref(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
|
@ -2907,6 +2902,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
}
|
||||
}
|
||||
|
||||
trans->hw_rf_id = iwl_read32(trans, CSR_HW_RF_ID);
|
||||
|
||||
iwl_pcie_set_interrupt_capa(pdev, trans);
|
||||
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
|
||||
snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/ieee80211.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <net/tso.h>
|
||||
|
||||
|
@ -605,7 +606,7 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
|
|||
if (trans_pcie->ref_cmd_in_flight) {
|
||||
trans_pcie->ref_cmd_in_flight = false;
|
||||
IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n");
|
||||
iwl_trans_pcie_unref(trans);
|
||||
iwl_trans_unref(trans);
|
||||
}
|
||||
|
||||
if (!trans->cfg->base_params->apmg_wake_up_wa)
|
||||
|
@ -650,7 +651,7 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
|
|||
if (txq_id != trans_pcie->cmd_queue) {
|
||||
IWL_DEBUG_RPM(trans, "Q %d - last tx freed\n",
|
||||
q->id);
|
||||
iwl_trans_pcie_unref(trans);
|
||||
iwl_trans_unref(trans);
|
||||
} else {
|
||||
iwl_pcie_clear_cmd_in_flight(trans);
|
||||
}
|
||||
|
@ -1134,7 +1135,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
|
|||
|
||||
if (q->read_ptr == q->write_ptr) {
|
||||
IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
|
||||
iwl_trans_pcie_unref(trans);
|
||||
iwl_trans_unref(trans);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1153,7 +1154,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
|
|||
!trans_pcie->ref_cmd_in_flight) {
|
||||
trans_pcie->ref_cmd_in_flight = true;
|
||||
IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n");
|
||||
iwl_trans_pcie_ref(trans);
|
||||
iwl_trans_ref(trans);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1799,6 +1800,16 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
|
|||
IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
|
||||
iwl_get_cmd_string(trans, cmd->id));
|
||||
|
||||
if (pm_runtime_suspended(&trans_pcie->pci_dev->dev)) {
|
||||
ret = wait_event_timeout(trans_pcie->d0i3_waitq,
|
||||
pm_runtime_active(&trans_pcie->pci_dev->dev),
|
||||
msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
|
||||
if (!ret) {
|
||||
IWL_ERR(trans, "Timeout exiting D0i3 before hcmd\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd);
|
||||
if (cmd_idx < 0) {
|
||||
ret = cmd_idx;
|
||||
|
@ -2362,7 +2373,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
txq->frozen_expiry_remainder = txq->wd_timeout;
|
||||
}
|
||||
IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
|
||||
iwl_trans_pcie_ref(trans);
|
||||
iwl_trans_ref(trans);
|
||||
}
|
||||
|
||||
/* Tell device the write index *just past* this latest filled TFD */
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#define _MWIFIEX_PCIE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pcieport_if.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "decl.h"
|
||||
|
@ -117,7 +116,7 @@
|
|||
/* FW awake cookie after FW ready */
|
||||
#define FW_AWAKE_COOKIE (0xAA55AA55)
|
||||
#define MWIFIEX_DEF_SLEEP_COOKIE 0xBEEFBEEF
|
||||
#define MWIFIEX_MAX_DELAY_COUNT 5
|
||||
#define MWIFIEX_MAX_DELAY_COUNT 100
|
||||
|
||||
struct mwifiex_pcie_card_reg {
|
||||
u16 cmd_addr_lo;
|
||||
|
|
|
@ -104,7 +104,7 @@ static int mwifiex_sdio_probe_of(struct device *dev, struct sdio_mmc_card *card)
|
|||
|
||||
if (!dev->of_node ||
|
||||
!of_match_node(mwifiex_sdio_of_match_table, dev->of_node)) {
|
||||
pr_err("sdio platform data not available");
|
||||
dev_err(dev, "sdio platform data not available\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,8 @@ static int mwifiex_sdio_probe_of(struct device *dev, struct sdio_mmc_card *card)
|
|||
if (cfg && card->plt_of_node) {
|
||||
cfg->irq_wifi = irq_of_parse_and_map(card->plt_of_node, 0);
|
||||
if (!cfg->irq_wifi) {
|
||||
dev_err(dev, "fail to parse irq_wifi from device tree");
|
||||
dev_err(dev,
|
||||
"fail to parse irq_wifi from device tree\n");
|
||||
} else {
|
||||
ret = devm_request_irq(dev, cfg->irq_wifi,
|
||||
mwifiex_wake_irq_wifi,
|
||||
|
|
|
@ -160,104 +160,40 @@ struct rtl8187_priv {
|
|||
|
||||
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
|
||||
|
||||
static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 idx)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
mutex_lock(&priv->io_mutex);
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits8, sizeof(val), HZ / 2);
|
||||
|
||||
val = priv->io_dmabuf->bits8;
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 idx);
|
||||
|
||||
static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
|
||||
{
|
||||
return rtl818x_ioread8_idx(priv, addr, 0);
|
||||
}
|
||||
|
||||
static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u8 idx)
|
||||
{
|
||||
__le16 val;
|
||||
|
||||
mutex_lock(&priv->io_mutex);
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits16, sizeof(val), HZ / 2);
|
||||
|
||||
val = priv->io_dmabuf->bits16;
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
|
||||
return le16_to_cpu(val);
|
||||
}
|
||||
u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u8 idx);
|
||||
|
||||
static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
|
||||
{
|
||||
return rtl818x_ioread16_idx(priv, addr, 0);
|
||||
}
|
||||
|
||||
static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u8 idx)
|
||||
{
|
||||
__le32 val;
|
||||
|
||||
mutex_lock(&priv->io_mutex);
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits32, sizeof(val), HZ / 2);
|
||||
|
||||
val = priv->io_dmabuf->bits32;
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
|
||||
return le32_to_cpu(val);
|
||||
}
|
||||
u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u8 idx);
|
||||
|
||||
static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
|
||||
{
|
||||
return rtl818x_ioread32_idx(priv, addr, 0);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 val, u8 idx)
|
||||
{
|
||||
mutex_lock(&priv->io_mutex);
|
||||
|
||||
priv->io_dmabuf->bits8 = val;
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits8, sizeof(val), HZ / 2);
|
||||
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
}
|
||||
void rtl818x_iowrite8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 val, u8 idx);
|
||||
|
||||
static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val)
|
||||
{
|
||||
rtl818x_iowrite8_idx(priv, addr, val, 0);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u16 val, u8 idx)
|
||||
{
|
||||
mutex_lock(&priv->io_mutex);
|
||||
|
||||
priv->io_dmabuf->bits16 = cpu_to_le16(val);
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits16, sizeof(val), HZ / 2);
|
||||
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
}
|
||||
void rtl818x_iowrite16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u16 val, u8 idx);
|
||||
|
||||
static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr,
|
||||
u16 val)
|
||||
|
@ -265,19 +201,8 @@ static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr,
|
|||
rtl818x_iowrite16_idx(priv, addr, val, 0);
|
||||
}
|
||||
|
||||
static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u32 val, u8 idx)
|
||||
{
|
||||
mutex_lock(&priv->io_mutex);
|
||||
|
||||
priv->io_dmabuf->bits32 = cpu_to_le32(val);
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits32, sizeof(val), HZ / 2);
|
||||
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
}
|
||||
void rtl818x_iowrite32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u32 val, u8 idx);
|
||||
|
||||
static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr,
|
||||
u32 val)
|
||||
|
|
|
@ -22,6 +22,99 @@
|
|||
#include "rtl8187.h"
|
||||
#include "rtl8225.h"
|
||||
|
||||
u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 idx)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
mutex_lock(&priv->io_mutex);
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits8, sizeof(val), HZ / 2);
|
||||
|
||||
val = priv->io_dmabuf->bits8;
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u8 idx)
|
||||
{
|
||||
__le16 val;
|
||||
|
||||
mutex_lock(&priv->io_mutex);
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits16, sizeof(val), HZ / 2);
|
||||
|
||||
val = priv->io_dmabuf->bits16;
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
|
||||
return le16_to_cpu(val);
|
||||
}
|
||||
|
||||
u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u8 idx)
|
||||
{
|
||||
__le32 val;
|
||||
|
||||
mutex_lock(&priv->io_mutex);
|
||||
usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits32, sizeof(val), HZ / 2);
|
||||
|
||||
val = priv->io_dmabuf->bits32;
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
|
||||
return le32_to_cpu(val);
|
||||
}
|
||||
|
||||
void rtl818x_iowrite8_idx(struct rtl8187_priv *priv,
|
||||
u8 *addr, u8 val, u8 idx)
|
||||
{
|
||||
mutex_lock(&priv->io_mutex);
|
||||
|
||||
priv->io_dmabuf->bits8 = val;
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits8, sizeof(val), HZ / 2);
|
||||
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
}
|
||||
|
||||
void rtl818x_iowrite16_idx(struct rtl8187_priv *priv,
|
||||
__le16 *addr, u16 val, u8 idx)
|
||||
{
|
||||
mutex_lock(&priv->io_mutex);
|
||||
|
||||
priv->io_dmabuf->bits16 = cpu_to_le16(val);
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits16, sizeof(val), HZ / 2);
|
||||
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
}
|
||||
|
||||
void rtl818x_iowrite32_idx(struct rtl8187_priv *priv,
|
||||
__le32 *addr, u32 val, u8 idx)
|
||||
{
|
||||
mutex_lock(&priv->io_mutex);
|
||||
|
||||
priv->io_dmabuf->bits32 = cpu_to_le32(val);
|
||||
usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
|
||||
RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
|
||||
(unsigned long)addr, idx & 0x03,
|
||||
&priv->io_dmabuf->bits32, sizeof(val), HZ / 2);
|
||||
|
||||
mutex_unlock(&priv->io_mutex);
|
||||
}
|
||||
|
||||
static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o
|
||||
|
||||
rtl8xxxu-y := rtl8xxxu_core.o rtl8xxxu_8192e.o rtl8xxxu_8723b.o \
|
||||
rtl8xxxu_8723a.o rtl8xxxu_8192c.o
|
||||
|
|
|
@ -1329,8 +1329,6 @@ struct rtl8xxxu_fileops {
|
|||
void (*report_connect) (struct rtl8xxxu_priv *priv,
|
||||
u8 macid, bool connect);
|
||||
int writeN_block_size;
|
||||
u16 mbox_ext_reg;
|
||||
char mbox_ext_width;
|
||||
char tx_desc_size;
|
||||
char rx_desc_size;
|
||||
char has_s0s1;
|
||||
|
@ -1347,3 +1345,82 @@ struct rtl8xxxu_fileops {
|
|||
u8 page_num_lo;
|
||||
u8 page_num_norm;
|
||||
};
|
||||
|
||||
extern int rtl8xxxu_debug;
|
||||
|
||||
extern struct rtl8xxxu_reg8val rtl8xxxu_gen1_mac_init_table[];
|
||||
extern const u32 rtl8xxxu_iqk_phy_iq_bb_reg[];
|
||||
u8 rtl8xxxu_read8(struct rtl8xxxu_priv *priv, u16 addr);
|
||||
u16 rtl8xxxu_read16(struct rtl8xxxu_priv *priv, u16 addr);
|
||||
u32 rtl8xxxu_read32(struct rtl8xxxu_priv *priv, u16 addr);
|
||||
int rtl8xxxu_write8(struct rtl8xxxu_priv *priv, u16 addr, u8 val);
|
||||
int rtl8xxxu_write16(struct rtl8xxxu_priv *priv, u16 addr, u16 val);
|
||||
int rtl8xxxu_write32(struct rtl8xxxu_priv *priv, u16 addr, u32 val);
|
||||
u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv,
|
||||
enum rtl8xxxu_rfpath path, u8 reg);
|
||||
int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
|
||||
enum rtl8xxxu_rfpath path, u8 reg, u32 data);
|
||||
void rtl8xxxu_save_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
|
||||
u32 *backup, int count);
|
||||
void rtl8xxxu_restore_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
|
||||
u32 *backup, int count);
|
||||
void rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv,
|
||||
const u32 *reg, u32 *backup);
|
||||
void rtl8xxxu_restore_mac_regs(struct rtl8xxxu_priv *priv,
|
||||
const u32 *reg, u32 *backup);
|
||||
void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs,
|
||||
bool path_a_on);
|
||||
void rtl8xxxu_mac_calibration(struct rtl8xxxu_priv *priv,
|
||||
const u32 *regs, u32 *backup);
|
||||
void rtl8xxxu_fill_iqk_matrix_a(struct rtl8xxxu_priv *priv, bool iqk_ok,
|
||||
int result[][8], int candidate, bool tx_only);
|
||||
void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv, bool iqk_ok,
|
||||
int result[][8], int candidate, bool tx_only);
|
||||
int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv,
|
||||
struct rtl8xxxu_rfregval *table,
|
||||
enum rtl8xxxu_rfpath path);
|
||||
int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
|
||||
struct rtl8xxxu_reg32val *array);
|
||||
int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name);
|
||||
void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv);
|
||||
int rtl8xxxu_auto_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page);
|
||||
void rtl8xxxu_gen2_prepare_calibrate(struct rtl8xxxu_priv *priv, u8 start);
|
||||
int rtl8xxxu_flush_fifo(struct rtl8xxxu_priv *priv);
|
||||
int rtl8xxxu_gen2_h2c_cmd(struct rtl8xxxu_priv *priv,
|
||||
struct h2c_cmd *h2c, int len);
|
||||
int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv);
|
||||
int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page);
|
||||
void rtl8xxxu_gen1_phy_iq_calibrate(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen1_init_phy_bb(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv,
|
||||
int channel, bool ht40);
|
||||
void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw);
|
||||
void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw);
|
||||
void rtl8xxxu_gen1_usb_quirks(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen2_usb_quirks(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv,
|
||||
u32 ramask, int sgi);
|
||||
void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv,
|
||||
u32 ramask, int sgi);
|
||||
void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv,
|
||||
u8 macid, bool connect);
|
||||
void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
|
||||
u8 macid, bool connect);
|
||||
void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv);
|
||||
int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int rtl8xxxu_gen2_channel_to_group(int channel);
|
||||
bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv,
|
||||
int result[][8], int c1, int c2);
|
||||
|
||||
extern struct rtl8xxxu_fileops rtl8192cu_fops;
|
||||
extern struct rtl8xxxu_fileops rtl8192eu_fops;
|
||||
extern struct rtl8xxxu_fileops rtl8723au_fops;
|
||||
extern struct rtl8xxxu_fileops rtl8723bu_fops;
|
||||
|
|
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
* RTL8XXXU mac80211 USB driver - 8188c/8188r/8192c specific subdriver
|
||||
*
|
||||
* Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@redhat.com>
|
||||
*
|
||||
* Portions, notably calibration code:
|
||||
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
|
||||
*
|
||||
* This driver was written as a replacement for the vendor provided
|
||||
* rtl8723au driver. As the Realtek 8xxx chips are very similar in
|
||||
* their programming interface, I have started adding support for
|
||||
* additional 8xxx chips like the 8192cu, 8188cus, etc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "rtl8xxxu.h"
|
||||
#include "rtl8xxxu_regs.h"
|
||||
|
||||
#ifdef CONFIG_RTL8XXXU_UNTESTED
|
||||
static struct rtl8xxxu_power_base rtl8192c_power_base = {
|
||||
.reg_0e00 = 0x07090c0c,
|
||||
.reg_0e04 = 0x01020405,
|
||||
.reg_0e08 = 0x00000000,
|
||||
.reg_086c = 0x00000000,
|
||||
|
||||
.reg_0e10 = 0x0b0c0c0e,
|
||||
.reg_0e14 = 0x01030506,
|
||||
.reg_0e18 = 0x0b0c0d0e,
|
||||
.reg_0e1c = 0x01030509,
|
||||
|
||||
.reg_0830 = 0x07090c0c,
|
||||
.reg_0834 = 0x01020405,
|
||||
.reg_0838 = 0x00000000,
|
||||
.reg_086c_2 = 0x00000000,
|
||||
|
||||
.reg_083c = 0x0b0c0d0e,
|
||||
.reg_0848 = 0x01030509,
|
||||
.reg_084c = 0x0b0c0d0e,
|
||||
.reg_0868 = 0x01030509,
|
||||
};
|
||||
|
||||
static struct rtl8xxxu_power_base rtl8188r_power_base = {
|
||||
.reg_0e00 = 0x06080808,
|
||||
.reg_0e04 = 0x00040406,
|
||||
.reg_0e08 = 0x00000000,
|
||||
.reg_086c = 0x00000000,
|
||||
|
||||
.reg_0e10 = 0x04060608,
|
||||
.reg_0e14 = 0x00020204,
|
||||
.reg_0e18 = 0x04060608,
|
||||
.reg_0e1c = 0x00020204,
|
||||
|
||||
.reg_0830 = 0x06080808,
|
||||
.reg_0834 = 0x00040406,
|
||||
.reg_0838 = 0x00000000,
|
||||
.reg_086c_2 = 0x00000000,
|
||||
|
||||
.reg_083c = 0x04060608,
|
||||
.reg_0848 = 0x00020204,
|
||||
.reg_084c = 0x04060608,
|
||||
.reg_0868 = 0x00020204,
|
||||
};
|
||||
|
||||
static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = {
|
||||
{0x00, 0x00030159}, {0x01, 0x00031284},
|
||||
{0x02, 0x00098000}, {0x03, 0x00018c63},
|
||||
{0x04, 0x000210e7}, {0x09, 0x0002044f},
|
||||
{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
|
||||
{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
|
||||
{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
|
||||
{0x19, 0x00000000}, {0x1a, 0x00010255},
|
||||
{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
|
||||
{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
|
||||
{0x1f, 0x00080001}, {0x20, 0x0000b614},
|
||||
{0x21, 0x0006c000}, {0x22, 0x00000000},
|
||||
{0x23, 0x00001558}, {0x24, 0x00000060},
|
||||
{0x25, 0x00000483}, {0x26, 0x0004f000},
|
||||
{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
|
||||
{0x29, 0x00004783}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00021334}, {0x2a, 0x00000000},
|
||||
{0x2b, 0x00000054}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000c}, {0x2a, 0x00000002},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000003},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000004},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000005},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000006},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000007},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000008},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000009},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
|
||||
{0x2b, 0x0000050b}, {0x2b, 0x00066666},
|
||||
{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
|
||||
{0x10, 0x0004000f}, {0x11, 0x000e31fc},
|
||||
{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
|
||||
{0x10, 0x0002000f}, {0x11, 0x000203f9},
|
||||
{0x10, 0x0003000f}, {0x11, 0x000ff500},
|
||||
{0x10, 0x00000000}, {0x11, 0x00000000},
|
||||
{0x10, 0x0008000f}, {0x11, 0x0003f100},
|
||||
{0x10, 0x0009000f}, {0x11, 0x00023100},
|
||||
{0x12, 0x00032000}, {0x12, 0x00071000},
|
||||
{0x12, 0x000b0000}, {0x12, 0x000fc000},
|
||||
{0x13, 0x000287b3}, {0x13, 0x000244b7},
|
||||
{0x13, 0x000204ab}, {0x13, 0x0001c49f},
|
||||
{0x13, 0x00018493}, {0x13, 0x0001429b},
|
||||
{0x13, 0x00010299}, {0x13, 0x0000c29c},
|
||||
{0x13, 0x000081a0}, {0x13, 0x000040ac},
|
||||
{0x13, 0x00000020}, {0x14, 0x0001944c},
|
||||
{0x14, 0x00059444}, {0x14, 0x0009944c},
|
||||
{0x14, 0x000d9444}, {0x15, 0x0000f424},
|
||||
{0x15, 0x0004f424}, {0x15, 0x0008f424},
|
||||
{0x15, 0x000cf424}, {0x16, 0x000e0330},
|
||||
{0x16, 0x000a0330}, {0x16, 0x00060330},
|
||||
{0x16, 0x00020330}, {0x00, 0x00010159},
|
||||
{0x18, 0x0000f401}, {0xfe, 0x00000000},
|
||||
{0xfe, 0x00000000}, {0x1f, 0x00080003},
|
||||
{0xfe, 0x00000000}, {0xfe, 0x00000000},
|
||||
{0x1e, 0x00044457}, {0x1f, 0x00080000},
|
||||
{0x00, 0x00030159},
|
||||
{0xff, 0xffffffff}
|
||||
};
|
||||
|
||||
static struct rtl8xxxu_rfregval rtl8192cu_radiob_2t_init_table[] = {
|
||||
{0x00, 0x00030159}, {0x01, 0x00031284},
|
||||
{0x02, 0x00098000}, {0x03, 0x00018c63},
|
||||
{0x04, 0x000210e7}, {0x09, 0x0002044f},
|
||||
{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
|
||||
{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
|
||||
{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
|
||||
{0x12, 0x00032000}, {0x12, 0x00071000},
|
||||
{0x12, 0x000b0000}, {0x12, 0x000fc000},
|
||||
{0x13, 0x000287af}, {0x13, 0x000244b7},
|
||||
{0x13, 0x000204ab}, {0x13, 0x0001c49f},
|
||||
{0x13, 0x00018493}, {0x13, 0x00014297},
|
||||
{0x13, 0x00010295}, {0x13, 0x0000c298},
|
||||
{0x13, 0x0000819c}, {0x13, 0x000040a8},
|
||||
{0x13, 0x0000001c}, {0x14, 0x0001944c},
|
||||
{0x14, 0x00059444}, {0x14, 0x0009944c},
|
||||
{0x14, 0x000d9444}, {0x15, 0x0000f424},
|
||||
{0x15, 0x0004f424}, {0x15, 0x0008f424},
|
||||
{0x15, 0x000cf424}, {0x16, 0x000e0330},
|
||||
{0x16, 0x000a0330}, {0x16, 0x00060330},
|
||||
{0x16, 0x00020330},
|
||||
{0xff, 0xffffffff}
|
||||
};
|
||||
|
||||
static struct rtl8xxxu_rfregval rtl8192cu_radioa_1t_init_table[] = {
|
||||
{0x00, 0x00030159}, {0x01, 0x00031284},
|
||||
{0x02, 0x00098000}, {0x03, 0x00018c63},
|
||||
{0x04, 0x000210e7}, {0x09, 0x0002044f},
|
||||
{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
|
||||
{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
|
||||
{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
|
||||
{0x19, 0x00000000}, {0x1a, 0x00010255},
|
||||
{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
|
||||
{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
|
||||
{0x1f, 0x00080001}, {0x20, 0x0000b614},
|
||||
{0x21, 0x0006c000}, {0x22, 0x00000000},
|
||||
{0x23, 0x00001558}, {0x24, 0x00000060},
|
||||
{0x25, 0x00000483}, {0x26, 0x0004f000},
|
||||
{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
|
||||
{0x29, 0x00004783}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00021334}, {0x2a, 0x00000000},
|
||||
{0x2b, 0x00000054}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000c}, {0x2a, 0x00000002},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000003},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000004},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000005},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000006},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000007},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000008},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000009},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
|
||||
{0x2b, 0x0000050b}, {0x2b, 0x00066666},
|
||||
{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
|
||||
{0x10, 0x0004000f}, {0x11, 0x000e31fc},
|
||||
{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
|
||||
{0x10, 0x0002000f}, {0x11, 0x000203f9},
|
||||
{0x10, 0x0003000f}, {0x11, 0x000ff500},
|
||||
{0x10, 0x00000000}, {0x11, 0x00000000},
|
||||
{0x10, 0x0008000f}, {0x11, 0x0003f100},
|
||||
{0x10, 0x0009000f}, {0x11, 0x00023100},
|
||||
{0x12, 0x00032000}, {0x12, 0x00071000},
|
||||
{0x12, 0x000b0000}, {0x12, 0x000fc000},
|
||||
{0x13, 0x000287b3}, {0x13, 0x000244b7},
|
||||
{0x13, 0x000204ab}, {0x13, 0x0001c49f},
|
||||
{0x13, 0x00018493}, {0x13, 0x0001429b},
|
||||
{0x13, 0x00010299}, {0x13, 0x0000c29c},
|
||||
{0x13, 0x000081a0}, {0x13, 0x000040ac},
|
||||
{0x13, 0x00000020}, {0x14, 0x0001944c},
|
||||
{0x14, 0x00059444}, {0x14, 0x0009944c},
|
||||
{0x14, 0x000d9444}, {0x15, 0x0000f405},
|
||||
{0x15, 0x0004f405}, {0x15, 0x0008f405},
|
||||
{0x15, 0x000cf405}, {0x16, 0x000e0330},
|
||||
{0x16, 0x000a0330}, {0x16, 0x00060330},
|
||||
{0x16, 0x00020330}, {0x00, 0x00010159},
|
||||
{0x18, 0x0000f401}, {0xfe, 0x00000000},
|
||||
{0xfe, 0x00000000}, {0x1f, 0x00080003},
|
||||
{0xfe, 0x00000000}, {0xfe, 0x00000000},
|
||||
{0x1e, 0x00044457}, {0x1f, 0x00080000},
|
||||
{0x00, 0x00030159},
|
||||
{0xff, 0xffffffff}
|
||||
};
|
||||
|
||||
static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = {
|
||||
{0x00, 0x00030159}, {0x01, 0x00031284},
|
||||
{0x02, 0x00098000}, {0x03, 0x00018c63},
|
||||
{0x04, 0x000210e7}, {0x09, 0x0002044f},
|
||||
{0x0a, 0x0001adb0}, {0x0b, 0x00054867},
|
||||
{0x0c, 0x0008992e}, {0x0d, 0x0000e529},
|
||||
{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
|
||||
{0x19, 0x00000000}, {0x1a, 0x00000255},
|
||||
{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
|
||||
{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
|
||||
{0x1f, 0x00080001}, {0x20, 0x0000b614},
|
||||
{0x21, 0x0006c000}, {0x22, 0x0000083c},
|
||||
{0x23, 0x00001558}, {0x24, 0x00000060},
|
||||
{0x25, 0x00000483}, {0x26, 0x0004f000},
|
||||
{0x27, 0x000ec7d9}, {0x28, 0x000977c0},
|
||||
{0x29, 0x00004783}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00021334}, {0x2a, 0x00000000},
|
||||
{0x2b, 0x00000054}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000c}, {0x2a, 0x00000002},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000003},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000004},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000005},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000006},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000007},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000008},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000009},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
|
||||
{0x2b, 0x0000050b}, {0x2b, 0x00066666},
|
||||
{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
|
||||
{0x10, 0x0004000f}, {0x11, 0x000e31fc},
|
||||
{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
|
||||
{0x10, 0x0002000f}, {0x11, 0x000203f9},
|
||||
{0x10, 0x0003000f}, {0x11, 0x000ff500},
|
||||
{0x10, 0x00000000}, {0x11, 0x00000000},
|
||||
{0x10, 0x0008000f}, {0x11, 0x0003f100},
|
||||
{0x10, 0x0009000f}, {0x11, 0x00023100},
|
||||
{0x12, 0x000d8000}, {0x12, 0x00090000},
|
||||
{0x12, 0x00051000}, {0x12, 0x00012000},
|
||||
{0x13, 0x00028fb4}, {0x13, 0x00024fa8},
|
||||
{0x13, 0x000207a4}, {0x13, 0x0001c3b0},
|
||||
{0x13, 0x000183a4}, {0x13, 0x00014398},
|
||||
{0x13, 0x000101a4}, {0x13, 0x0000c198},
|
||||
{0x13, 0x000080a4}, {0x13, 0x00004098},
|
||||
{0x13, 0x00000000}, {0x14, 0x0001944c},
|
||||
{0x14, 0x00059444}, {0x14, 0x0009944c},
|
||||
{0x14, 0x000d9444}, {0x15, 0x0000f405},
|
||||
{0x15, 0x0004f405}, {0x15, 0x0008f405},
|
||||
{0x15, 0x000cf405}, {0x16, 0x000e0330},
|
||||
{0x16, 0x000a0330}, {0x16, 0x00060330},
|
||||
{0x16, 0x00020330}, {0x00, 0x00010159},
|
||||
{0x18, 0x0000f401}, {0xfe, 0x00000000},
|
||||
{0xfe, 0x00000000}, {0x1f, 0x00080003},
|
||||
{0xfe, 0x00000000}, {0xfe, 0x00000000},
|
||||
{0x1e, 0x00044457}, {0x1f, 0x00080000},
|
||||
{0x00, 0x00030159},
|
||||
{0xff, 0xffffffff}
|
||||
};
|
||||
|
||||
static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
char *fw_name;
|
||||
int ret;
|
||||
|
||||
if (!priv->vendor_umc)
|
||||
fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
|
||||
else if (priv->chip_cut || priv->rtl_chip == RTL8192C)
|
||||
fw_name = "rtlwifi/rtl8192cufw_B.bin";
|
||||
else
|
||||
fw_name = "rtlwifi/rtl8192cufw_A.bin";
|
||||
|
||||
ret = rtl8xxxu_load_firmware(priv, fw_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
struct rtl8192cu_efuse *efuse = &priv->efuse_wifi.efuse8192;
|
||||
int i;
|
||||
|
||||
if (efuse->rtl_id != cpu_to_le16(0x8129))
|
||||
return -EINVAL;
|
||||
|
||||
ether_addr_copy(priv->mac_addr, efuse->mac_addr);
|
||||
|
||||
memcpy(priv->cck_tx_power_index_A,
|
||||
efuse->cck_tx_power_index_A,
|
||||
sizeof(efuse->cck_tx_power_index_A));
|
||||
memcpy(priv->cck_tx_power_index_B,
|
||||
efuse->cck_tx_power_index_B,
|
||||
sizeof(efuse->cck_tx_power_index_B));
|
||||
|
||||
memcpy(priv->ht40_1s_tx_power_index_A,
|
||||
efuse->ht40_1s_tx_power_index_A,
|
||||
sizeof(efuse->ht40_1s_tx_power_index_A));
|
||||
memcpy(priv->ht40_1s_tx_power_index_B,
|
||||
efuse->ht40_1s_tx_power_index_B,
|
||||
sizeof(efuse->ht40_1s_tx_power_index_B));
|
||||
memcpy(priv->ht40_2s_tx_power_index_diff,
|
||||
efuse->ht40_2s_tx_power_index_diff,
|
||||
sizeof(efuse->ht40_2s_tx_power_index_diff));
|
||||
|
||||
memcpy(priv->ht20_tx_power_index_diff,
|
||||
efuse->ht20_tx_power_index_diff,
|
||||
sizeof(efuse->ht20_tx_power_index_diff));
|
||||
memcpy(priv->ofdm_tx_power_index_diff,
|
||||
efuse->ofdm_tx_power_index_diff,
|
||||
sizeof(efuse->ofdm_tx_power_index_diff));
|
||||
|
||||
memcpy(priv->ht40_max_power_offset,
|
||||
efuse->ht40_max_power_offset,
|
||||
sizeof(efuse->ht40_max_power_offset));
|
||||
memcpy(priv->ht20_max_power_offset,
|
||||
efuse->ht20_max_power_offset,
|
||||
sizeof(efuse->ht20_max_power_offset));
|
||||
|
||||
dev_info(&priv->udev->dev, "Vendor: %.7s\n",
|
||||
efuse->vendor_name);
|
||||
dev_info(&priv->udev->dev, "Product: %.20s\n",
|
||||
efuse->device_name);
|
||||
|
||||
priv->power_base = &rtl8192c_power_base;
|
||||
|
||||
if (efuse->rf_regulatory & 0x20) {
|
||||
sprintf(priv->chip_name, "8188RU");
|
||||
priv->rtl_chip = RTL8188R;
|
||||
priv->hi_pa = 1;
|
||||
priv->no_pape = 1;
|
||||
priv->power_base = &rtl8188r_power_base;
|
||||
}
|
||||
|
||||
if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
|
||||
unsigned char *raw = priv->efuse_wifi.raw;
|
||||
|
||||
dev_info(&priv->udev->dev,
|
||||
"%s: dumping efuse (0x%02zx bytes):\n",
|
||||
__func__, sizeof(struct rtl8192cu_efuse));
|
||||
for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) {
|
||||
dev_info(&priv->udev->dev, "%02x: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
|
||||
raw[i], raw[i + 1], raw[i + 2],
|
||||
raw[i + 3], raw[i + 4], raw[i + 5],
|
||||
raw[i + 6], raw[i + 7]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8192cu_init_phy_rf(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
struct rtl8xxxu_rfregval *rftable;
|
||||
int ret;
|
||||
|
||||
if (priv->rtl_chip == RTL8188R) {
|
||||
rftable = rtl8188ru_radioa_1t_highpa_table;
|
||||
ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
|
||||
} else if (priv->rf_paths == 1) {
|
||||
rftable = rtl8192cu_radioa_1t_init_table;
|
||||
ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
|
||||
} else {
|
||||
rftable = rtl8192cu_radioa_2t_init_table;
|
||||
ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
|
||||
if (ret)
|
||||
goto exit;
|
||||
rftable = rtl8192cu_radiob_2t_init_table;
|
||||
ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
u8 val8;
|
||||
u16 val16;
|
||||
u32 val32;
|
||||
int i;
|
||||
|
||||
for (i = 100; i; i--) {
|
||||
val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO);
|
||||
if (val8 & APS_FSMCO_PFM_ALDN)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!i) {
|
||||
pr_info("%s: Poll failed\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
|
||||
*/
|
||||
rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
|
||||
rtl8xxxu_write8(priv, REG_SPS0_CTRL, 0x2b);
|
||||
udelay(100);
|
||||
|
||||
val8 = rtl8xxxu_read8(priv, REG_LDOV12D_CTRL);
|
||||
if (!(val8 & LDOV12D_ENABLE)) {
|
||||
pr_info("%s: Enabling LDOV12D (%02x)\n", __func__, val8);
|
||||
val8 |= LDOV12D_ENABLE;
|
||||
rtl8xxxu_write8(priv, REG_LDOV12D_CTRL, val8);
|
||||
|
||||
udelay(100);
|
||||
|
||||
val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
|
||||
val8 &= ~SYS_ISO_MD2PP;
|
||||
rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Auto enable WLAN
|
||||
*/
|
||||
val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
|
||||
val16 |= APS_FSMCO_MAC_ENABLE;
|
||||
rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
|
||||
|
||||
for (i = 1000; i; i--) {
|
||||
val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
|
||||
if (!(val16 & APS_FSMCO_MAC_ENABLE))
|
||||
break;
|
||||
}
|
||||
if (!i) {
|
||||
pr_info("%s: FSMCO_MAC_ENABLE poll failed\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable radio, GPIO, LED
|
||||
*/
|
||||
val16 = APS_FSMCO_HW_SUSPEND | APS_FSMCO_ENABLE_POWERDOWN |
|
||||
APS_FSMCO_PFM_ALDN;
|
||||
rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
|
||||
|
||||
/*
|
||||
* Release RF digital isolation
|
||||
*/
|
||||
val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
|
||||
val16 &= ~SYS_ISO_DIOR;
|
||||
rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
|
||||
|
||||
val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
|
||||
val8 &= ~APSD_CTRL_OFF;
|
||||
rtl8xxxu_write8(priv, REG_APSD_CTRL, val8);
|
||||
for (i = 200; i; i--) {
|
||||
val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
|
||||
if (!(val8 & APSD_CTRL_OFF_STATUS))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!i) {
|
||||
pr_info("%s: APSD_CTRL poll failed\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable MAC DMA/WMAC/SCHEDULE/SEC block
|
||||
*/
|
||||
val16 = rtl8xxxu_read16(priv, REG_CR);
|
||||
val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
|
||||
CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | CR_PROTOCOL_ENABLE |
|
||||
CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE;
|
||||
rtl8xxxu_write16(priv, REG_CR, val16);
|
||||
|
||||
rtl8xxxu_write8(priv, 0xfe10, 0x19);
|
||||
|
||||
/*
|
||||
* Workaround for 8188RU LNA power leakage problem.
|
||||
*/
|
||||
if (priv->rtl_chip == RTL8188R) {
|
||||
val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
|
||||
val32 &= ~BIT(1);
|
||||
rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rtl8xxxu_fileops rtl8192cu_fops = {
|
||||
.parse_efuse = rtl8192cu_parse_efuse,
|
||||
.load_firmware = rtl8192cu_load_firmware,
|
||||
.power_on = rtl8192cu_power_on,
|
||||
.power_off = rtl8xxxu_power_off,
|
||||
.reset_8051 = rtl8xxxu_reset_8051,
|
||||
.llt_init = rtl8xxxu_init_llt_table,
|
||||
.init_phy_bb = rtl8xxxu_gen1_init_phy_bb,
|
||||
.init_phy_rf = rtl8192cu_init_phy_rf,
|
||||
.phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
|
||||
.config_channel = rtl8xxxu_gen1_config_channel,
|
||||
.parse_rx_desc = rtl8xxxu_parse_rxdesc16,
|
||||
.enable_rf = rtl8xxxu_gen1_enable_rf,
|
||||
.disable_rf = rtl8xxxu_gen1_disable_rf,
|
||||
.usb_quirks = rtl8xxxu_gen1_usb_quirks,
|
||||
.set_tx_power = rtl8xxxu_gen1_set_tx_power,
|
||||
.update_rate_mask = rtl8xxxu_update_rate_mask,
|
||||
.report_connect = rtl8xxxu_gen1_report_connect,
|
||||
.writeN_block_size = 128,
|
||||
.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
|
||||
.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
|
||||
.adda_1t_init = 0x0b1b25a0,
|
||||
.adda_1t_path_on = 0x0bdb25a0,
|
||||
.adda_2t_path_on_a = 0x04db25a4,
|
||||
.adda_2t_path_on_b = 0x0b1b25a4,
|
||||
.trxff_boundary = 0x27ff,
|
||||
.pbp_rx = PBP_PAGE_SIZE_128,
|
||||
.pbp_tx = PBP_PAGE_SIZE_128,
|
||||
.mactable = rtl8xxxu_gen1_mac_init_table,
|
||||
};
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* RTL8XXXU mac80211 USB driver - 8723a specific subdriver
|
||||
*
|
||||
* Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@redhat.com>
|
||||
*
|
||||
* Portions, notably calibration code:
|
||||
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
|
||||
*
|
||||
* This driver was written as a replacement for the vendor provided
|
||||
* rtl8723au driver. As the Realtek 8xxx chips are very similar in
|
||||
* their programming interface, I have started adding support for
|
||||
* additional 8xxx chips like the 8192cu, 8188cus, etc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "rtl8xxxu.h"
|
||||
#include "rtl8xxxu_regs.h"
|
||||
|
||||
static struct rtl8xxxu_power_base rtl8723a_power_base = {
|
||||
.reg_0e00 = 0x0a0c0c0c,
|
||||
.reg_0e04 = 0x02040608,
|
||||
.reg_0e08 = 0x00000000,
|
||||
.reg_086c = 0x00000000,
|
||||
|
||||
.reg_0e10 = 0x0a0c0d0e,
|
||||
.reg_0e14 = 0x02040608,
|
||||
.reg_0e18 = 0x0a0c0d0e,
|
||||
.reg_0e1c = 0x02040608,
|
||||
|
||||
.reg_0830 = 0x0a0c0c0c,
|
||||
.reg_0834 = 0x02040608,
|
||||
.reg_0838 = 0x00000000,
|
||||
.reg_086c_2 = 0x00000000,
|
||||
|
||||
.reg_083c = 0x0a0c0d0e,
|
||||
.reg_0848 = 0x02040608,
|
||||
.reg_084c = 0x0a0c0d0e,
|
||||
.reg_0868 = 0x02040608,
|
||||
};
|
||||
|
||||
static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
|
||||
{0x00, 0x00030159}, {0x01, 0x00031284},
|
||||
{0x02, 0x00098000}, {0x03, 0x00039c63},
|
||||
{0x04, 0x000210e7}, {0x09, 0x0002044f},
|
||||
{0x0a, 0x0001a3f1}, {0x0b, 0x00014787},
|
||||
{0x0c, 0x000896fe}, {0x0d, 0x0000e02c},
|
||||
{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
|
||||
{0x19, 0x00000000}, {0x1a, 0x00030355},
|
||||
{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
|
||||
{0x1d, 0x000a1250}, {0x1e, 0x0000024f},
|
||||
{0x1f, 0x00000000}, {0x20, 0x0000b614},
|
||||
{0x21, 0x0006c000}, {0x22, 0x00000000},
|
||||
{0x23, 0x00001558}, {0x24, 0x00000060},
|
||||
{0x25, 0x00000483}, {0x26, 0x0004f000},
|
||||
{0x27, 0x000ec7d9}, {0x28, 0x00057730},
|
||||
{0x29, 0x00004783}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00021334}, {0x2a, 0x00000000},
|
||||
{0x2b, 0x00000054}, {0x2a, 0x00000001},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000c}, {0x2a, 0x00000002},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000003},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000004},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000005},
|
||||
{0x2b, 0x00000808}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000006},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000007},
|
||||
{0x2b, 0x00000709}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000008},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x00000009},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00053333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00063333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
|
||||
{0x2b, 0x0000060a}, {0x2b, 0x00073333},
|
||||
{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
|
||||
{0x2b, 0x0000050b}, {0x2b, 0x00066666},
|
||||
{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
|
||||
{0x10, 0x0004000f}, {0x11, 0x000e31fc},
|
||||
{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
|
||||
{0x10, 0x0002000f}, {0x11, 0x000203f9},
|
||||
{0x10, 0x0003000f}, {0x11, 0x000ff500},
|
||||
{0x10, 0x00000000}, {0x11, 0x00000000},
|
||||
{0x10, 0x0008000f}, {0x11, 0x0003f100},
|
||||
{0x10, 0x0009000f}, {0x11, 0x00023100},
|
||||
{0x12, 0x00032000}, {0x12, 0x00071000},
|
||||
{0x12, 0x000b0000}, {0x12, 0x000fc000},
|
||||
{0x13, 0x000287b3}, {0x13, 0x000244b7},
|
||||
{0x13, 0x000204ab}, {0x13, 0x0001c49f},
|
||||
{0x13, 0x00018493}, {0x13, 0x0001429b},
|
||||
{0x13, 0x00010299}, {0x13, 0x0000c29c},
|
||||
{0x13, 0x000081a0}, {0x13, 0x000040ac},
|
||||
{0x13, 0x00000020}, {0x14, 0x0001944c},
|
||||
{0x14, 0x00059444}, {0x14, 0x0009944c},
|
||||
{0x14, 0x000d9444}, {0x15, 0x0000f474},
|
||||
{0x15, 0x0004f477}, {0x15, 0x0008f455},
|
||||
{0x15, 0x000cf455}, {0x16, 0x00000339},
|
||||
{0x16, 0x00040339}, {0x16, 0x00080339},
|
||||
{0x16, 0x000c0366}, {0x00, 0x00010159},
|
||||
{0x18, 0x0000f401}, {0xfe, 0x00000000},
|
||||
{0xfe, 0x00000000}, {0x1f, 0x00000003},
|
||||
{0xfe, 0x00000000}, {0xfe, 0x00000000},
|
||||
{0x1e, 0x00000247}, {0x1f, 0x00000000},
|
||||
{0x00, 0x00030159},
|
||||
{0xff, 0xffffffff}
|
||||
};
|
||||
|
||||
static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
struct rtl8723au_efuse *efuse = &priv->efuse_wifi.efuse8723;
|
||||
|
||||
if (efuse->rtl_id != cpu_to_le16(0x8129))
|
||||
return -EINVAL;
|
||||
|
||||
ether_addr_copy(priv->mac_addr, efuse->mac_addr);
|
||||
|
||||
memcpy(priv->cck_tx_power_index_A,
|
||||
efuse->cck_tx_power_index_A,
|
||||
sizeof(efuse->cck_tx_power_index_A));
|
||||
memcpy(priv->cck_tx_power_index_B,
|
||||
efuse->cck_tx_power_index_B,
|
||||
sizeof(efuse->cck_tx_power_index_B));
|
||||
|
||||
memcpy(priv->ht40_1s_tx_power_index_A,
|
||||
efuse->ht40_1s_tx_power_index_A,
|
||||
sizeof(efuse->ht40_1s_tx_power_index_A));
|
||||
memcpy(priv->ht40_1s_tx_power_index_B,
|
||||
efuse->ht40_1s_tx_power_index_B,
|
||||
sizeof(efuse->ht40_1s_tx_power_index_B));
|
||||
|
||||
memcpy(priv->ht20_tx_power_index_diff,
|
||||
efuse->ht20_tx_power_index_diff,
|
||||
sizeof(efuse->ht20_tx_power_index_diff));
|
||||
memcpy(priv->ofdm_tx_power_index_diff,
|
||||
efuse->ofdm_tx_power_index_diff,
|
||||
sizeof(efuse->ofdm_tx_power_index_diff));
|
||||
|
||||
memcpy(priv->ht40_max_power_offset,
|
||||
efuse->ht40_max_power_offset,
|
||||
sizeof(efuse->ht40_max_power_offset));
|
||||
memcpy(priv->ht20_max_power_offset,
|
||||
efuse->ht20_max_power_offset,
|
||||
sizeof(efuse->ht20_max_power_offset));
|
||||
|
||||
if (priv->efuse_wifi.efuse8723.version >= 0x01) {
|
||||
priv->has_xtalk = 1;
|
||||
priv->xtalk = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
|
||||
}
|
||||
|
||||
priv->power_base = &rtl8723a_power_base;
|
||||
|
||||
dev_info(&priv->udev->dev, "Vendor: %.7s\n",
|
||||
efuse->vendor_name);
|
||||
dev_info(&priv->udev->dev, "Product: %.41s\n",
|
||||
efuse->device_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
char *fw_name;
|
||||
int ret;
|
||||
|
||||
switch (priv->chip_cut) {
|
||||
case 0:
|
||||
fw_name = "rtlwifi/rtl8723aufw_A.bin";
|
||||
break;
|
||||
case 1:
|
||||
if (priv->enable_bluetooth)
|
||||
fw_name = "rtlwifi/rtl8723aufw_B.bin";
|
||||
else
|
||||
fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rtl8xxxu_load_firmware(priv, fw_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8723au_init_phy_rf(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtl8xxxu_init_phy_rf(priv, rtl8723au_radioa_1t_init_table, RF_A);
|
||||
|
||||
/* Reduce 80M spur */
|
||||
rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
|
||||
rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
|
||||
rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
|
||||
rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8723a_emu_to_active(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
u8 val8;
|
||||
u32 val32;
|
||||
int count, ret = 0;
|
||||
|
||||
/* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/
|
||||
val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
|
||||
val8 |= LDOA15_ENABLE;
|
||||
rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
|
||||
|
||||
/* 0x67[0] = 0 to disable BT_GPS_SEL pins*/
|
||||
val8 = rtl8xxxu_read8(priv, 0x0067);
|
||||
val8 &= ~BIT(4);
|
||||
rtl8xxxu_write8(priv, 0x0067, val8);
|
||||
|
||||
mdelay(1);
|
||||
|
||||
/* 0x00[5] = 0 release analog Ips to digital, 1:isolation */
|
||||
val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
|
||||
val8 &= ~SYS_ISO_ANALOG_IPS;
|
||||
rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
|
||||
|
||||
/* disable SW LPS 0x04[10]= 0 */
|
||||
val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
|
||||
val8 &= ~BIT(2);
|
||||
rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
|
||||
|
||||
/* wait till 0x04[17] = 1 power ready*/
|
||||
for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
|
||||
val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
|
||||
if (val32 & BIT(17))
|
||||
break;
|
||||
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* We should be able to optimize the following three entries into one */
|
||||
|
||||
/* release WLON reset 0x04[16]= 1*/
|
||||
val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
|
||||
val8 |= BIT(0);
|
||||
rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
|
||||
|
||||
/* disable HWPDN 0x04[15]= 0*/
|
||||
val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
|
||||
val8 &= ~BIT(7);
|
||||
rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
|
||||
|
||||
/* disable WL suspend*/
|
||||
val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
|
||||
val8 &= ~(BIT(3) | BIT(4));
|
||||
rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
|
||||
|
||||
/* set, then poll until 0 */
|
||||
val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
|
||||
val32 |= APS_FSMCO_MAC_ENABLE;
|
||||
rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
|
||||
|
||||
for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
|
||||
val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
|
||||
if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */
|
||||
/*
|
||||
* Note: Vendor driver actually clears this bit, despite the
|
||||
* documentation claims it's being set!
|
||||
*/
|
||||
val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
|
||||
val8 |= LEDCFG2_DPDT_SELECT;
|
||||
val8 &= ~LEDCFG2_DPDT_SELECT;
|
||||
rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
u8 val8;
|
||||
u16 val16;
|
||||
u32 val32;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
|
||||
*/
|
||||
rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
|
||||
|
||||
rtl8xxxu_disabled_to_emu(priv);
|
||||
|
||||
ret = rtl8723a_emu_to_active(priv);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* 0x0004[19] = 1, reset 8051
|
||||
*/
|
||||
val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
|
||||
val8 |= BIT(3);
|
||||
rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
|
||||
|
||||
/*
|
||||
* Enable MAC DMA/WMAC/SCHEDULE/SEC block
|
||||
* Set CR bit10 to enable 32k calibration.
|
||||
*/
|
||||
val16 = rtl8xxxu_read16(priv, REG_CR);
|
||||
val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
|
||||
CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
|
||||
CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
|
||||
CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE |
|
||||
CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
|
||||
rtl8xxxu_write16(priv, REG_CR, val16);
|
||||
|
||||
/* For EFuse PG */
|
||||
val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
|
||||
val32 &= ~(BIT(28) | BIT(29) | BIT(30));
|
||||
val32 |= (0x06 << 28);
|
||||
rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct rtl8xxxu_fileops rtl8723au_fops = {
|
||||
.parse_efuse = rtl8723au_parse_efuse,
|
||||
.load_firmware = rtl8723au_load_firmware,
|
||||
.power_on = rtl8723au_power_on,
|
||||
.power_off = rtl8xxxu_power_off,
|
||||
.reset_8051 = rtl8xxxu_reset_8051,
|
||||
.llt_init = rtl8xxxu_init_llt_table,
|
||||
.init_phy_bb = rtl8xxxu_gen1_init_phy_bb,
|
||||
.init_phy_rf = rtl8723au_init_phy_rf,
|
||||
.phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
|
||||
.config_channel = rtl8xxxu_gen1_config_channel,
|
||||
.parse_rx_desc = rtl8xxxu_parse_rxdesc16,
|
||||
.enable_rf = rtl8xxxu_gen1_enable_rf,
|
||||
.disable_rf = rtl8xxxu_gen1_disable_rf,
|
||||
.usb_quirks = rtl8xxxu_gen1_usb_quirks,
|
||||
.set_tx_power = rtl8xxxu_gen1_set_tx_power,
|
||||
.update_rate_mask = rtl8xxxu_update_rate_mask,
|
||||
.report_connect = rtl8xxxu_gen1_report_connect,
|
||||
.writeN_block_size = 1024,
|
||||
.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
|
||||
.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
|
||||
.adda_1t_init = 0x0b1b25a0,
|
||||
.adda_1t_path_on = 0x0bdb25a0,
|
||||
.adda_2t_path_on_a = 0x04db25a4,
|
||||
.adda_2t_path_on_b = 0x0b1b25a4,
|
||||
.trxff_boundary = 0x27ff,
|
||||
.pbp_rx = PBP_PAGE_SIZE_128,
|
||||
.pbp_tx = PBP_PAGE_SIZE_128,
|
||||
.mactable = rtl8xxxu_gen1_mac_init_table,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1660,9 +1660,9 @@ void rtl_watchdog_wq_callback(void *data)
|
|||
if (((rtlpriv->link_info.num_rx_inperiod +
|
||||
rtlpriv->link_info.num_tx_inperiod) > 8) ||
|
||||
(rtlpriv->link_info.num_rx_inperiod > 2))
|
||||
rtl_lps_enter(hw);
|
||||
else
|
||||
rtl_lps_leave(hw);
|
||||
else
|
||||
rtl_lps_enter(hw);
|
||||
}
|
||||
|
||||
rtlpriv->link_info.num_rx_inperiod = 0;
|
||||
|
|
|
@ -1572,7 +1572,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
|
|||
true,
|
||||
HW_DESC_TXBUFF_ADDR),
|
||||
skb->len, PCI_DMA_TODEVICE);
|
||||
kfree_skb(skb);
|
||||
dev_kfree_skb_irq(skb);
|
||||
ring->idx = (ring->idx + 1) % ring->entries;
|
||||
}
|
||||
ring->idx = 0;
|
||||
|
@ -2456,7 +2456,7 @@ int rtl_pci_resume(struct device *dev)
|
|||
EXPORT_SYMBOL(rtl_pci_resume);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
struct rtl_intf_ops rtl_pci_ops = {
|
||||
const struct rtl_intf_ops rtl_pci_ops = {
|
||||
.read_efuse_byte = read_efuse_byte,
|
||||
.adapter_start = rtl_pci_start,
|
||||
.adapter_stop = rtl_pci_stop,
|
||||
|
|
|
@ -286,7 +286,7 @@ struct rtl_pci_priv {
|
|||
|
||||
int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw);
|
||||
|
||||
extern struct rtl_intf_ops rtl_pci_ops;
|
||||
extern const struct rtl_intf_ops rtl_pci_ops;
|
||||
|
||||
int rtl_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id);
|
||||
|
|
|
@ -443,14 +443,10 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
|
|||
|
||||
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
|
||||
|
||||
/* Idle for a while if we connect to AP a while ago. */
|
||||
if (mac->cnt_after_linked >= 2) {
|
||||
if (ppsc->dot11_psmode == EACTIVE) {
|
||||
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
|
||||
"Enter 802.11 power save mode...\n");
|
||||
|
||||
rtl_lps_set_psmode(hw, EAUTOPS);
|
||||
}
|
||||
if (ppsc->dot11_psmode == EACTIVE) {
|
||||
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
|
||||
"Enter 802.11 power save mode...\n");
|
||||
rtl_lps_set_psmode(hw, EAUTOPS);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
|
||||
|
|
|
@ -208,8 +208,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
|
|||
"Realtek regulatory, 40MHz, writeval = 0x%x\n",
|
||||
writeval);
|
||||
} else {
|
||||
if (rtlphy->pwrgroup_cnt == 1)
|
||||
chnlgroup = 0;
|
||||
chnlgroup = 0;
|
||||
|
||||
if (rtlphy->pwrgroup_cnt >= 3) {
|
||||
if (chnl <= 3)
|
||||
|
|
|
@ -1049,7 +1049,7 @@ static void rtl_fill_h2c_cmd_work_callback(struct work_struct *work)
|
|||
rtlpriv->cfg->ops->fill_h2c_cmd(hw, H2C_RA_MASK, 5, rtlpriv->rate_mask);
|
||||
}
|
||||
|
||||
static struct rtl_intf_ops rtl_usb_ops = {
|
||||
static const struct rtl_intf_ops rtl_usb_ops = {
|
||||
.adapter_start = rtl_usb_start,
|
||||
.adapter_stop = rtl_usb_stop,
|
||||
.adapter_tx = rtl_usb_tx,
|
||||
|
|
|
@ -2593,7 +2593,7 @@ struct rtl_priv {
|
|||
*intf_ops : for diff interrface usb/pcie
|
||||
*/
|
||||
struct rtl_hal_cfg *cfg;
|
||||
struct rtl_intf_ops *intf_ops;
|
||||
const struct rtl_intf_ops *intf_ops;
|
||||
|
||||
/*this var will be set by set_bit,
|
||||
and was used to indicate status of
|
||||
|
|
|
@ -553,8 +553,8 @@ static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = {
|
|||
.size = 0x00000004
|
||||
},
|
||||
.mem3 = {
|
||||
.start = 0x00040404,
|
||||
.size = 0x00000000
|
||||
.start = 0x00000000,
|
||||
.size = 0x00040404
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -175,14 +175,25 @@ int wlcore_set_partition(struct wl1271 *wl,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* We don't need the size of the last partition, as it is
|
||||
* automatically calculated based on the total memory size and
|
||||
* the sizes of the previous partitions.
|
||||
/* wl12xx only: We don't need the size of the last partition,
|
||||
* as it is automatically calculated based on the total memory
|
||||
* size and the sizes of the previous partitions.
|
||||
*
|
||||
* wl18xx re-defines the HW_PART3 addresses for logger over
|
||||
* SDIO support. wl12xx is expecting the write to
|
||||
* HW_PART3_START_ADDR at offset 24. This creates conflict
|
||||
* between the addresses.
|
||||
* In order to fix this the expected value is written to
|
||||
* HW_PART3_SIZE_ADDR instead which is at offset 24 after changes.
|
||||
*/
|
||||
ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12)
|
||||
#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16)
|
||||
#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20)
|
||||
#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
|
||||
#define HW_PART3_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
|
||||
#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 28)
|
||||
|
||||
#define HW_ACCESS_REGISTER_SIZE 4
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4345 0x4345
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4354 0x4354
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4356 0x4356
|
||||
|
||||
#define SDIO_VENDOR_ID_INTEL 0x0089
|
||||
#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402
|
||||
|
|
Loading…
Reference in New Issue