forked from Minki/linux
wireless-drivers patches for 4.7
Major changes: iwlwifi * support for Link Quality measurement * more work 9000 devices and MSIx * continuation of the Dynamic Queue Allocation work * make the paging less memory hungry * 9000 new Rx path * removal of IWLWIFI_UAPSD Kconfig option ath10k * implement push-pull tx model using mac80211 software queuing support * enable scan in AP mode (NL80211_FEATURE_AP_SCAN) wil6210 * add basic PBSS (Personal Basic Service Set) support * add initial P2P support * add oob_mode module parameter -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJXC5ZnAAoJEG4XJFUm622bcLgIAKxTHWfcirfNpzLg39gfR/jx vWTX8YifGdZUuQuaEJhc7pPZ6eiTyMlRLZsu9JDT0LErM6uwPKSOXkogzfiSFG00 ntXGOWfQlGdyFyQshOoHWlXSkfE7bBWpLiROgk7dS2oyObQr2ETBT/yVd1bkP6Ka g13sgzM/a3CbxaZSllaK0S/YPQ6JhXlbeWotqOqE4SotYQD2QfLkYJiXSFRXNcQl OWDPCTjI3yybOVRLTnLMn2CoWrRqtUElwXaWBKJPhgY3EyxlU6R6UPw8OL8DvXIw EedpflIekKahwZJbipqdkKbhpxinUAa9kPsSkfCtlPJQWsiQvdwpG7R5KQmJ8Lc= =A2Lw -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-next-for-davem-2016-04-11' 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 * support for Link Quality measurement * more work 9000 devices and MSIx * continuation of the Dynamic Queue Allocation work * make the paging less memory hungry * 9000 new Rx path * removal of IWLWIFI_UAPSD Kconfig option ath10k * implement push-pull tx model using mac80211 software queuing support * enable scan in AP mode (NL80211_FEATURE_AP_SCAN) wil6210 * add basic PBSS (Personal Basic Service Set) support * add initial P2P support * add oob_mode module parameter ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
bddf59046d
@ -5,12 +5,18 @@ Required properties:
|
||||
* "qcom,ath10k"
|
||||
* "qcom,ipq4019-wifi"
|
||||
|
||||
PCI based devices uses compatible string "qcom,ath10k" and takes only
|
||||
calibration data via "qcom,ath10k-calibration-data". Rest of the properties
|
||||
are not applicable for PCI based devices.
|
||||
PCI based devices uses compatible string "qcom,ath10k" and takes calibration
|
||||
data along with board specific data via "qcom,ath10k-calibration-data".
|
||||
Rest of the properties are not applicable for PCI based devices.
|
||||
|
||||
AHB based devices (i.e. ipq4019) uses compatible string "qcom,ipq4019-wifi"
|
||||
and also uses most of the properties defined in this doc.
|
||||
and also uses most of the properties defined in this doc (except
|
||||
"qcom,ath10k-calibration-data"). It uses "qcom,ath10k-pre-calibration-data"
|
||||
to carry pre calibration data.
|
||||
|
||||
In general, entry "qcom,ath10k-pre-calibration-data" and
|
||||
"qcom,ath10k-calibration-data" conflict with each other and only one
|
||||
can be provided per device.
|
||||
|
||||
Optional properties:
|
||||
- reg: Address and length of the register set for the device.
|
||||
@ -35,8 +41,11 @@ Optional properties:
|
||||
- qcom,msi_addr: MSI interrupt address.
|
||||
- qcom,msi_base: Base value to add before writing MSI data into
|
||||
MSI address register.
|
||||
- qcom,ath10k-calibration-data : calibration data as an array, the
|
||||
length can vary between hw versions
|
||||
- qcom,ath10k-calibration-data : calibration data + board specific data
|
||||
as an array, the length can vary between
|
||||
hw versions.
|
||||
- qcom,ath10k-pre-calibration-data : pre calibration data as an array,
|
||||
the length can vary between hw versions.
|
||||
|
||||
Example (to supply the calibration data alone):
|
||||
|
||||
@ -105,5 +114,5 @@ wifi0: wifi@a000000 {
|
||||
"legacy";
|
||||
qcom,msi_addr = <0x0b006040>;
|
||||
qcom,msi_base = <0x40>;
|
||||
qcom,ath10k-calibration-data = [ 01 02 03 ... ];
|
||||
qcom,ath10k-pre-calibration-data = [ 01 02 03 ... ];
|
||||
};
|
||||
|
@ -411,7 +411,8 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
|
||||
|
||||
lockdep_assert_held(&ar_pci->ce_lock);
|
||||
|
||||
if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
|
||||
if ((pipe->id != 5) &&
|
||||
CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
desc->addr = __cpu_to_le32(paddr);
|
||||
@ -425,6 +426,19 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries)
|
||||
{
|
||||
struct ath10k *ar = pipe->ar;
|
||||
struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
|
||||
unsigned int nentries_mask = dest_ring->nentries_mask;
|
||||
unsigned int write_index = dest_ring->write_index;
|
||||
u32 ctrl_addr = pipe->ctrl_addr;
|
||||
|
||||
write_index = CE_RING_IDX_ADD(nentries_mask, write_index, nentries);
|
||||
ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
|
||||
dest_ring->write_index = write_index;
|
||||
}
|
||||
|
||||
int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
|
||||
{
|
||||
struct ath10k *ar = pipe->ar;
|
||||
@ -444,14 +458,10 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
|
||||
*/
|
||||
int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp,
|
||||
unsigned int *flagsp)
|
||||
unsigned int *nbytesp)
|
||||
{
|
||||
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
|
||||
unsigned int nentries_mask = dest_ring->nentries_mask;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
unsigned int sw_index = dest_ring->sw_index;
|
||||
|
||||
struct ce_desc *base = dest_ring->base_addr_owner_space;
|
||||
@ -476,21 +486,17 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
desc->nbytes = 0;
|
||||
|
||||
/* Return data from completed destination descriptor */
|
||||
*bufferp = __le32_to_cpu(sdesc.addr);
|
||||
*nbytesp = nbytes;
|
||||
*transfer_idp = MS(__le16_to_cpu(sdesc.flags), CE_DESC_FLAGS_META_DATA);
|
||||
|
||||
if (__le16_to_cpu(sdesc.flags) & CE_DESC_FLAGS_BYTE_SWAP)
|
||||
*flagsp = CE_RECV_FLAG_SWAPPED;
|
||||
else
|
||||
*flagsp = 0;
|
||||
|
||||
if (per_transfer_contextp)
|
||||
*per_transfer_contextp =
|
||||
dest_ring->per_transfer_context[sw_index];
|
||||
|
||||
/* sanity */
|
||||
dest_ring->per_transfer_context[sw_index] = NULL;
|
||||
/* Copy engine 5 (HTT Rx) will reuse the same transfer context.
|
||||
* So update transfer context all CEs except CE5.
|
||||
*/
|
||||
if (ce_state->id != 5)
|
||||
dest_ring->per_transfer_context[sw_index] = NULL;
|
||||
|
||||
/* Update sw_index */
|
||||
sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
|
||||
@ -501,10 +507,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
|
||||
int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp,
|
||||
unsigned int *flagsp)
|
||||
unsigned int *nbytesp)
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
@ -513,8 +516,7 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
ret = ath10k_ce_completed_recv_next_nolock(ce_state,
|
||||
per_transfer_contextp,
|
||||
bufferp, nbytesp,
|
||||
transfer_idp, flagsp);
|
||||
nbytesp);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
/* Maximum number of Copy Engine's supported */
|
||||
#define CE_COUNT_MAX 12
|
||||
#define CE_HTT_H2T_MSG_SRC_NENTRIES 4096
|
||||
#define CE_HTT_H2T_MSG_SRC_NENTRIES 8192
|
||||
|
||||
/* Descriptor rings must be aligned to this boundary */
|
||||
#define CE_DESC_RING_ALIGN 8
|
||||
@ -166,6 +166,7 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
|
||||
int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
|
||||
int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
|
||||
int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
|
||||
void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries);
|
||||
|
||||
/* recv flags */
|
||||
/* Data is byte-swapped */
|
||||
@ -177,10 +178,7 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
|
||||
*/
|
||||
int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp,
|
||||
unsigned int *flagsp);
|
||||
unsigned int *nbytesp);
|
||||
/*
|
||||
* Supply data for the next completed unprocessed send descriptor.
|
||||
* Pops 1 completed send buffer from Source ring.
|
||||
@ -212,10 +210,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
|
||||
int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp,
|
||||
unsigned int *flagsp);
|
||||
unsigned int *nbytesp);
|
||||
|
||||
/*
|
||||
* Support clean shutdown by allowing the caller to cancel
|
||||
@ -416,6 +411,8 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
|
||||
(((int)(toidx)-(int)(fromidx)) & (nentries_mask))
|
||||
|
||||
#define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask))
|
||||
#define CE_RING_IDX_ADD(nentries_mask, idx, num) \
|
||||
(((idx) + (num)) & (nentries_mask))
|
||||
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \
|
||||
ar->regs->ce_wrap_intr_sum_host_msi_lsb
|
||||
|
@ -60,6 +60,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
|
||||
.cal_data_len = 2116,
|
||||
.fw = {
|
||||
.dir = QCA988X_HW_2_0_FW_DIR,
|
||||
.fw = QCA988X_HW_2_0_FW_FILE,
|
||||
@ -78,6 +79,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.cal_data_len = 8124,
|
||||
.fw = {
|
||||
.dir = QCA6174_HW_2_1_FW_DIR,
|
||||
.fw = QCA6174_HW_2_1_FW_FILE,
|
||||
@ -97,6 +99,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
|
||||
.cal_data_len = 8124,
|
||||
.fw = {
|
||||
.dir = QCA6174_HW_2_1_FW_DIR,
|
||||
.fw = QCA6174_HW_2_1_FW_FILE,
|
||||
@ -116,6 +119,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
|
||||
.cal_data_len = 8124,
|
||||
.fw = {
|
||||
.dir = QCA6174_HW_3_0_FW_DIR,
|
||||
.fw = QCA6174_HW_3_0_FW_FILE,
|
||||
@ -135,6 +139,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
|
||||
.cal_data_len = 8124,
|
||||
.fw = {
|
||||
/* uses same binaries as hw3.0 */
|
||||
.dir = QCA6174_HW_3_0_FW_DIR,
|
||||
@ -156,11 +161,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.channel_counters_freq_hz = 150000,
|
||||
.max_probe_resp_desc_thres = 24,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
|
||||
.num_msdu_desc = 1424,
|
||||
.qcache_active_peers = 50,
|
||||
.tx_chain_mask = 0xf,
|
||||
.rx_chain_mask = 0xf,
|
||||
.max_spatial_stream = 4,
|
||||
.cal_data_len = 12064,
|
||||
.fw = {
|
||||
.dir = QCA99X0_HW_2_0_FW_DIR,
|
||||
.fw = QCA99X0_HW_2_0_FW_FILE,
|
||||
@ -179,6 +183,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.cal_data_len = 8124,
|
||||
.fw = {
|
||||
.dir = QCA9377_HW_1_0_FW_DIR,
|
||||
.fw = QCA9377_HW_1_0_FW_FILE,
|
||||
@ -197,6 +202,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.otp_exe_param = 0,
|
||||
.channel_counters_freq_hz = 88000,
|
||||
.max_probe_resp_desc_thres = 0,
|
||||
.cal_data_len = 8124,
|
||||
.fw = {
|
||||
.dir = QCA9377_HW_1_0_FW_DIR,
|
||||
.fw = QCA9377_HW_1_0_FW_FILE,
|
||||
@ -217,11 +223,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.channel_counters_freq_hz = 125000,
|
||||
.max_probe_resp_desc_thres = 24,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
|
||||
.num_msdu_desc = 2500,
|
||||
.qcache_active_peers = 35,
|
||||
.tx_chain_mask = 0x3,
|
||||
.rx_chain_mask = 0x3,
|
||||
.max_spatial_stream = 2,
|
||||
.cal_data_len = 12064,
|
||||
.fw = {
|
||||
.dir = QCA4019_HW_1_0_FW_DIR,
|
||||
.fw = QCA4019_HW_1_0_FW_FILE,
|
||||
@ -466,18 +471,18 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_download_cal_file(struct ath10k *ar)
|
||||
static int ath10k_download_cal_file(struct ath10k *ar,
|
||||
const struct firmware *file)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!ar->cal_file)
|
||||
if (!file)
|
||||
return -ENOENT;
|
||||
|
||||
if (IS_ERR(ar->cal_file))
|
||||
return PTR_ERR(ar->cal_file);
|
||||
if (IS_ERR(file))
|
||||
return PTR_ERR(file);
|
||||
|
||||
ret = ath10k_download_board_data(ar, ar->cal_file->data,
|
||||
ar->cal_file->size);
|
||||
ret = ath10k_download_board_data(ar, file->data, file->size);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
|
||||
return ret;
|
||||
@ -488,7 +493,7 @@ static int ath10k_download_cal_file(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_download_cal_dt(struct ath10k *ar)
|
||||
static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)
|
||||
{
|
||||
struct device_node *node;
|
||||
int data_len;
|
||||
@ -502,13 +507,12 @@ static int ath10k_download_cal_dt(struct ath10k *ar)
|
||||
*/
|
||||
return -ENOENT;
|
||||
|
||||
if (!of_get_property(node, "qcom,ath10k-calibration-data",
|
||||
&data_len)) {
|
||||
if (!of_get_property(node, dt_name, &data_len)) {
|
||||
/* The calibration data node is optional */
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (data_len != QCA988X_CAL_DATA_LEN) {
|
||||
if (data_len != ar->hw_params.cal_data_len) {
|
||||
ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
|
||||
data_len);
|
||||
ret = -EMSGSIZE;
|
||||
@ -521,8 +525,7 @@ static int ath10k_download_cal_dt(struct ath10k *ar)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
|
||||
data, data_len);
|
||||
ret = of_property_read_u8_array(node, dt_name, data, data_len);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
|
||||
ret);
|
||||
@ -726,6 +729,14 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
|
||||
{
|
||||
char filename[100];
|
||||
|
||||
/* pre-cal-<bus>-<id>.bin */
|
||||
scnprintf(filename, sizeof(filename), "pre-cal-%s-%s.bin",
|
||||
ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
|
||||
|
||||
ar->pre_cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);
|
||||
if (!IS_ERR(ar->pre_cal_file))
|
||||
goto success;
|
||||
|
||||
/* cal-<bus>-<id>.bin */
|
||||
scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",
|
||||
ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
|
||||
@ -734,7 +745,7 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
|
||||
if (IS_ERR(ar->cal_file))
|
||||
/* calibration file is optional, don't print any warnings */
|
||||
return PTR_ERR(ar->cal_file);
|
||||
|
||||
success:
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",
|
||||
ATH10K_FW_DIR, filename);
|
||||
|
||||
@ -1258,11 +1269,77 @@ success:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_pre_cal_download(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ath10k_download_cal_file(ar, ar->pre_cal_file);
|
||||
if (ret == 0) {
|
||||
ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE;
|
||||
goto success;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"boot did not find a pre calibration file, try DT next: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,ath10k-pre-calibration-data");
|
||||
if (ret) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"unable to load pre cal data from DT: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ar->cal_mode = ATH10K_PRE_CAL_MODE_DT;
|
||||
|
||||
success:
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",
|
||||
ath10k_cal_mode_str(ar->cal_mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_pre_cal_config(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ath10k_core_pre_cal_download(ar);
|
||||
if (ret) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"failed to load pre cal data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_core_get_board_id_from_otp(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to get board id: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_download_and_run_otp(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to run otp: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"pre cal configuration done successfully\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_download_cal_data(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ath10k_download_cal_file(ar);
|
||||
ret = ath10k_core_pre_cal_config(ar);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"pre cal download procedure failed, try cal file: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_download_cal_file(ar, ar->cal_file);
|
||||
if (ret == 0) {
|
||||
ar->cal_mode = ATH10K_CAL_MODE_FILE;
|
||||
goto done;
|
||||
@ -1272,7 +1349,7 @@ static int ath10k_download_cal_data(struct ath10k *ar)
|
||||
"boot did not find a calibration file, try DT next: %d\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_download_cal_dt(ar);
|
||||
ret = ath10k_download_cal_dt(ar, "qcom,ath10k-calibration-data");
|
||||
if (ret == 0) {
|
||||
ar->cal_mode = ATH10K_CAL_MODE_DT;
|
||||
goto done;
|
||||
@ -1509,7 +1586,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_1:
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_2:
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
|
||||
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
|
||||
if (ath10k_peer_stats_enabled(ar)) {
|
||||
ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
|
||||
ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;
|
||||
} else {
|
||||
@ -1538,9 +1615,15 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;
|
||||
ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
|
||||
ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;
|
||||
ar->htt.max_num_pending_tx = ar->hw_params.num_msdu_desc;
|
||||
ar->fw_stats_req_mask = WMI_STAT_PEER;
|
||||
ar->fw_stats_req_mask = WMI_10_4_STAT_PEER |
|
||||
WMI_10_4_STAT_PEER_EXTD;
|
||||
ar->max_spatial_stream = ar->hw_params.max_spatial_stream;
|
||||
|
||||
if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
|
||||
ar->fw_features))
|
||||
ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC_PFC;
|
||||
else
|
||||
ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_UNSET:
|
||||
case ATH10K_FW_WMI_OP_VERSION_MAX:
|
||||
@ -1578,6 +1661,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
{
|
||||
int status;
|
||||
u32 val;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
@ -1698,6 +1782,21 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
|
||||
ar->hw->wiphy->fw_version);
|
||||
|
||||
if (test_bit(WMI_SERVICE_EXT_RES_CFG_SUPPORT, ar->wmi.svc_map)) {
|
||||
val = 0;
|
||||
if (ath10k_peer_stats_enabled(ar))
|
||||
val = WMI_10_4_PEER_STATS;
|
||||
|
||||
status = ath10k_wmi_ext_resource_config(ar,
|
||||
WMI_HOST_PLATFORM_HIGH_PERF, val);
|
||||
if (status) {
|
||||
ath10k_err(ar,
|
||||
"failed to send ext resource cfg command : %d\n",
|
||||
status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
}
|
||||
|
||||
status = ath10k_wmi_cmd_init(ar);
|
||||
if (status) {
|
||||
ath10k_err(ar, "could not send WMI init command (%d)\n",
|
||||
@ -1834,11 +1933,20 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
||||
|
||||
ath10k_debug_print_hwfw_info(ar);
|
||||
|
||||
ret = ath10k_core_pre_cal_download(ar);
|
||||
if (ret) {
|
||||
/* pre calibration data download is not necessary
|
||||
* for all the chipsets. Ignore failures and continue.
|
||||
*/
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"could not load pre cal data: %d\n", ret);
|
||||
}
|
||||
|
||||
ret = ath10k_core_get_board_id_from_otp(ar);
|
||||
if (ret && ret != -EOPNOTSUPP) {
|
||||
ath10k_err(ar, "failed to get board id from otp: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
goto err_free_firmware_files;
|
||||
}
|
||||
|
||||
ret = ath10k_core_fetch_board_file(ar);
|
||||
@ -2048,7 +2156,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
spin_lock_init(&ar->txqs_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar->txqs);
|
||||
INIT_LIST_HEAD(&ar->peers);
|
||||
init_waitqueue_head(&ar->peer_mapping_wq);
|
||||
init_waitqueue_head(&ar->htt.empty_tx_wq);
|
||||
|
@ -98,6 +98,7 @@ struct ath10k_skb_cb {
|
||||
u8 eid;
|
||||
u16 msdu_id;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_txq *txq;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_skb_rxcb {
|
||||
@ -297,6 +298,9 @@ struct ath10k_dfs_stats {
|
||||
|
||||
struct ath10k_peer {
|
||||
struct list_head list;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
int vdev_id;
|
||||
u8 addr[ETH_ALEN];
|
||||
DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
|
||||
@ -305,6 +309,12 @@ struct ath10k_peer {
|
||||
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
|
||||
};
|
||||
|
||||
struct ath10k_txq {
|
||||
struct list_head list;
|
||||
unsigned long num_fw_queued;
|
||||
unsigned long num_push_allowed;
|
||||
};
|
||||
|
||||
struct ath10k_sta {
|
||||
struct ath10k_vif *arvif;
|
||||
|
||||
@ -313,6 +323,7 @@ struct ath10k_sta {
|
||||
u32 bw;
|
||||
u32 nss;
|
||||
u32 smps;
|
||||
u16 peer_id;
|
||||
|
||||
struct work_struct update_wk;
|
||||
|
||||
@ -335,6 +346,7 @@ struct ath10k_vif {
|
||||
struct list_head list;
|
||||
|
||||
u32 vdev_id;
|
||||
u16 peer_id;
|
||||
enum wmi_vdev_type vdev_type;
|
||||
enum wmi_vdev_subtype vdev_subtype;
|
||||
u32 beacon_interval;
|
||||
@ -549,12 +561,17 @@ enum ath10k_dev_flags {
|
||||
|
||||
/* Bluetooth coexistance enabled */
|
||||
ATH10K_FLAG_BTCOEX,
|
||||
|
||||
/* Per Station statistics service */
|
||||
ATH10K_FLAG_PEER_STATS,
|
||||
};
|
||||
|
||||
enum ath10k_cal_mode {
|
||||
ATH10K_CAL_MODE_FILE,
|
||||
ATH10K_CAL_MODE_OTP,
|
||||
ATH10K_CAL_MODE_DT,
|
||||
ATH10K_PRE_CAL_MODE_FILE,
|
||||
ATH10K_PRE_CAL_MODE_DT,
|
||||
};
|
||||
|
||||
enum ath10k_crypt_mode {
|
||||
@ -573,6 +590,10 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
|
||||
return "otp";
|
||||
case ATH10K_CAL_MODE_DT:
|
||||
return "dt";
|
||||
case ATH10K_PRE_CAL_MODE_FILE:
|
||||
return "pre-cal-file";
|
||||
case ATH10K_PRE_CAL_MODE_DT:
|
||||
return "pre-cal-dt";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
@ -680,11 +701,10 @@ struct ath10k {
|
||||
/* The padding bytes's location is different on various chips */
|
||||
enum ath10k_hw_4addr_pad hw_4addr_pad;
|
||||
|
||||
u32 num_msdu_desc;
|
||||
u32 qcache_active_peers;
|
||||
u32 tx_chain_mask;
|
||||
u32 rx_chain_mask;
|
||||
u32 max_spatial_stream;
|
||||
u32 cal_data_len;
|
||||
|
||||
struct ath10k_hw_params_fw {
|
||||
const char *dir;
|
||||
@ -708,6 +728,7 @@ struct ath10k {
|
||||
const void *firmware_data;
|
||||
size_t firmware_len;
|
||||
|
||||
const struct firmware *pre_cal_file;
|
||||
const struct firmware *cal_file;
|
||||
|
||||
struct {
|
||||
@ -756,6 +777,9 @@ struct ath10k {
|
||||
/* current operating channel definition */
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
/* currently configured operating channel in firmware */
|
||||
struct ieee80211_channel *tgt_oper_chan;
|
||||
|
||||
unsigned long long free_vdev_map;
|
||||
struct ath10k_vif *monitor_arvif;
|
||||
bool monitor;
|
||||
@ -786,9 +810,13 @@ struct ath10k {
|
||||
|
||||
/* protects shared structure data */
|
||||
spinlock_t data_lock;
|
||||
/* protects: ar->txqs, artxq->list */
|
||||
spinlock_t txqs_lock;
|
||||
|
||||
struct list_head txqs;
|
||||
struct list_head arvifs;
|
||||
struct list_head peers;
|
||||
struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS];
|
||||
wait_queue_head_t peer_mapping_wq;
|
||||
|
||||
/* protected by conf_mutex */
|
||||
@ -876,6 +904,15 @@ struct ath10k {
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
||||
static inline bool ath10k_peer_stats_enabled(struct ath10k *ar)
|
||||
{
|
||||
if (test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) &&
|
||||
test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
enum ath10k_bus bus,
|
||||
enum ath10k_hw_rev hw_rev,
|
||||
|
@ -127,6 +127,7 @@ EXPORT_SYMBOL(ath10k_info);
|
||||
void ath10k_debug_print_hwfw_info(struct ath10k *ar)
|
||||
{
|
||||
char fw_features[128] = {};
|
||||
u32 crc = 0;
|
||||
|
||||
ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));
|
||||
|
||||
@ -143,11 +144,14 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar)
|
||||
config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
|
||||
config_enabled(CONFIG_NL80211_TESTMODE));
|
||||
|
||||
if (ar->firmware)
|
||||
crc = crc32_le(0, ar->firmware->data, ar->firmware->size);
|
||||
|
||||
ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",
|
||||
ar->hw->wiphy->fw_version,
|
||||
ar->fw_api,
|
||||
fw_features,
|
||||
crc32_le(0, ar->firmware->data, ar->firmware->size));
|
||||
crc);
|
||||
}
|
||||
|
||||
void ath10k_debug_print_board_info(struct ath10k *ar)
|
||||
@ -319,7 +323,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
|
||||
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_fw_stats stats = {};
|
||||
bool is_start, is_started, is_end, peer_stats_svc;
|
||||
bool is_start, is_started, is_end;
|
||||
size_t num_peers;
|
||||
size_t num_vdevs;
|
||||
int ret;
|
||||
@ -346,13 +350,11 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
* b) consume stat update events until another one with pdev stats is
|
||||
* delivered which is treated as end-of-data and is itself discarded
|
||||
*/
|
||||
|
||||
peer_stats_svc = test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map);
|
||||
if (peer_stats_svc)
|
||||
if (ath10k_peer_stats_enabled(ar))
|
||||
ath10k_sta_update_rx_duration(ar, &stats.peers);
|
||||
|
||||
if (ar->debug.fw_stats_done) {
|
||||
if (!peer_stats_svc)
|
||||
if (!ath10k_peer_stats_enabled(ar))
|
||||
ath10k_warn(ar, "received unsolicited stats update event\n");
|
||||
|
||||
goto free;
|
||||
@ -1447,7 +1449,7 @@ static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
|
||||
goto err;
|
||||
}
|
||||
|
||||
buf = vmalloc(QCA988X_CAL_DATA_LEN);
|
||||
buf = vmalloc(ar->hw_params.cal_data_len);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
@ -1462,7 +1464,7 @@ static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf,
|
||||
QCA988X_CAL_DATA_LEN);
|
||||
ar->hw_params.cal_data_len);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
|
||||
goto err_vfree;
|
||||
@ -1487,10 +1489,11 @@ static ssize_t ath10k_debug_cal_data_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
void *buf = file->private_data;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
buf, QCA988X_CAL_DATA_LEN);
|
||||
buf, ar->hw_params.cal_data_len);
|
||||
}
|
||||
|
||||
static int ath10k_debug_cal_data_release(struct inode *inode,
|
||||
@ -2019,7 +2022,12 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (filter && (filter != ar->debug.pktlog_filter)) {
|
||||
if (filter == ar->debug.pktlog_filter) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
|
||||
@ -2174,6 +2182,73 @@ static const struct file_operations fops_btcoex = {
|
||||
.open = simple_open
|
||||
};
|
||||
|
||||
static ssize_t ath10k_write_peer_stats(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
size_t buf_size;
|
||||
int ret = 0;
|
||||
bool val;
|
||||
|
||||
buf_size = min(count, (sizeof(buf) - 1));
|
||||
if (copy_from_user(buf, ubuf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
buf[buf_size] = '\0';
|
||||
|
||||
if (strtobool(buf, &val) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON &&
|
||||
ar->state != ATH10K_STATE_RESTARTED) {
|
||||
ret = -ENETDOWN;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val))
|
||||
goto exit;
|
||||
|
||||
if (val)
|
||||
set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
|
||||
else
|
||||
clear_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
|
||||
|
||||
ath10k_info(ar, "restarting firmware due to Peer stats change");
|
||||
|
||||
queue_work(ar->workqueue, &ar->restart_work);
|
||||
ret = count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_read_peer_stats(struct file *file, char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
||||
{
|
||||
char buf[32];
|
||||
struct ath10k *ar = file->private_data;
|
||||
int len = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
||||
test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags));
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_peer_stats = {
|
||||
.read = ath10k_read_peer_stats,
|
||||
.write = ath10k_write_peer_stats,
|
||||
.open = simple_open
|
||||
};
|
||||
|
||||
static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@ -2337,6 +2412,11 @@ int ath10k_debug_register(struct ath10k *ar)
|
||||
debugfs_create_file("btcoex", S_IRUGO | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_btcoex);
|
||||
|
||||
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
|
||||
debugfs_create_file("peer_stats", S_IRUGO | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
&fops_peer_stats);
|
||||
|
||||
debugfs_create_file("fw_checksums", S_IRUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_fw_checksums);
|
||||
|
||||
|
@ -149,7 +149,7 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
memset(&conn_resp, 0, sizeof(conn_resp));
|
||||
|
||||
conn_req.ep_ops.ep_tx_complete = ath10k_htt_htc_tx_complete;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htt_t2h_msg_handler;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htt_htc_t2h_msg_handler;
|
||||
|
||||
/* connect to control service */
|
||||
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "htc.h"
|
||||
@ -1461,6 +1462,14 @@ struct htt_tx_mode_switch_ind {
|
||||
struct htt_tx_mode_switch_record records[0];
|
||||
} __packed;
|
||||
|
||||
struct htt_channel_change {
|
||||
u8 pad[3];
|
||||
__le32 freq;
|
||||
__le32 center_freq1;
|
||||
__le32 center_freq2;
|
||||
__le32 phymode;
|
||||
} __packed;
|
||||
|
||||
union htt_rx_pn_t {
|
||||
/* WEP: 24-bit PN */
|
||||
u32 pn24;
|
||||
@ -1511,16 +1520,22 @@ struct htt_resp {
|
||||
struct htt_tx_fetch_ind tx_fetch_ind;
|
||||
struct htt_tx_fetch_confirm tx_fetch_confirm;
|
||||
struct htt_tx_mode_switch_ind tx_mode_switch_ind;
|
||||
struct htt_channel_change chan_change;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*** host side structures follow ***/
|
||||
|
||||
struct htt_tx_done {
|
||||
u32 msdu_id;
|
||||
bool discard;
|
||||
bool no_ack;
|
||||
bool success;
|
||||
u16 msdu_id;
|
||||
u16 status;
|
||||
};
|
||||
|
||||
enum htt_tx_compl_state {
|
||||
HTT_TX_COMPL_STATE_NONE,
|
||||
HTT_TX_COMPL_STATE_ACK,
|
||||
HTT_TX_COMPL_STATE_NOACK,
|
||||
HTT_TX_COMPL_STATE_DISCARD,
|
||||
};
|
||||
|
||||
struct htt_peer_map_event {
|
||||
@ -1641,17 +1656,20 @@ struct ath10k_htt {
|
||||
struct idr pending_tx;
|
||||
wait_queue_head_t empty_tx_wq;
|
||||
|
||||
/* FIFO for storing tx done status {ack, no-ack, discard} and msdu id */
|
||||
DECLARE_KFIFO_PTR(txdone_fifo, struct htt_tx_done);
|
||||
|
||||
/* set if host-fw communication goes haywire
|
||||
* used to avoid further failures */
|
||||
bool rx_confused;
|
||||
struct tasklet_struct rx_replenish_task;
|
||||
atomic_t num_mpdus_ready;
|
||||
|
||||
/* This is used to group tx/rx completions separately and process them
|
||||
* in batches to reduce cache stalls */
|
||||
struct tasklet_struct txrx_compl_task;
|
||||
struct sk_buff_head tx_compl_q;
|
||||
struct sk_buff_head rx_compl_q;
|
||||
struct sk_buff_head rx_in_ord_compl_q;
|
||||
struct sk_buff_head tx_fetch_ind_q;
|
||||
|
||||
/* rx_status template */
|
||||
struct ieee80211_rx_status rx_status;
|
||||
@ -1667,10 +1685,13 @@ struct ath10k_htt {
|
||||
} txbuf;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
struct htt_q_state *vaddr;
|
||||
dma_addr_t paddr;
|
||||
u16 num_push_allowed;
|
||||
u16 num_peers;
|
||||
u16 num_tids;
|
||||
enum htt_tx_mode_switch_mode mode;
|
||||
enum htt_q_depth_type type;
|
||||
} tx_q_state;
|
||||
};
|
||||
@ -1715,7 +1736,7 @@ struct htt_rx_desc {
|
||||
|
||||
/* Refill a bunch of RX buffers for each refill round so that FW/HW can handle
|
||||
* aggregated traffic more nicely. */
|
||||
#define ATH10K_HTT_MAX_NUM_REFILL 16
|
||||
#define ATH10K_HTT_MAX_NUM_REFILL 100
|
||||
|
||||
/*
|
||||
* DMA_MAP expects the buffer to be an integral number of cache lines.
|
||||
@ -1743,7 +1764,8 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar);
|
||||
void ath10k_htt_rx_free(struct ath10k_htt *htt);
|
||||
|
||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
|
||||
int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
|
||||
int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt);
|
||||
@ -1752,8 +1774,23 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
|
||||
u8 max_subfrms_ampdu,
|
||||
u8 max_subfrms_amsdu);
|
||||
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
|
||||
__le32 token,
|
||||
__le16 fetch_seq_num,
|
||||
struct htt_tx_fetch_record *records,
|
||||
size_t num_records);
|
||||
|
||||
void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq);
|
||||
void ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq);
|
||||
void ath10k_htt_tx_txq_sync(struct ath10k *ar);
|
||||
void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
|
||||
int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt);
|
||||
int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
|
||||
bool is_presp);
|
||||
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc);
|
||||
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
|
||||
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
|
||||
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
|
||||
|
@ -31,6 +31,8 @@
|
||||
/* when under memory pressure rx ring refill may fail and needs a retry */
|
||||
#define HTT_RX_RING_REFILL_RETRY_MS 50
|
||||
|
||||
#define HTT_RX_RING_REFILL_RESCHED_MS 5
|
||||
|
||||
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
|
||||
static void ath10k_htt_txrx_compl_task(unsigned long ptr);
|
||||
|
||||
@ -192,7 +194,8 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
|
||||
mod_timer(&htt->rx_ring.refill_retry_timer, jiffies +
|
||||
msecs_to_jiffies(HTT_RX_RING_REFILL_RETRY_MS));
|
||||
} else if (num_deficit > 0) {
|
||||
tasklet_schedule(&htt->rx_replenish_task);
|
||||
mod_timer(&htt->rx_ring.refill_retry_timer, jiffies +
|
||||
msecs_to_jiffies(HTT_RX_RING_REFILL_RESCHED_MS));
|
||||
}
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
}
|
||||
@ -223,12 +226,11 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar)
|
||||
void ath10k_htt_rx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
del_timer_sync(&htt->rx_ring.refill_retry_timer);
|
||||
tasklet_kill(&htt->rx_replenish_task);
|
||||
tasklet_kill(&htt->txrx_compl_task);
|
||||
|
||||
skb_queue_purge(&htt->tx_compl_q);
|
||||
skb_queue_purge(&htt->rx_compl_q);
|
||||
skb_queue_purge(&htt->rx_in_ord_compl_q);
|
||||
skb_queue_purge(&htt->tx_fetch_ind_q);
|
||||
|
||||
ath10k_htt_rx_ring_free(htt);
|
||||
|
||||
@ -281,7 +283,6 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
|
||||
|
||||
/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
|
||||
static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
u8 **fw_desc, int *fw_desc_len,
|
||||
struct sk_buff_head *amsdu)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
@ -323,48 +324,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the FW rx descriptor for this MSDU from the rx
|
||||
* indication message into the MSDU's netbuf. HL uses the
|
||||
* same rx indication message definition as LL, and simply
|
||||
* appends new info (fields from the HW rx desc, and the
|
||||
* MSDU payload itself). So, the offset into the rx
|
||||
* indication message only has to account for the standard
|
||||
* offset of the per-MSDU FW rx desc info within the
|
||||
* message, and how many bytes of the per-MSDU FW rx desc
|
||||
* info have already been consumed. (And the endianness of
|
||||
* the host, since for a big-endian host, the rx ind
|
||||
* message contents, including the per-MSDU rx desc bytes,
|
||||
* were byteswapped during upload.)
|
||||
*/
|
||||
if (*fw_desc_len > 0) {
|
||||
rx_desc->fw_desc.info0 = **fw_desc;
|
||||
/*
|
||||
* The target is expected to only provide the basic
|
||||
* per-MSDU rx descriptors. Just to be sure, verify
|
||||
* that the target has not attached extension data
|
||||
* (e.g. LRO flow ID).
|
||||
*/
|
||||
|
||||
/* or more, if there's extension data */
|
||||
(*fw_desc)++;
|
||||
(*fw_desc_len)--;
|
||||
} else {
|
||||
/*
|
||||
* When an oversized AMSDU happened, FW will lost
|
||||
* some of MSDU status - in this case, the FW
|
||||
* descriptors provided will be less than the
|
||||
* actual MSDUs inside this MPDU. Mark the FW
|
||||
* descriptors so that it will still deliver to
|
||||
* upper stack, if no CRC error for this MPDU.
|
||||
*
|
||||
* FIX THIS - the FW descriptors are actually for
|
||||
* MSDUs in the end of this A-MSDU instead of the
|
||||
* beginning.
|
||||
*/
|
||||
rx_desc->fw_desc.info0 = 0;
|
||||
}
|
||||
|
||||
msdu_len_invalid = !!(__le32_to_cpu(rx_desc->attention.flags)
|
||||
& (RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR |
|
||||
RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR));
|
||||
@ -423,13 +382,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
return msdu_chaining;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_replenish_task(unsigned long ptr)
|
||||
{
|
||||
struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
|
||||
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
||||
static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt,
|
||||
u32 paddr)
|
||||
{
|
||||
@ -563,12 +515,10 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
|
||||
htt->rx_ring.sw_rd_idx.msdu_payld = 0;
|
||||
hash_init(htt->rx_ring.skb_table);
|
||||
|
||||
tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
|
||||
(unsigned long)htt);
|
||||
|
||||
skb_queue_head_init(&htt->tx_compl_q);
|
||||
skb_queue_head_init(&htt->rx_compl_q);
|
||||
skb_queue_head_init(&htt->rx_in_ord_compl_q);
|
||||
skb_queue_head_init(&htt->tx_fetch_ind_q);
|
||||
atomic_set(&htt->num_mpdus_ready, 0);
|
||||
|
||||
tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
|
||||
(unsigned long)htt);
|
||||
@ -860,6 +810,8 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
|
||||
ch = ath10k_htt_rx_h_vdev_channel(ar, vdev_id);
|
||||
if (!ch)
|
||||
ch = ath10k_htt_rx_h_any_channel(ar);
|
||||
if (!ch)
|
||||
ch = ar->tgt_oper_chan;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!ch)
|
||||
@ -1076,20 +1028,25 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
|
||||
hdr = (void *)msdu->data;
|
||||
|
||||
/* Tail */
|
||||
skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype));
|
||||
if (status->flag & RX_FLAG_IV_STRIPPED)
|
||||
skb_trim(msdu, msdu->len -
|
||||
ath10k_htt_rx_crypto_tail_len(ar, enctype));
|
||||
|
||||
/* MMIC */
|
||||
if (!ieee80211_has_morefrags(hdr->frame_control) &&
|
||||
if ((status->flag & RX_FLAG_MMIC_STRIPPED) &&
|
||||
!ieee80211_has_morefrags(hdr->frame_control) &&
|
||||
enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
|
||||
skb_trim(msdu, msdu->len - 8);
|
||||
|
||||
/* Head */
|
||||
hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
||||
crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
|
||||
if (status->flag & RX_FLAG_IV_STRIPPED) {
|
||||
hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
||||
crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
|
||||
|
||||
memmove((void *)msdu->data + crypto_len,
|
||||
(void *)msdu->data, hdr_len);
|
||||
skb_pull(msdu, crypto_len);
|
||||
memmove((void *)msdu->data + crypto_len,
|
||||
(void *)msdu->data, hdr_len);
|
||||
skb_pull(msdu, crypto_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
|
||||
@ -1343,6 +1300,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
bool has_tkip_err;
|
||||
bool has_peer_idx_invalid;
|
||||
bool is_decrypted;
|
||||
bool is_mgmt;
|
||||
u32 attention;
|
||||
|
||||
if (skb_queue_empty(amsdu))
|
||||
@ -1351,6 +1309,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
first = skb_peek(amsdu);
|
||||
rxd = (void *)first->data - sizeof(*rxd);
|
||||
|
||||
is_mgmt = !!(rxd->attention.flags &
|
||||
__cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
|
||||
|
||||
enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
RX_MPDU_START_INFO0_ENCRYPT_TYPE);
|
||||
|
||||
@ -1392,6 +1353,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
RX_FLAG_MMIC_ERROR |
|
||||
RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_ONLY_MONITOR |
|
||||
RX_FLAG_MMIC_STRIPPED);
|
||||
|
||||
if (has_fcs_err)
|
||||
@ -1400,10 +1362,21 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
if (has_tkip_err)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (is_decrypted)
|
||||
status->flag |= RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
/* Firmware reports all necessary management frames via WMI already.
|
||||
* They are not reported to monitor interfaces at all so pass the ones
|
||||
* coming via HTT to monitor interfaces instead. This simplifies
|
||||
* matters a lot.
|
||||
*/
|
||||
if (is_mgmt)
|
||||
status->flag |= RX_FLAG_ONLY_MONITOR;
|
||||
|
||||
if (is_decrypted) {
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
if (likely(!is_mgmt))
|
||||
status->flag |= RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
}
|
||||
|
||||
skb_queue_walk(amsdu, msdu) {
|
||||
ath10k_htt_rx_h_csum_offload(msdu);
|
||||
@ -1416,6 +1389,8 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
*/
|
||||
if (!is_decrypted)
|
||||
continue;
|
||||
if (is_mgmt)
|
||||
continue;
|
||||
|
||||
hdr = (void *)msdu->data;
|
||||
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
@ -1516,14 +1491,6 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct sk_buff *msdu;
|
||||
struct htt_rx_desc *rxd;
|
||||
bool is_mgmt;
|
||||
bool has_fcs_err;
|
||||
|
||||
msdu = skb_peek(amsdu);
|
||||
rxd = (void *)msdu->data - sizeof(*rxd);
|
||||
|
||||
/* FIXME: It might be a good idea to do some fuzzy-testing to drop
|
||||
* invalid/dangerous frames.
|
||||
*/
|
||||
@ -1533,23 +1500,6 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
|
||||
return false;
|
||||
}
|
||||
|
||||
is_mgmt = !!(rxd->attention.flags &
|
||||
__cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
|
||||
has_fcs_err = !!(rxd->attention.flags &
|
||||
__cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
|
||||
|
||||
/* Management frames are handled via WMI events. The pros of such
|
||||
* approach is that channel is explicitly provided in WMI events
|
||||
* whereas HTT doesn't provide channel information for Rxed frames.
|
||||
*
|
||||
* However some firmware revisions don't report corrupted frames via
|
||||
* WMI so don't drop them.
|
||||
*/
|
||||
if (is_mgmt && !has_fcs_err) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n");
|
||||
return false;
|
||||
@ -1571,25 +1521,49 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar,
|
||||
__skb_queue_purge(amsdu);
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
||||
struct htt_rx_indication *rx)
|
||||
static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
||||
struct htt_rx_indication_mpdu_range *mpdu_ranges;
|
||||
static struct ieee80211_rx_status rx_status;
|
||||
struct sk_buff_head amsdu;
|
||||
int ret;
|
||||
|
||||
__skb_queue_head_init(&amsdu);
|
||||
|
||||
spin_lock_bh(&htt->rx_ring.lock);
|
||||
if (htt->rx_confused) {
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
return -EIO;
|
||||
}
|
||||
ret = ath10k_htt_rx_amsdu_pop(htt, &amsdu);
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
|
||||
if (ret < 0) {
|
||||
ath10k_warn(ar, "rx ring became corrupted: %d\n", ret);
|
||||
__skb_queue_purge(&amsdu);
|
||||
/* FIXME: It's probably a good idea to reboot the
|
||||
* device instead of leaving it inoperable.
|
||||
*/
|
||||
htt->rx_confused = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, &rx_status, 0xffff);
|
||||
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, &rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, &rx_status);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, &rx_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
|
||||
struct htt_rx_indication *rx)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct htt_rx_indication_mpdu_range *mpdu_ranges;
|
||||
int num_mpdu_ranges;
|
||||
int fw_desc_len;
|
||||
u8 *fw_desc;
|
||||
int i, ret, mpdu_count = 0;
|
||||
|
||||
lockdep_assert_held(&htt->rx_ring.lock);
|
||||
|
||||
if (htt->rx_confused)
|
||||
return;
|
||||
|
||||
fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);
|
||||
fw_desc = (u8 *)&rx->fw_desc;
|
||||
int i, mpdu_count = 0;
|
||||
|
||||
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
|
||||
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
|
||||
@ -1603,80 +1577,19 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
||||
for (i = 0; i < num_mpdu_ranges; i++)
|
||||
mpdu_count += mpdu_ranges[i].mpdu_count;
|
||||
|
||||
while (mpdu_count--) {
|
||||
__skb_queue_head_init(&amsdu);
|
||||
ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc,
|
||||
&fw_desc_len, &amsdu);
|
||||
if (ret < 0) {
|
||||
ath10k_warn(ar, "rx ring became corrupted: %d\n", ret);
|
||||
__skb_queue_purge(&amsdu);
|
||||
/* FIXME: It's probably a good idea to reboot the
|
||||
* device instead of leaving it inoperable.
|
||||
*/
|
||||
htt->rx_confused = true;
|
||||
break;
|
||||
}
|
||||
atomic_add(mpdu_count, &htt->num_mpdus_ready);
|
||||
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
||||
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
||||
}
|
||||
|
||||
tasklet_schedule(&htt->rx_replenish_task);
|
||||
tasklet_schedule(&htt->txrx_compl_task);
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
struct htt_rx_fragment_indication *frag)
|
||||
static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
||||
struct sk_buff_head amsdu;
|
||||
int ret;
|
||||
u8 *fw_desc;
|
||||
int fw_desc_len;
|
||||
atomic_inc(&htt->num_mpdus_ready);
|
||||
|
||||
fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes);
|
||||
fw_desc = (u8 *)frag->fw_msdu_rx_desc;
|
||||
|
||||
__skb_queue_head_init(&amsdu);
|
||||
|
||||
spin_lock_bh(&htt->rx_ring.lock);
|
||||
ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
|
||||
&amsdu);
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
|
||||
tasklet_schedule(&htt->rx_replenish_task);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
|
||||
ret);
|
||||
__skb_queue_purge(&amsdu);
|
||||
return;
|
||||
}
|
||||
|
||||
if (skb_queue_len(&amsdu) != 1) {
|
||||
ath10k_warn(ar, "failed to pop frag amsdu: too many msdus\n");
|
||||
__skb_queue_purge(&amsdu);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
||||
|
||||
if (fw_desc_len > 0) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"expecting more fragmented rx in one indication %d\n",
|
||||
fw_desc_len);
|
||||
}
|
||||
tasklet_schedule(&htt->txrx_compl_task);
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
|
||||
static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
@ -1688,19 +1601,19 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
|
||||
|
||||
switch (status) {
|
||||
case HTT_DATA_TX_STATUS_NO_ACK:
|
||||
tx_done.no_ack = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_NOACK;
|
||||
break;
|
||||
case HTT_DATA_TX_STATUS_OK:
|
||||
tx_done.success = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_ACK;
|
||||
break;
|
||||
case HTT_DATA_TX_STATUS_DISCARD:
|
||||
case HTT_DATA_TX_STATUS_POSTPONE:
|
||||
case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL:
|
||||
tx_done.discard = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_DISCARD;
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "unhandled tx completion status %d\n", status);
|
||||
tx_done.discard = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_DISCARD;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1710,7 +1623,20 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
|
||||
for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
|
||||
msdu_id = resp->data_tx_completion.msdus[i];
|
||||
tx_done.msdu_id = __le16_to_cpu(msdu_id);
|
||||
ath10k_txrx_tx_unref(htt, &tx_done);
|
||||
|
||||
/* kfifo_put: In practice firmware shouldn't fire off per-CE
|
||||
* interrupt and main interrupt (MSI/-X range case) for the same
|
||||
* HTC service so it should be safe to use kfifo_put w/o lock.
|
||||
*
|
||||
* From kfifo_put() documentation:
|
||||
* Note that with only one concurrent reader and one concurrent
|
||||
* writer, you don't need extra locking to use these macro.
|
||||
*/
|
||||
if (!kfifo_put(&htt->txdone_fifo, tx_done)) {
|
||||
ath10k_warn(ar, "txdone fifo overrun, msdu_id %d status %d\n",
|
||||
tx_done.msdu_id, tx_done.status);
|
||||
ath10k_txrx_tx_unref(htt, &tx_done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1978,11 +1904,324 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tasklet_schedule(&htt->rx_replenish_task);
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
|
||||
const __le32 *resp_ids,
|
||||
int num_resp_ids)
|
||||
{
|
||||
int i;
|
||||
u32 resp_id;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch confirm num_resp_ids %d\n",
|
||||
num_resp_ids);
|
||||
|
||||
for (i = 0; i < num_resp_ids; i++) {
|
||||
resp_id = le32_to_cpu(resp_ids[i]);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch confirm resp_id %u\n",
|
||||
resp_id);
|
||||
|
||||
/* TODO: free resp_id */
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_tx_fetch_ind(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hw *hw = ar->hw;
|
||||
struct ieee80211_txq *txq;
|
||||
struct htt_resp *resp = (struct htt_resp *)skb->data;
|
||||
struct htt_tx_fetch_record *record;
|
||||
size_t len;
|
||||
size_t max_num_bytes;
|
||||
size_t max_num_msdus;
|
||||
size_t num_bytes;
|
||||
size_t num_msdus;
|
||||
const __le32 *resp_ids;
|
||||
u16 num_records;
|
||||
u16 num_resp_ids;
|
||||
u16 peer_id;
|
||||
u8 tid;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch ind\n");
|
||||
|
||||
len = sizeof(resp->hdr) + sizeof(resp->tx_fetch_ind);
|
||||
if (unlikely(skb->len < len)) {
|
||||
ath10k_warn(ar, "received corrupted tx_fetch_ind event: buffer too short\n");
|
||||
return;
|
||||
}
|
||||
|
||||
num_records = le16_to_cpu(resp->tx_fetch_ind.num_records);
|
||||
num_resp_ids = le16_to_cpu(resp->tx_fetch_ind.num_resp_ids);
|
||||
|
||||
len += sizeof(resp->tx_fetch_ind.records[0]) * num_records;
|
||||
len += sizeof(resp->tx_fetch_ind.resp_ids[0]) * num_resp_ids;
|
||||
|
||||
if (unlikely(skb->len < len)) {
|
||||
ath10k_warn(ar, "received corrupted tx_fetch_ind event: too many records/resp_ids\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch ind num records %hu num resps %hu seq %hu\n",
|
||||
num_records, num_resp_ids,
|
||||
le16_to_cpu(resp->tx_fetch_ind.fetch_seq_num));
|
||||
|
||||
if (!ar->htt.tx_q_state.enabled) {
|
||||
ath10k_warn(ar, "received unexpected tx_fetch_ind event: not enabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ar->htt.tx_q_state.mode == HTT_TX_MODE_SWITCH_PUSH) {
|
||||
ath10k_warn(ar, "received unexpected tx_fetch_ind event: in push mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (i = 0; i < num_records; i++) {
|
||||
record = &resp->tx_fetch_ind.records[i];
|
||||
peer_id = MS(le16_to_cpu(record->info),
|
||||
HTT_TX_FETCH_RECORD_INFO_PEER_ID);
|
||||
tid = MS(le16_to_cpu(record->info),
|
||||
HTT_TX_FETCH_RECORD_INFO_TID);
|
||||
max_num_msdus = le16_to_cpu(record->num_msdus);
|
||||
max_num_bytes = le32_to_cpu(record->num_bytes);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch record %i peer_id %hu tid %hhu msdus %zu bytes %zu\n",
|
||||
i, peer_id, tid, max_num_msdus, max_num_bytes);
|
||||
|
||||
if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) ||
|
||||
unlikely(tid >= ar->htt.tx_q_state.num_tids)) {
|
||||
ath10k_warn(ar, "received out of range peer_id %hu tid %hhu\n",
|
||||
peer_id, tid);
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
txq = ath10k_mac_txq_lookup(ar, peer_id, tid);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
/* It is okay to release the lock and use txq because RCU read
|
||||
* lock is held.
|
||||
*/
|
||||
|
||||
if (unlikely(!txq)) {
|
||||
ath10k_warn(ar, "failed to lookup txq for peer_id %hu tid %hhu\n",
|
||||
peer_id, tid);
|
||||
continue;
|
||||
}
|
||||
|
||||
num_msdus = 0;
|
||||
num_bytes = 0;
|
||||
|
||||
while (num_msdus < max_num_msdus &&
|
||||
num_bytes < max_num_bytes) {
|
||||
ret = ath10k_mac_tx_push_txq(hw, txq);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
num_msdus++;
|
||||
num_bytes += ret;
|
||||
}
|
||||
|
||||
record->num_msdus = cpu_to_le16(num_msdus);
|
||||
record->num_bytes = cpu_to_le32(num_bytes);
|
||||
|
||||
ath10k_htt_tx_txq_recalc(hw, txq);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
resp_ids = ath10k_htt_get_tx_fetch_ind_resp_ids(&resp->tx_fetch_ind);
|
||||
ath10k_htt_rx_tx_fetch_resp_id_confirm(ar, resp_ids, num_resp_ids);
|
||||
|
||||
ret = ath10k_htt_tx_fetch_resp(ar,
|
||||
resp->tx_fetch_ind.token,
|
||||
resp->tx_fetch_ind.fetch_seq_num,
|
||||
resp->tx_fetch_ind.records,
|
||||
num_records);
|
||||
if (unlikely(ret)) {
|
||||
ath10k_warn(ar, "failed to submit tx fetch resp for token 0x%08x: %d\n",
|
||||
le32_to_cpu(resp->tx_fetch_ind.token), ret);
|
||||
/* FIXME: request fw restart */
|
||||
}
|
||||
|
||||
ath10k_htt_tx_txq_sync(ar);
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_tx_fetch_confirm(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct htt_resp *resp = (void *)skb->data;
|
||||
size_t len;
|
||||
int num_resp_ids;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch confirm\n");
|
||||
|
||||
len = sizeof(resp->hdr) + sizeof(resp->tx_fetch_confirm);
|
||||
if (unlikely(skb->len < len)) {
|
||||
ath10k_warn(ar, "received corrupted tx_fetch_confirm event: buffer too short\n");
|
||||
return;
|
||||
}
|
||||
|
||||
num_resp_ids = le16_to_cpu(resp->tx_fetch_confirm.num_resp_ids);
|
||||
len += sizeof(resp->tx_fetch_confirm.resp_ids[0]) * num_resp_ids;
|
||||
|
||||
if (unlikely(skb->len < len)) {
|
||||
ath10k_warn(ar, "received corrupted tx_fetch_confirm event: resp_ids buffer overflow\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_htt_rx_tx_fetch_resp_id_confirm(ar,
|
||||
resp->tx_fetch_confirm.resp_ids,
|
||||
num_resp_ids);
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_tx_mode_switch_ind(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct htt_resp *resp = (void *)skb->data;
|
||||
const struct htt_tx_mode_switch_record *record;
|
||||
struct ieee80211_txq *txq;
|
||||
struct ath10k_txq *artxq;
|
||||
size_t len;
|
||||
size_t num_records;
|
||||
enum htt_tx_mode_switch_mode mode;
|
||||
bool enable;
|
||||
u16 info0;
|
||||
u16 info1;
|
||||
u16 threshold;
|
||||
u16 peer_id;
|
||||
u8 tid;
|
||||
int i;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx mode switch ind\n");
|
||||
|
||||
len = sizeof(resp->hdr) + sizeof(resp->tx_mode_switch_ind);
|
||||
if (unlikely(skb->len < len)) {
|
||||
ath10k_warn(ar, "received corrupted tx_mode_switch_ind event: buffer too short\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info0 = le16_to_cpu(resp->tx_mode_switch_ind.info0);
|
||||
info1 = le16_to_cpu(resp->tx_mode_switch_ind.info1);
|
||||
|
||||
enable = !!(info0 & HTT_TX_MODE_SWITCH_IND_INFO0_ENABLE);
|
||||
num_records = MS(info0, HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD);
|
||||
mode = MS(info1, HTT_TX_MODE_SWITCH_IND_INFO1_MODE);
|
||||
threshold = MS(info1, HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt rx tx mode switch ind info0 0x%04hx info1 0x%04hx enable %d num records %zd mode %d threshold %hu\n",
|
||||
info0, info1, enable, num_records, mode, threshold);
|
||||
|
||||
len += sizeof(resp->tx_mode_switch_ind.records[0]) * num_records;
|
||||
|
||||
if (unlikely(skb->len < len)) {
|
||||
ath10k_warn(ar, "received corrupted tx_mode_switch_mode_ind event: too many records\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case HTT_TX_MODE_SWITCH_PUSH:
|
||||
case HTT_TX_MODE_SWITCH_PUSH_PULL:
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "received invalid tx_mode_switch_mode_ind mode %d, ignoring\n",
|
||||
mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enable)
|
||||
return;
|
||||
|
||||
ar->htt.tx_q_state.enabled = enable;
|
||||
ar->htt.tx_q_state.mode = mode;
|
||||
ar->htt.tx_q_state.num_push_allowed = threshold;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (i = 0; i < num_records; i++) {
|
||||
record = &resp->tx_mode_switch_ind.records[i];
|
||||
info0 = le16_to_cpu(record->info0);
|
||||
peer_id = MS(info0, HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID);
|
||||
tid = MS(info0, HTT_TX_MODE_SWITCH_RECORD_INFO0_TID);
|
||||
|
||||
if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) ||
|
||||
unlikely(tid >= ar->htt.tx_q_state.num_tids)) {
|
||||
ath10k_warn(ar, "received out of range peer_id %hu tid %hhu\n",
|
||||
peer_id, tid);
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
txq = ath10k_mac_txq_lookup(ar, peer_id, tid);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
/* It is okay to release the lock and use txq because RCU read
|
||||
* lock is held.
|
||||
*/
|
||||
|
||||
if (unlikely(!txq)) {
|
||||
ath10k_warn(ar, "failed to lookup txq for peer_id %hu tid %hhu\n",
|
||||
peer_id, tid);
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
artxq = (void *)txq->drv_priv;
|
||||
artxq->num_push_allowed = le16_to_cpu(record->num_max_msdus);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ath10k_mac_tx_push_pending(ar);
|
||||
}
|
||||
|
||||
static inline enum ieee80211_band phy_mode_to_band(u32 phy_mode)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
|
||||
switch (phy_mode) {
|
||||
case MODE_11A:
|
||||
case MODE_11NA_HT20:
|
||||
case MODE_11NA_HT40:
|
||||
case MODE_11AC_VHT20:
|
||||
case MODE_11AC_VHT40:
|
||||
case MODE_11AC_VHT80:
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
break;
|
||||
case MODE_11G:
|
||||
case MODE_11B:
|
||||
case MODE_11GONLY:
|
||||
case MODE_11NG_HT20:
|
||||
case MODE_11NG_HT40:
|
||||
case MODE_11AC_VHT20_2G:
|
||||
case MODE_11AC_VHT40_2G:
|
||||
case MODE_11AC_VHT80_2G:
|
||||
default:
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
}
|
||||
|
||||
return band;
|
||||
}
|
||||
|
||||
void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
bool release;
|
||||
|
||||
release = ath10k_htt_t2h_msg_handler(ar, skb);
|
||||
|
||||
/* Free the indication buffer */
|
||||
if (release)
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
struct htt_resp *resp = (struct htt_resp *)skb->data;
|
||||
@ -1998,8 +2237,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
if (resp->hdr.msg_type >= ar->htt.t2h_msg_types_max) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, unsupported msg_type: 0x%0X\n max: 0x%0X",
|
||||
resp->hdr.msg_type, ar->htt.t2h_msg_types_max);
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
type = ar->htt.t2h_msg_types[resp->hdr.msg_type];
|
||||
|
||||
@ -2011,9 +2249,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_RX_IND:
|
||||
skb_queue_tail(&htt->rx_compl_q, skb);
|
||||
tasklet_schedule(&htt->txrx_compl_task);
|
||||
return;
|
||||
ath10k_htt_rx_proc_rx_ind(htt, &resp->rx_ind);
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_PEER_MAP: {
|
||||
struct htt_peer_map_event ev = {
|
||||
.vdev_id = resp->peer_map.vdev_id,
|
||||
@ -2034,28 +2271,33 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
struct htt_tx_done tx_done = {};
|
||||
int status = __le32_to_cpu(resp->mgmt_tx_completion.status);
|
||||
|
||||
tx_done.msdu_id =
|
||||
__le32_to_cpu(resp->mgmt_tx_completion.desc_id);
|
||||
tx_done.msdu_id = __le32_to_cpu(resp->mgmt_tx_completion.desc_id);
|
||||
|
||||
switch (status) {
|
||||
case HTT_MGMT_TX_STATUS_OK:
|
||||
tx_done.success = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_ACK;
|
||||
break;
|
||||
case HTT_MGMT_TX_STATUS_RETRY:
|
||||
tx_done.no_ack = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_NOACK;
|
||||
break;
|
||||
case HTT_MGMT_TX_STATUS_DROP:
|
||||
tx_done.discard = true;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_DISCARD;
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_txrx_tx_unref(htt, &tx_done);
|
||||
status = ath10k_txrx_tx_unref(htt, &tx_done);
|
||||
if (!status) {
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
ath10k_htt_tx_mgmt_dec_pending(htt);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
ath10k_mac_tx_push_pending(ar);
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
|
||||
skb_queue_tail(&htt->tx_compl_q, skb);
|
||||
ath10k_htt_rx_tx_compl_ind(htt->ar, skb);
|
||||
tasklet_schedule(&htt->txrx_compl_task);
|
||||
return;
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_SEC_IND: {
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct htt_security_indication *ev = &resp->security_indication;
|
||||
@ -2071,7 +2313,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
|
||||
skb->data, skb->len);
|
||||
ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind);
|
||||
ath10k_htt_rx_frag_handler(htt);
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_TEST:
|
||||
@ -2111,18 +2353,39 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
|
||||
skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
|
||||
tasklet_schedule(&htt->txrx_compl_task);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_CHAN_CHANGE:
|
||||
case HTT_T2H_MSG_TYPE_CHAN_CHANGE: {
|
||||
u32 phymode = __le32_to_cpu(resp->chan_change.phymode);
|
||||
u32 freq = __le32_to_cpu(resp->chan_change.freq);
|
||||
|
||||
ar->tgt_oper_chan =
|
||||
__ieee80211_get_channel(ar->hw->wiphy, freq);
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt chan change freq %u phymode %s\n",
|
||||
freq, ath10k_wmi_phymode_str(phymode));
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_AGGR_CONF:
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_TX_FETCH_IND:
|
||||
case HTT_T2H_MSG_TYPE_TX_FETCH_IND: {
|
||||
struct sk_buff *tx_fetch_ind = skb_copy(skb, GFP_ATOMIC);
|
||||
|
||||
if (!tx_fetch_ind) {
|
||||
ath10k_warn(ar, "failed to copy htt tx fetch ind\n");
|
||||
break;
|
||||
}
|
||||
skb_queue_tail(&htt->tx_fetch_ind_q, tx_fetch_ind);
|
||||
tasklet_schedule(&htt->txrx_compl_task);
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
|
||||
ath10k_htt_rx_tx_fetch_confirm(ar, skb);
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
|
||||
/* TODO: Implement pull-push logic */
|
||||
ath10k_htt_rx_tx_mode_switch_ind(ar, skb);
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_EN_STATS:
|
||||
default:
|
||||
@ -2132,9 +2395,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
skb->data, skb->len);
|
||||
break;
|
||||
};
|
||||
|
||||
/* Free the indication buffer */
|
||||
dev_kfree_skb_any(skb);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler);
|
||||
|
||||
@ -2150,40 +2411,47 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
|
||||
{
|
||||
struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct sk_buff_head tx_q;
|
||||
struct sk_buff_head rx_q;
|
||||
struct htt_tx_done tx_done = {};
|
||||
struct sk_buff_head rx_ind_q;
|
||||
struct htt_resp *resp;
|
||||
struct sk_buff_head tx_ind_q;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
int num_mpdus;
|
||||
|
||||
__skb_queue_head_init(&tx_q);
|
||||
__skb_queue_head_init(&rx_q);
|
||||
__skb_queue_head_init(&rx_ind_q);
|
||||
|
||||
spin_lock_irqsave(&htt->tx_compl_q.lock, flags);
|
||||
skb_queue_splice_init(&htt->tx_compl_q, &tx_q);
|
||||
spin_unlock_irqrestore(&htt->tx_compl_q.lock, flags);
|
||||
|
||||
spin_lock_irqsave(&htt->rx_compl_q.lock, flags);
|
||||
skb_queue_splice_init(&htt->rx_compl_q, &rx_q);
|
||||
spin_unlock_irqrestore(&htt->rx_compl_q.lock, flags);
|
||||
__skb_queue_head_init(&tx_ind_q);
|
||||
|
||||
spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags);
|
||||
skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q);
|
||||
spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags);
|
||||
|
||||
while ((skb = __skb_dequeue(&tx_q))) {
|
||||
ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
|
||||
spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags);
|
||||
skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q);
|
||||
spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags);
|
||||
|
||||
/* kfifo_get: called only within txrx_tasklet so it's neatly serialized.
|
||||
* From kfifo_get() documentation:
|
||||
* Note that with only one concurrent reader and one concurrent writer,
|
||||
* you don't need extra locking to use these macro.
|
||||
*/
|
||||
while (kfifo_get(&htt->txdone_fifo, &tx_done))
|
||||
ath10k_txrx_tx_unref(htt, &tx_done);
|
||||
|
||||
while ((skb = __skb_dequeue(&tx_ind_q))) {
|
||||
ath10k_htt_rx_tx_fetch_ind(ar, skb);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
while ((skb = __skb_dequeue(&rx_q))) {
|
||||
resp = (struct htt_resp *)skb->data;
|
||||
spin_lock_bh(&htt->rx_ring.lock);
|
||||
ath10k_htt_rx_handler(htt, &resp->rx_ind);
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
dev_kfree_skb_any(skb);
|
||||
ath10k_mac_tx_push_pending(ar);
|
||||
|
||||
num_mpdus = atomic_read(&htt->num_mpdus_ready);
|
||||
|
||||
while (num_mpdus) {
|
||||
if (ath10k_htt_rx_handle_amsdu(htt))
|
||||
break;
|
||||
|
||||
num_mpdus--;
|
||||
atomic_dec(&htt->num_mpdus_ready);
|
||||
}
|
||||
|
||||
while ((skb = __skb_dequeue(&rx_ind_q))) {
|
||||
@ -2192,4 +2460,6 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
@ -22,53 +22,183 @@
|
||||
#include "txrx.h"
|
||||
#include "debug.h"
|
||||
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc)
|
||||
static u8 ath10k_htt_tx_txq_calc_size(size_t count)
|
||||
{
|
||||
if (limit_mgmt_desc)
|
||||
htt->num_pending_mgmt_tx--;
|
||||
int exp;
|
||||
int factor;
|
||||
|
||||
exp = 0;
|
||||
factor = count >> 7;
|
||||
|
||||
while (factor >= 64 && exp < 4) {
|
||||
factor >>= 3;
|
||||
exp++;
|
||||
}
|
||||
|
||||
if (exp == 4)
|
||||
return 0xff;
|
||||
|
||||
if (count > 0)
|
||||
factor = max(1, factor);
|
||||
|
||||
return SM(exp, HTT_TX_Q_STATE_ENTRY_EXP) |
|
||||
SM(factor, HTT_TX_Q_STATE_ENTRY_FACTOR);
|
||||
}
|
||||
|
||||
static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_sta *arsta = (void *)txq->sta->drv_priv;
|
||||
struct ath10k_vif *arvif = (void *)txq->vif->drv_priv;
|
||||
unsigned long frame_cnt;
|
||||
unsigned long byte_cnt;
|
||||
int idx;
|
||||
u32 bit;
|
||||
u16 peer_id;
|
||||
u8 tid;
|
||||
u8 count;
|
||||
|
||||
lockdep_assert_held(&ar->htt.tx_lock);
|
||||
|
||||
if (!ar->htt.tx_q_state.enabled)
|
||||
return;
|
||||
|
||||
if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL)
|
||||
return;
|
||||
|
||||
if (txq->sta)
|
||||
peer_id = arsta->peer_id;
|
||||
else
|
||||
peer_id = arvif->peer_id;
|
||||
|
||||
tid = txq->tid;
|
||||
bit = BIT(peer_id % 32);
|
||||
idx = peer_id / 32;
|
||||
|
||||
ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt);
|
||||
count = ath10k_htt_tx_txq_calc_size(byte_cnt);
|
||||
|
||||
if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) ||
|
||||
unlikely(tid >= ar->htt.tx_q_state.num_tids)) {
|
||||
ath10k_warn(ar, "refusing to update txq for peer_id %hu tid %hhu due to out of bounds\n",
|
||||
peer_id, tid);
|
||||
return;
|
||||
}
|
||||
|
||||
ar->htt.tx_q_state.vaddr->count[tid][peer_id] = count;
|
||||
ar->htt.tx_q_state.vaddr->map[tid][idx] &= ~bit;
|
||||
ar->htt.tx_q_state.vaddr->map[tid][idx] |= count ? bit : 0;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx txq state update peer_id %hu tid %hhu count %hhu\n",
|
||||
peer_id, tid, count);
|
||||
}
|
||||
|
||||
static void __ath10k_htt_tx_txq_sync(struct ath10k *ar)
|
||||
{
|
||||
u32 seq;
|
||||
size_t size;
|
||||
|
||||
lockdep_assert_held(&ar->htt.tx_lock);
|
||||
|
||||
if (!ar->htt.tx_q_state.enabled)
|
||||
return;
|
||||
|
||||
if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL)
|
||||
return;
|
||||
|
||||
seq = le32_to_cpu(ar->htt.tx_q_state.vaddr->seq);
|
||||
seq++;
|
||||
ar->htt.tx_q_state.vaddr->seq = cpu_to_le32(seq);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx txq state update commit seq %u\n",
|
||||
seq);
|
||||
|
||||
size = sizeof(*ar->htt.tx_q_state.vaddr);
|
||||
dma_sync_single_for_device(ar->dev,
|
||||
ar->htt.tx_q_state.paddr,
|
||||
size,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
__ath10k_htt_tx_txq_recalc(hw, txq);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_txq_sync(struct ath10k *ar)
|
||||
{
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
__ath10k_htt_tx_txq_sync(ar);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
__ath10k_htt_tx_txq_recalc(hw, txq);
|
||||
__ath10k_htt_tx_txq_sync(ar);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
lockdep_assert_held(&htt->tx_lock);
|
||||
|
||||
htt->num_pending_tx--;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
|
||||
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
|
||||
bool limit_mgmt_desc)
|
||||
int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
__ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
lockdep_assert_held(&htt->tx_lock);
|
||||
|
||||
static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
|
||||
bool limit_mgmt_desc, bool is_probe_resp)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
|
||||
if (htt->num_pending_tx >= htt->max_num_pending_tx) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (limit_mgmt_desc) {
|
||||
if (is_probe_resp && (htt->num_pending_mgmt_tx >
|
||||
ar->hw_params.max_probe_resp_desc_thres)) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
htt->num_pending_mgmt_tx++;
|
||||
}
|
||||
if (htt->num_pending_tx >= htt->max_num_pending_tx)
|
||||
return -EBUSY;
|
||||
|
||||
htt->num_pending_tx++;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx)
|
||||
ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
|
||||
bool is_presp)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
|
||||
lockdep_assert_held(&htt->tx_lock);
|
||||
|
||||
if (!is_mgmt || !ar->hw_params.max_probe_resp_desc_thres)
|
||||
return 0;
|
||||
|
||||
if (is_presp &&
|
||||
ar->hw_params.max_probe_resp_desc_thres < htt->num_pending_mgmt_tx)
|
||||
return -EBUSY;
|
||||
|
||||
htt->num_pending_mgmt_tx++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
lockdep_assert_held(&htt->tx_lock);
|
||||
|
||||
if (!htt->ar->hw_params.max_probe_resp_desc_thres)
|
||||
return;
|
||||
|
||||
htt->num_pending_mgmt_tx--;
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
|
||||
@ -209,8 +339,18 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||
goto free_frag_desc;
|
||||
}
|
||||
|
||||
size = roundup_pow_of_two(htt->max_num_pending_tx);
|
||||
ret = kfifo_alloc(&htt->txdone_fifo, size, GFP_KERNEL);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to alloc txdone fifo: %d\n", ret);
|
||||
goto free_txq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_txq:
|
||||
ath10k_htt_tx_free_txq(htt);
|
||||
|
||||
free_frag_desc:
|
||||
ath10k_htt_tx_free_cont_frag_desc(htt);
|
||||
|
||||
@ -234,8 +374,8 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id);
|
||||
|
||||
tx_done.discard = 1;
|
||||
tx_done.msdu_id = msdu_id;
|
||||
tx_done.status = HTT_TX_COMPL_STATE_DISCARD;
|
||||
|
||||
ath10k_txrx_tx_unref(htt, &tx_done);
|
||||
|
||||
@ -258,6 +398,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
|
||||
ath10k_htt_tx_free_txq(htt);
|
||||
ath10k_htt_tx_free_cont_frag_desc(htt);
|
||||
WARN_ON(!kfifo_is_empty(&htt->txdone_fifo));
|
||||
kfifo_free(&htt->txdone_fifo);
|
||||
}
|
||||
|
||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
||||
@ -535,6 +677,55 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
|
||||
__le32 token,
|
||||
__le16 fetch_seq_num,
|
||||
struct htt_tx_fetch_record *records,
|
||||
size_t num_records)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct htt_cmd *cmd;
|
||||
const u16 resp_id = 0;
|
||||
int len = 0;
|
||||
int ret;
|
||||
|
||||
/* Response IDs are echo-ed back only for host driver convienence
|
||||
* purposes. They aren't used for anything in the driver yet so use 0.
|
||||
*/
|
||||
|
||||
len += sizeof(cmd->hdr);
|
||||
len += sizeof(cmd->tx_fetch_resp);
|
||||
len += sizeof(cmd->tx_fetch_resp.records[0]) * num_records;
|
||||
|
||||
skb = ath10k_htc_alloc_skb(ar, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, len);
|
||||
cmd = (struct htt_cmd *)skb->data;
|
||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FETCH_RESP;
|
||||
cmd->tx_fetch_resp.resp_id = cpu_to_le16(resp_id);
|
||||
cmd->tx_fetch_resp.fetch_seq_num = fetch_seq_num;
|
||||
cmd->tx_fetch_resp.num_records = cpu_to_le16(num_records);
|
||||
cmd->tx_fetch_resp.token = token;
|
||||
|
||||
memcpy(cmd->tx_fetch_resp.records, records,
|
||||
sizeof(records[0]) * num_records);
|
||||
|
||||
ret = ath10k_htc_send(&ar->htc, ar->htt.eid, skb);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to submit htc command: %d\n", ret);
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_skb:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
@ -576,20 +767,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
int msdu_id = -1;
|
||||
int res;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
bool limit_mgmt_desc = false;
|
||||
bool is_probe_resp = false;
|
||||
|
||||
if (ar->hw_params.max_probe_resp_desc_thres) {
|
||||
limit_mgmt_desc = true;
|
||||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control))
|
||||
is_probe_resp = true;
|
||||
}
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
|
||||
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
len += sizeof(cmd->hdr);
|
||||
len += sizeof(cmd->mgmt_tx);
|
||||
@ -598,7 +775,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
if (res < 0)
|
||||
goto err_tx_dec;
|
||||
goto err;
|
||||
|
||||
msdu_id = res;
|
||||
|
||||
@ -649,8 +826,6 @@ err_free_msdu_id:
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
err_tx_dec:
|
||||
ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
@ -677,26 +852,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
|
||||
u32 frags_paddr = 0;
|
||||
u32 txbuf_paddr;
|
||||
struct htt_msdu_ext_desc *ext_desc = NULL;
|
||||
bool limit_mgmt_desc = false;
|
||||
bool is_probe_resp = false;
|
||||
|
||||
if (unlikely(ieee80211_is_mgmt(hdr->frame_control)) &&
|
||||
ar->hw_params.max_probe_resp_desc_thres) {
|
||||
limit_mgmt_desc = true;
|
||||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control))
|
||||
is_probe_resp = true;
|
||||
}
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
if (res < 0)
|
||||
goto err_tx_dec;
|
||||
goto err;
|
||||
|
||||
msdu_id = res;
|
||||
|
||||
@ -862,11 +1023,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
|
||||
err_unmap_msdu:
|
||||
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
|
||||
err_free_msdu_id:
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
err_tx_dec:
|
||||
ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
|
@ -134,8 +134,6 @@ enum qca9377_chip_id_rev {
|
||||
|
||||
#define REG_DUMP_COUNT_QCA988X 60
|
||||
|
||||
#define QCA988X_CAL_DATA_LEN 2116
|
||||
|
||||
struct ath10k_fw_ie {
|
||||
__le32 id;
|
||||
__le32 len;
|
||||
@ -431,10 +429,14 @@ enum ath10k_hw_4addr_pad {
|
||||
#define TARGET_10_4_ACTIVE_PEERS 0
|
||||
|
||||
#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 512
|
||||
#define TARGET_10_4_QCACHE_ACTIVE_PEERS 50
|
||||
#define TARGET_10_4_QCACHE_ACTIVE_PEERS_PFC 35
|
||||
#define TARGET_10_4_NUM_OFFLOAD_PEERS 0
|
||||
#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0
|
||||
#define TARGET_10_4_NUM_PEER_KEYS 2
|
||||
#define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2)
|
||||
#define TARGET_10_4_NUM_MSDU_DESC (1024 + 400)
|
||||
#define TARGET_10_4_NUM_MSDU_DESC_PFC 2500
|
||||
#define TARGET_10_4_AST_SKID_LIMIT 32
|
||||
|
||||
/* 100 ms for video, best-effort, and background */
|
||||
|
@ -618,10 +618,15 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
|
||||
*def = &conf->def;
|
||||
}
|
||||
|
||||
static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,
|
||||
static int ath10k_peer_create(struct ath10k *ar,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 vdev_id,
|
||||
const u8 *addr,
|
||||
enum wmi_peer_type peer_type)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
struct ath10k_peer *peer;
|
||||
int num_peers = 0;
|
||||
int ret;
|
||||
|
||||
@ -650,6 +655,22 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
peer = ath10k_peer_find(ar, vdev_id, addr);
|
||||
if (!peer) {
|
||||
ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n",
|
||||
addr, vdev_id);
|
||||
ath10k_wmi_peer_delete(ar, vdev_id, addr);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
peer->vif = vif;
|
||||
peer->sta = sta;
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ar->num_peers++;
|
||||
|
||||
return 0;
|
||||
@ -731,6 +752,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
||||
static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
||||
{
|
||||
struct ath10k_peer *peer, *tmp;
|
||||
int peer_id;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
@ -742,6 +764,11 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
||||
ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
|
||||
peer->addr, vdev_id);
|
||||
|
||||
for_each_set_bit(peer_id, peer->peer_ids,
|
||||
ATH10K_MAX_NUM_PEER_IDS) {
|
||||
ar->peer_map[peer_id] = NULL;
|
||||
}
|
||||
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
@ -2994,6 +3021,13 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
|
||||
/* TX handlers */
|
||||
/***************/
|
||||
|
||||
enum ath10k_mac_tx_path {
|
||||
ATH10K_MAC_TX_HTT,
|
||||
ATH10K_MAC_TX_HTT_MGMT,
|
||||
ATH10K_MAC_TX_WMI_MGMT,
|
||||
ATH10K_MAC_TX_UNKNOWN,
|
||||
};
|
||||
|
||||
void ath10k_mac_tx_lock(struct ath10k *ar, int reason)
|
||||
{
|
||||
lockdep_assert_held(&ar->htt.tx_lock);
|
||||
@ -3271,6 +3305,28 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_txq *txq,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
||||
|
||||
cb->flags = 0;
|
||||
if (!ath10k_tx_h_use_hwcrypto(vif, skb))
|
||||
cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
|
||||
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
cb->flags |= ATH10K_SKB_F_MGMT;
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
cb->flags |= ATH10K_SKB_F_QOS;
|
||||
|
||||
cb->vif = vif;
|
||||
cb->txq = txq;
|
||||
}
|
||||
|
||||
bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
|
||||
{
|
||||
/* FIXME: Not really sure since when the behaviour changed. At some
|
||||
@ -3306,26 +3362,50 @@ unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_mac_tx(struct ath10k *ar, enum ath10k_hw_txrx_mode txmode,
|
||||
struct sk_buff *skb)
|
||||
static enum ath10k_mac_tx_path
|
||||
ath10k_mac_tx_h_get_txpath(struct ath10k *ar,
|
||||
struct sk_buff *skb,
|
||||
enum ath10k_hw_txrx_mode txmode)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
int ret = 0;
|
||||
|
||||
switch (txmode) {
|
||||
case ATH10K_HW_TXRX_RAW:
|
||||
case ATH10K_HW_TXRX_NATIVE_WIFI:
|
||||
case ATH10K_HW_TXRX_ETHERNET:
|
||||
ret = ath10k_htt_tx(htt, txmode, skb);
|
||||
break;
|
||||
return ATH10K_MAC_TX_HTT;
|
||||
case ATH10K_HW_TXRX_MGMT:
|
||||
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
||||
ar->fw_features))
|
||||
ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
|
||||
return ATH10K_MAC_TX_WMI_MGMT;
|
||||
else if (ar->htt.target_version_major >= 3)
|
||||
ret = ath10k_htt_tx(htt, txmode, skb);
|
||||
return ATH10K_MAC_TX_HTT;
|
||||
else
|
||||
ret = ath10k_htt_mgmt_tx(htt, skb);
|
||||
return ATH10K_MAC_TX_HTT_MGMT;
|
||||
}
|
||||
|
||||
return ATH10K_MAC_TX_UNKNOWN;
|
||||
}
|
||||
|
||||
static int ath10k_mac_tx_submit(struct ath10k *ar,
|
||||
enum ath10k_hw_txrx_mode txmode,
|
||||
enum ath10k_mac_tx_path txpath,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (txpath) {
|
||||
case ATH10K_MAC_TX_HTT:
|
||||
ret = ath10k_htt_tx(htt, txmode, skb);
|
||||
break;
|
||||
case ATH10K_MAC_TX_HTT_MGMT:
|
||||
ret = ath10k_htt_mgmt_tx(htt, skb);
|
||||
break;
|
||||
case ATH10K_MAC_TX_WMI_MGMT:
|
||||
ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
|
||||
break;
|
||||
case ATH10K_MAC_TX_UNKNOWN:
|
||||
WARN_ON_ONCE(1);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3334,6 +3414,64 @@ static void ath10k_mac_tx(struct ath10k *ar, enum ath10k_hw_txrx_mode txmode,
|
||||
ret);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function consumes the sk_buff regardless of return value as far as
|
||||
* caller is concerned so no freeing is necessary afterwards.
|
||||
*/
|
||||
static int ath10k_mac_tx(struct ath10k *ar,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ath10k_hw_txrx_mode txmode,
|
||||
enum ath10k_mac_tx_path txpath,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hw *hw = ar->hw;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int ret;
|
||||
|
||||
/* We should disable CCK RATE due to P2P */
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
|
||||
|
||||
switch (txmode) {
|
||||
case ATH10K_HW_TXRX_MGMT:
|
||||
case ATH10K_HW_TXRX_NATIVE_WIFI:
|
||||
ath10k_tx_h_nwifi(hw, skb);
|
||||
ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
|
||||
ath10k_tx_h_seq_no(vif, skb);
|
||||
break;
|
||||
case ATH10K_HW_TXRX_ETHERNET:
|
||||
ath10k_tx_h_8023(skb);
|
||||
break;
|
||||
case ATH10K_HW_TXRX_RAW:
|
||||
if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
||||
WARN_ON_ONCE(1);
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
||||
if (!ath10k_mac_tx_frm_has_freq(ar)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
|
||||
skb);
|
||||
|
||||
skb_queue_tail(&ar->offchan_tx_queue, skb);
|
||||
ieee80211_queue_work(hw, &ar->offchan_tx_work);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath10k_mac_tx_submit(ar, txmode, txpath, skb);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to submit frame: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_offchan_tx_purge(struct ath10k *ar)
|
||||
@ -3354,12 +3492,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
||||
struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work);
|
||||
struct ath10k_peer *peer;
|
||||
struct ath10k_vif *arvif;
|
||||
enum ath10k_hw_txrx_mode txmode;
|
||||
enum ath10k_mac_tx_path txpath;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_sta *sta;
|
||||
struct sk_buff *skb;
|
||||
const u8 *peer_addr;
|
||||
enum ath10k_hw_txrx_mode txmode;
|
||||
int vdev_id;
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
@ -3396,7 +3535,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
||||
peer_addr, vdev_id);
|
||||
|
||||
if (!peer) {
|
||||
ret = ath10k_peer_create(ar, vdev_id, peer_addr,
|
||||
ret = ath10k_peer_create(ar, NULL, NULL, vdev_id,
|
||||
peer_addr,
|
||||
WMI_PEER_TYPE_DEFAULT);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
|
||||
@ -3423,8 +3563,14 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
|
||||
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
|
||||
|
||||
ath10k_mac_tx(ar, txmode, skb);
|
||||
ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to transmit offchannel frame: %d\n",
|
||||
ret);
|
||||
/* not serious */
|
||||
}
|
||||
|
||||
time_left =
|
||||
wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
|
||||
@ -3476,6 +3622,175 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
|
||||
if (!txq)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&artxq->list);
|
||||
}
|
||||
|
||||
static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
struct ath10k_skb_cb *cb;
|
||||
struct sk_buff *msdu;
|
||||
int msdu_id;
|
||||
|
||||
if (!txq)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&ar->txqs_lock);
|
||||
if (!list_empty(&artxq->list))
|
||||
list_del_init(&artxq->list);
|
||||
spin_unlock_bh(&ar->txqs_lock);
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) {
|
||||
cb = ATH10K_SKB_CB(msdu);
|
||||
if (cb->txq == txq)
|
||||
cb->txq = NULL;
|
||||
}
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
|
||||
struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
|
||||
u16 peer_id,
|
||||
u8 tid)
|
||||
{
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
peer = ar->peer_map[peer_id];
|
||||
if (!peer)
|
||||
return NULL;
|
||||
|
||||
if (peer->sta)
|
||||
return peer->sta->txq[tid];
|
||||
else if (peer->vif)
|
||||
return peer->vif->txq;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool ath10k_mac_tx_can_push(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
|
||||
/* No need to get locks */
|
||||
|
||||
if (ar->htt.tx_q_state.mode == HTT_TX_MODE_SWITCH_PUSH)
|
||||
return true;
|
||||
|
||||
if (ar->htt.num_pending_tx < ar->htt.tx_q_state.num_push_allowed)
|
||||
return true;
|
||||
|
||||
if (artxq->num_fw_queued < artxq->num_push_allowed)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
struct ieee80211_vif *vif = txq->vif;
|
||||
struct ieee80211_sta *sta = txq->sta;
|
||||
enum ath10k_hw_txrx_mode txmode;
|
||||
enum ath10k_mac_tx_path txpath;
|
||||
struct sk_buff *skb;
|
||||
size_t skb_len;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
ret = ath10k_htt_tx_inc_pending(htt);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
skb = ieee80211_tx_dequeue(hw, txq);
|
||||
if (!skb) {
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
|
||||
|
||||
skb_len = skb->len;
|
||||
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
|
||||
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
|
||||
|
||||
ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
|
||||
if (unlikely(ret)) {
|
||||
ath10k_warn(ar, "failed to push frame: %d\n", ret);
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
artxq->num_fw_queued++;
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
|
||||
return skb_len;
|
||||
}
|
||||
|
||||
void ath10k_mac_tx_push_pending(struct ath10k *ar)
|
||||
{
|
||||
struct ieee80211_hw *hw = ar->hw;
|
||||
struct ieee80211_txq *txq;
|
||||
struct ath10k_txq *artxq;
|
||||
struct ath10k_txq *last;
|
||||
int ret;
|
||||
int max;
|
||||
|
||||
spin_lock_bh(&ar->txqs_lock);
|
||||
rcu_read_lock();
|
||||
|
||||
last = list_last_entry(&ar->txqs, struct ath10k_txq, list);
|
||||
while (!list_empty(&ar->txqs)) {
|
||||
artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list);
|
||||
txq = container_of((void *)artxq, struct ieee80211_txq,
|
||||
drv_priv);
|
||||
|
||||
/* Prevent aggressive sta/tid taking over tx queue */
|
||||
max = 16;
|
||||
ret = 0;
|
||||
while (ath10k_mac_tx_can_push(hw, txq) && max--) {
|
||||
ret = ath10k_mac_tx_push_txq(hw, txq);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
list_del_init(&artxq->list);
|
||||
if (ret != -ENOENT)
|
||||
list_add_tail(&artxq->list, &ar->txqs);
|
||||
|
||||
ath10k_htt_tx_txq_update(hw, txq);
|
||||
|
||||
if (artxq == last || (ret < 0 && ret != -ENOENT))
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&ar->txqs_lock);
|
||||
}
|
||||
|
||||
/************/
|
||||
/* Scanning */
|
||||
/************/
|
||||
@ -3638,66 +3953,86 @@ static int ath10k_start_scan(struct ath10k *ar,
|
||||
/* mac80211 callbacks */
|
||||
/**********************/
|
||||
|
||||
static void ath10k_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_control *control,
|
||||
struct sk_buff *skb)
|
||||
static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_control *control,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct ieee80211_sta *sta = control->sta;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_txq *txq = NULL;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
enum ath10k_hw_txrx_mode txmode;
|
||||
enum ath10k_mac_tx_path txpath;
|
||||
bool is_htt;
|
||||
bool is_mgmt;
|
||||
bool is_presp;
|
||||
int ret;
|
||||
|
||||
/* We should disable CCK RATE due to P2P */
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
|
||||
ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
|
||||
|
||||
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
|
||||
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
|
||||
is_htt = (txpath == ATH10K_MAC_TX_HTT ||
|
||||
txpath == ATH10K_MAC_TX_HTT_MGMT);
|
||||
is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT);
|
||||
|
||||
skb_cb->flags = 0;
|
||||
if (!ath10k_tx_h_use_hwcrypto(vif, skb))
|
||||
skb_cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
|
||||
if (is_htt) {
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
is_presp = ieee80211_is_probe_resp(hdr->frame_control);
|
||||
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
skb_cb->flags |= ATH10K_SKB_F_MGMT;
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
skb_cb->flags |= ATH10K_SKB_F_QOS;
|
||||
|
||||
skb_cb->vif = vif;
|
||||
|
||||
switch (txmode) {
|
||||
case ATH10K_HW_TXRX_MGMT:
|
||||
case ATH10K_HW_TXRX_NATIVE_WIFI:
|
||||
ath10k_tx_h_nwifi(hw, skb);
|
||||
ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
|
||||
ath10k_tx_h_seq_no(vif, skb);
|
||||
break;
|
||||
case ATH10K_HW_TXRX_ETHERNET:
|
||||
ath10k_tx_h_8023(skb);
|
||||
break;
|
||||
case ATH10K_HW_TXRX_RAW:
|
||||
if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
||||
WARN_ON_ONCE(1);
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
ret = ath10k_htt_tx_inc_pending(htt);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to increase tx pending count: %d, dropping\n",
|
||||
ret);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
||||
if (!ath10k_mac_tx_frm_has_freq(ar)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
|
||||
skb);
|
||||
|
||||
skb_queue_tail(&ar->offchan_tx_queue, skb);
|
||||
ieee80211_queue_work(hw, &ar->offchan_tx_work);
|
||||
ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp);
|
||||
if (ret) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "failed to increase tx mgmt pending count: %d, dropping\n",
|
||||
ret);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
return;
|
||||
}
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
|
||||
ath10k_mac_tx(ar, txmode, skb);
|
||||
ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to transmit frame: %d\n", ret);
|
||||
if (is_htt) {
|
||||
spin_lock_bh(&ar->htt.tx_lock);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
if (is_mgmt)
|
||||
ath10k_htt_tx_mgmt_dec_pending(htt);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
|
||||
spin_lock_bh(&ar->txqs_lock);
|
||||
if (list_empty(&artxq->list))
|
||||
list_add_tail(&artxq->list, &ar->txqs);
|
||||
spin_unlock_bh(&ar->txqs_lock);
|
||||
|
||||
if (ath10k_mac_tx_can_push(hw, txq))
|
||||
tasklet_schedule(&ar->htt.txrx_compl_task);
|
||||
|
||||
ath10k_htt_tx_txq_update(hw, txq);
|
||||
}
|
||||
|
||||
/* Must not be called with conf_mutex held as workers can use that also. */
|
||||
@ -4100,7 +4435,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||
|
||||
ar->ani_enabled = true;
|
||||
|
||||
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
|
||||
if (ath10k_peer_stats_enabled(ar)) {
|
||||
param = ar->wmi.pdev_param->peer_stats_update_period;
|
||||
ret = ath10k_wmi_pdev_set_param(ar, param,
|
||||
PEER_DEFAULT_STATS_UPDATE_PERIOD);
|
||||
@ -4313,6 +4648,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k_peer *peer;
|
||||
enum wmi_sta_powersave_param param;
|
||||
int ret = 0;
|
||||
u32 value;
|
||||
@ -4325,6 +4661,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
memset(arvif, 0, sizeof(*arvif));
|
||||
ath10k_mac_txq_init(vif->txq);
|
||||
|
||||
arvif->ar = ar;
|
||||
arvif->vif = vif;
|
||||
@ -4489,7 +4826,10 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
if (ar->cfg_tx_chainmask) {
|
||||
/* Configuring number of spatial stream for monitor interface is causing
|
||||
* target assert in qca9888 and qca6174.
|
||||
*/
|
||||
if (ar->cfg_tx_chainmask && (vif->type != NL80211_IFTYPE_MONITOR)) {
|
||||
u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->nss;
|
||||
@ -4505,13 +4845,31 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
|
||||
arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
|
||||
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr,
|
||||
WMI_PEER_TYPE_DEFAULT);
|
||||
ret = ath10k_peer_create(ar, vif, NULL, arvif->vdev_id,
|
||||
vif->addr, WMI_PEER_TYPE_DEFAULT);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to create vdev %i peer for AP/IBSS: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
peer = ath10k_peer_find(ar, arvif->vdev_id, vif->addr);
|
||||
if (!peer) {
|
||||
ath10k_warn(ar, "failed to lookup peer %pM on vdev %i\n",
|
||||
vif->addr, arvif->vdev_id);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
ret = -ENOENT;
|
||||
goto err_peer_delete;
|
||||
}
|
||||
|
||||
arvif->peer_id = find_first_bit(peer->peer_ids,
|
||||
ATH10K_MAX_NUM_PEER_IDS);
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
} else {
|
||||
arvif->peer_id = HTT_INVALID_PEERID;
|
||||
}
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
@ -4622,7 +4980,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k_peer *peer;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&arvif->ap_csa_work);
|
||||
cancel_delayed_work_sync(&arvif->connection_loss_work);
|
||||
@ -4676,7 +5036,22 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
|
||||
peer = ar->peer_map[i];
|
||||
if (!peer)
|
||||
continue;
|
||||
|
||||
if (peer->vif == vif) {
|
||||
ath10k_warn(ar, "found vif peer %pM entry on vdev %i after it was supposedly removed\n",
|
||||
vif->addr, arvif->vdev_id);
|
||||
peer->vif = NULL;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ath10k_peer_cleanup(ar, arvif->vdev_id);
|
||||
ath10k_mac_txq_unref(ar, vif->txq);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_MONITOR) {
|
||||
ar->monitor_arvif = NULL;
|
||||
@ -4689,6 +5064,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||
ath10k_mac_vif_tx_unlock_all(arvif);
|
||||
spin_unlock_bh(&ar->htt.tx_lock);
|
||||
|
||||
ath10k_mac_txq_unref(ar, vif->txq);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
@ -5393,13 +5770,18 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k_peer *peer;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (old_state == IEEE80211_STA_NOTEXIST &&
|
||||
new_state == IEEE80211_STA_NONE) {
|
||||
memset(arsta, 0, sizeof(*arsta));
|
||||
arsta->arvif = arvif;
|
||||
INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
|
||||
ath10k_mac_txq_init(sta->txq[i]);
|
||||
}
|
||||
|
||||
/* cancel must be done outside the mutex to avoid deadlock */
|
||||
@ -5434,8 +5816,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
if (sta->tdls)
|
||||
peer_type = WMI_PEER_TYPE_TDLS;
|
||||
|
||||
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
|
||||
peer_type);
|
||||
ret = ath10k_peer_create(ar, vif, sta, arvif->vdev_id,
|
||||
sta->addr, peer_type);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
|
||||
sta->addr, arvif->vdev_id, ret);
|
||||
@ -5443,6 +5825,24 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr);
|
||||
if (!peer) {
|
||||
ath10k_warn(ar, "failed to lookup peer %pM on vdev %i\n",
|
||||
vif->addr, arvif->vdev_id);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
|
||||
ath10k_mac_dec_num_stations(arvif, sta);
|
||||
ret = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arsta->peer_id = find_first_bit(peer->peer_ids,
|
||||
ATH10K_MAX_NUM_PEER_IDS);
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!sta->tdls)
|
||||
goto exit;
|
||||
|
||||
@ -5505,6 +5905,23 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
|
||||
ath10k_mac_dec_num_stations(arvif, sta);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
|
||||
peer = ar->peer_map[i];
|
||||
if (!peer)
|
||||
continue;
|
||||
|
||||
if (peer->sta == sta) {
|
||||
ath10k_warn(ar, "found sta peer %pM entry on vdev %i after it was supposedly removed\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
peer->sta = NULL;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
|
||||
ath10k_mac_txq_unref(ar, sta->txq[i]);
|
||||
|
||||
if (!sta->tdls)
|
||||
goto exit;
|
||||
|
||||
@ -6807,7 +7224,8 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath10k_ops = {
|
||||
.tx = ath10k_tx,
|
||||
.tx = ath10k_mac_op_tx,
|
||||
.wake_tx_queue = ath10k_mac_op_wake_tx_queue,
|
||||
.start = ath10k_start,
|
||||
.stop = ath10k_stop,
|
||||
.config = ath10k_config,
|
||||
@ -7262,6 +7680,7 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
|
||||
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
|
||||
ar->hw->sta_data_size = sizeof(struct ath10k_sta);
|
||||
ar->hw->txq_data_size = sizeof(struct ath10k_txq);
|
||||
|
||||
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
|
||||
|
||||
@ -7286,7 +7705,8 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
|
||||
|
||||
ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
|
||||
ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
|
||||
NL80211_FEATURE_AP_SCAN;
|
||||
|
||||
ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
|
||||
|
||||
|
@ -75,6 +75,12 @@ void ath10k_mac_tx_unlock(struct ath10k *ar, int reason);
|
||||
void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason);
|
||||
void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason);
|
||||
bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar);
|
||||
void ath10k_mac_tx_push_pending(struct ath10k *ar);
|
||||
int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq);
|
||||
struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
|
||||
u16 peer_id,
|
||||
u8 tid);
|
||||
|
||||
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -809,7 +809,8 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
while (num--) {
|
||||
|
||||
while (num >= 0) {
|
||||
ret = __ath10k_pci_rx_post_buf(pipe);
|
||||
if (ret) {
|
||||
if (ret == -ENOSPC)
|
||||
@ -819,6 +820,7 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||
ATH10K_PCI_RX_POST_RETRY_MS);
|
||||
break;
|
||||
}
|
||||
num--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -870,10 +872,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret = 0;
|
||||
u32 buf;
|
||||
u32 *buf;
|
||||
unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
|
||||
unsigned int id;
|
||||
unsigned int flags;
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
/* Host buffer address in CE space */
|
||||
u32 ce_data;
|
||||
@ -909,7 +909,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
|
||||
nbytes = min_t(unsigned int, remaining_bytes,
|
||||
DIAG_TRANSFER_LIMIT);
|
||||
|
||||
ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
|
||||
ret = __ath10k_ce_rx_post_buf(ce_diag, &ce_data, ce_data);
|
||||
if (ret != 0)
|
||||
goto done;
|
||||
|
||||
@ -940,9 +940,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
|
||||
&completed_nbytes,
|
||||
&id, &flags) != 0) {
|
||||
while (ath10k_ce_completed_recv_next_nolock(ce_diag,
|
||||
(void **)&buf,
|
||||
&completed_nbytes)
|
||||
!= 0) {
|
||||
mdelay(1);
|
||||
|
||||
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
|
||||
@ -956,7 +957,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (buf != ce_data) {
|
||||
if (*buf != ce_data) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
@ -1026,10 +1027,8 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret = 0;
|
||||
u32 buf;
|
||||
u32 *buf;
|
||||
unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
|
||||
unsigned int id;
|
||||
unsigned int flags;
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
void *data_buf = NULL;
|
||||
u32 ce_data; /* Host buffer address in CE space */
|
||||
@ -1078,7 +1077,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
|
||||
|
||||
/* Set up to receive directly into Target(!) address */
|
||||
ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address);
|
||||
ret = __ath10k_ce_rx_post_buf(ce_diag, &address, address);
|
||||
if (ret != 0)
|
||||
goto done;
|
||||
|
||||
@ -1103,9 +1102,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
|
||||
&completed_nbytes,
|
||||
&id, &flags) != 0) {
|
||||
while (ath10k_ce_completed_recv_next_nolock(ce_diag,
|
||||
(void **)&buf,
|
||||
&completed_nbytes)
|
||||
!= 0) {
|
||||
mdelay(1);
|
||||
|
||||
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
|
||||
@ -1119,7 +1119,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (buf != address) {
|
||||
if (*buf != address) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
@ -1181,15 +1181,11 @@ static void ath10k_pci_process_rx_cb(struct ath10k_ce_pipe *ce_state,
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff_head list;
|
||||
void *transfer_context;
|
||||
u32 ce_data;
|
||||
unsigned int nbytes, max_nbytes;
|
||||
unsigned int transfer_id;
|
||||
unsigned int flags;
|
||||
|
||||
__skb_queue_head_init(&list);
|
||||
while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
|
||||
&ce_data, &nbytes, &transfer_id,
|
||||
&flags) == 0) {
|
||||
&nbytes) == 0) {
|
||||
skb = transfer_context;
|
||||
max_nbytes = skb->len + skb_tailroom(skb);
|
||||
dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
|
||||
@ -1218,6 +1214,63 @@ static void ath10k_pci_process_rx_cb(struct ath10k_ce_pipe *ce_state,
|
||||
ath10k_pci_rx_post_pipe(pipe_info);
|
||||
}
|
||||
|
||||
static void ath10k_pci_process_htt_rx_cb(struct ath10k_ce_pipe *ce_state,
|
||||
void (*callback)(struct ath10k *ar,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
||||
struct ath10k_ce_pipe *ce_pipe = pipe_info->ce_hdl;
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff_head list;
|
||||
void *transfer_context;
|
||||
unsigned int nbytes, max_nbytes, nentries;
|
||||
int orig_len;
|
||||
|
||||
/* No need to aquire ce_lock for CE5, since this is the only place CE5
|
||||
* is processed other than init and deinit. Before releasing CE5
|
||||
* buffers, interrupts are disabled. Thus CE5 access is serialized.
|
||||
*/
|
||||
__skb_queue_head_init(&list);
|
||||
while (ath10k_ce_completed_recv_next_nolock(ce_state, &transfer_context,
|
||||
&nbytes) == 0) {
|
||||
skb = transfer_context;
|
||||
max_nbytes = skb->len + skb_tailroom(skb);
|
||||
|
||||
if (unlikely(max_nbytes < nbytes)) {
|
||||
ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)",
|
||||
nbytes, max_nbytes);
|
||||
continue;
|
||||
}
|
||||
|
||||
dma_sync_single_for_cpu(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
|
||||
max_nbytes, DMA_FROM_DEVICE);
|
||||
skb_put(skb, nbytes);
|
||||
__skb_queue_tail(&list, skb);
|
||||
}
|
||||
|
||||
nentries = skb_queue_len(&list);
|
||||
while ((skb = __skb_dequeue(&list))) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
|
||||
ce_state->id, skb->len);
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
|
||||
skb->data, skb->len);
|
||||
|
||||
orig_len = skb->len;
|
||||
callback(ar, skb);
|
||||
skb_push(skb, orig_len - skb->len);
|
||||
skb_reset_tail_pointer(skb);
|
||||
skb_trim(skb, 0);
|
||||
|
||||
/*let device gain the buffer again*/
|
||||
dma_sync_single_for_device(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
ath10k_ce_rx_update_write_idx(ce_pipe, nentries);
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when data is received from the Target. */
|
||||
static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
@ -1274,7 +1327,7 @@ static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state)
|
||||
*/
|
||||
ath10k_ce_per_engine_service(ce_state->ar, 4);
|
||||
|
||||
ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver);
|
||||
ath10k_pci_process_htt_rx_cb(ce_state, ath10k_pci_htt_rx_deliver);
|
||||
}
|
||||
|
||||
int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
@ -1835,13 +1888,10 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct bmi_xfer *xfer;
|
||||
u32 ce_data;
|
||||
unsigned int nbytes;
|
||||
unsigned int transfer_id;
|
||||
unsigned int flags;
|
||||
|
||||
if (ath10k_ce_completed_recv_next(ce_state, (void **)&xfer, &ce_data,
|
||||
&nbytes, &transfer_id, &flags))
|
||||
if (ath10k_ce_completed_recv_next(ce_state, (void **)&xfer,
|
||||
&nbytes))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(!xfer))
|
||||
|
@ -49,25 +49,25 @@ out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done)
|
||||
int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct device *dev = ar->dev;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_txq *txq;
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct ath10k_txq *artxq;
|
||||
struct sk_buff *msdu;
|
||||
bool limit_mgmt_desc = false;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
|
||||
tx_done->msdu_id, !!tx_done->discard,
|
||||
!!tx_done->no_ack, !!tx_done->success);
|
||||
"htt tx completion msdu_id %u status %d\n",
|
||||
tx_done->msdu_id, tx_done->status);
|
||||
|
||||
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
|
||||
ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
|
||||
tx_done->msdu_id);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
@ -76,17 +76,18 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
|
||||
tx_done->msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
return;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
skb_cb = ATH10K_SKB_CB(msdu);
|
||||
txq = skb_cb->txq;
|
||||
artxq = (void *)txq->drv_priv;
|
||||
|
||||
if (unlikely(skb_cb->flags & ATH10K_SKB_F_MGMT) &&
|
||||
ar->hw_params.max_probe_resp_desc_thres)
|
||||
limit_mgmt_desc = true;
|
||||
if (txq)
|
||||
artxq->num_fw_queued--;
|
||||
|
||||
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
||||
__ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
if (htt->num_pending_tx == 0)
|
||||
wake_up(&htt->empty_tx_wq);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
@ -99,22 +100,24 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
memset(&info->status, 0, sizeof(info->status));
|
||||
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
|
||||
|
||||
if (tx_done->discard) {
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
|
||||
ieee80211_free_txskb(htt->ar->hw, msdu);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if (tx_done->no_ack)
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_NOACK)
|
||||
info->flags &= ~IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if (tx_done->success && (info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) &&
|
||||
(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
|
||||
ieee80211_tx_status(htt->ar->hw, msdu);
|
||||
/* we do not own the msdu anymore */
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
@ -203,6 +206,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
|
||||
ev->vdev_id, ev->addr, ev->peer_id);
|
||||
|
||||
ar->peer_map[ev->peer_id] = peer;
|
||||
set_bit(ev->peer_id, peer->peer_ids);
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
@ -225,6 +229,7 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
|
||||
peer->vdev_id, peer->addr, ev->peer_id);
|
||||
|
||||
ar->peer_map[ev->peer_id] = NULL;
|
||||
clear_bit(ev->peer_id, peer->peer_ids);
|
||||
|
||||
if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) {
|
||||
|
@ -19,8 +19,8 @@
|
||||
|
||||
#include "htt.h"
|
||||
|
||||
void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done);
|
||||
int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done);
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
|
@ -186,6 +186,9 @@ struct wmi_ops {
|
||||
u8 enable,
|
||||
u32 detect_level,
|
||||
u32 detect_margin);
|
||||
struct sk_buff *(*ext_resource_config)(struct ath10k *ar,
|
||||
enum wmi_host_platform_type type,
|
||||
u32 fw_feature_bitmap);
|
||||
int (*get_vdev_subtype)(struct ath10k *ar,
|
||||
enum wmi_vdev_subtype subtype);
|
||||
};
|
||||
@ -1329,6 +1332,26 @@ ath10k_wmi_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
|
||||
ar->wmi.cmd->pdev_enable_adaptive_cca_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_ext_resource_config(struct ath10k *ar,
|
||||
enum wmi_host_platform_type type,
|
||||
u32 fw_feature_bitmap)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!ar->wmi.ops->ext_resource_config)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
skb = ar->wmi.ops->ext_resource_config(ar, type,
|
||||
fw_feature_bitmap);
|
||||
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb,
|
||||
ar->wmi.cmd->ext_resource_cfg_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype)
|
||||
{
|
||||
|
@ -705,6 +705,7 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = {
|
||||
.set_cca_params_cmdid = WMI_10_4_SET_CCA_PARAMS_CMDID,
|
||||
.pdev_bss_chan_info_request_cmdid =
|
||||
WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
|
||||
.ext_resource_cfg_cmdid = WMI_10_4_EXT_RESOURCE_CFG_CMDID,
|
||||
};
|
||||
|
||||
/* MAIN WMI VDEV param map */
|
||||
@ -2099,34 +2100,6 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ieee80211_band phy_mode_to_band(u32 phy_mode)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
|
||||
switch (phy_mode) {
|
||||
case MODE_11A:
|
||||
case MODE_11NA_HT20:
|
||||
case MODE_11NA_HT40:
|
||||
case MODE_11AC_VHT20:
|
||||
case MODE_11AC_VHT40:
|
||||
case MODE_11AC_VHT80:
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
break;
|
||||
case MODE_11G:
|
||||
case MODE_11B:
|
||||
case MODE_11GONLY:
|
||||
case MODE_11NG_HT20:
|
||||
case MODE_11NG_HT40:
|
||||
case MODE_11AC_VHT20_2G:
|
||||
case MODE_11AC_VHT40_2G:
|
||||
case MODE_11AC_VHT80_2G:
|
||||
default:
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
}
|
||||
|
||||
return band;
|
||||
}
|
||||
|
||||
/* If keys are configured, HW decrypts all frames
|
||||
* with protected bit set. Mark such frames as decrypted.
|
||||
*/
|
||||
@ -2167,8 +2140,10 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
|
||||
struct wmi_mgmt_rx_event_v1 *ev_v1;
|
||||
struct wmi_mgmt_rx_event_v2 *ev_v2;
|
||||
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
|
||||
struct wmi_mgmt_rx_ext_info *ext_info;
|
||||
size_t pull_len;
|
||||
u32 msdu_len;
|
||||
u32 len;
|
||||
|
||||
if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
|
||||
ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
|
||||
@ -2195,6 +2170,12 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
|
||||
if (skb->len < msdu_len)
|
||||
return -EPROTO;
|
||||
|
||||
if (le32_to_cpu(arg->status) & WMI_RX_STATUS_EXT_INFO) {
|
||||
len = ALIGN(le32_to_cpu(arg->buf_len), 4);
|
||||
ext_info = (struct wmi_mgmt_rx_ext_info *)(skb->data + len);
|
||||
memcpy(&arg->ext_info, ext_info,
|
||||
sizeof(struct wmi_mgmt_rx_ext_info));
|
||||
}
|
||||
/* the WMI buffer might've ended up being padded to 4 bytes due to HTC
|
||||
* trailer with credit update. Trim the excess garbage.
|
||||
*/
|
||||
@ -2211,6 +2192,8 @@ static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar,
|
||||
struct wmi_10_4_mgmt_rx_hdr *ev_hdr;
|
||||
size_t pull_len;
|
||||
u32 msdu_len;
|
||||
struct wmi_mgmt_rx_ext_info *ext_info;
|
||||
u32 len;
|
||||
|
||||
ev = (struct wmi_10_4_mgmt_rx_event *)skb->data;
|
||||
ev_hdr = &ev->hdr;
|
||||
@ -2231,6 +2214,13 @@ static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar,
|
||||
if (skb->len < msdu_len)
|
||||
return -EPROTO;
|
||||
|
||||
if (le32_to_cpu(arg->status) & WMI_RX_STATUS_EXT_INFO) {
|
||||
len = ALIGN(le32_to_cpu(arg->buf_len), 4);
|
||||
ext_info = (struct wmi_mgmt_rx_ext_info *)(skb->data + len);
|
||||
memcpy(&arg->ext_info, ext_info,
|
||||
sizeof(struct wmi_mgmt_rx_ext_info));
|
||||
}
|
||||
|
||||
/* Make sure bytes added for padding are removed. */
|
||||
skb_trim(skb, msdu_len);
|
||||
|
||||
@ -2281,6 +2271,11 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
if (rx_status & WMI_RX_STATUS_ERR_MIC)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (rx_status & WMI_RX_STATUS_EXT_INFO) {
|
||||
status->mactime =
|
||||
__le64_to_cpu(arg.ext_info.rx_mac_timestamp);
|
||||
status->flag |= RX_FLAG_MACTIME_END;
|
||||
}
|
||||
/* Hardware can Rx CCK rates on 5GHz. In that case phy_mode is set to
|
||||
* MODE_11B. This means phy_mode is not a reliable source for the band
|
||||
* of mgmt rx.
|
||||
@ -2310,6 +2305,12 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
/* Firmware is guaranteed to report all essential management frames via
|
||||
* WMI while it can deliver some extra via HTT. Since there can be
|
||||
* duplicates split the reporting wrt monitor/sniffing.
|
||||
*/
|
||||
status->flag |= RX_FLAG_SKIP_MONITOR;
|
||||
|
||||
ath10k_wmi_handle_wep_reauth(ar, skb, status);
|
||||
|
||||
/* FW delivers WEP Shared Auth frame with Protected Bit set and
|
||||
@ -2612,6 +2613,16 @@ void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
|
||||
dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_10_4_pull_peer_stats(const struct wmi_10_4_peer_stats *src,
|
||||
struct ath10k_fw_stats_peer *dst)
|
||||
{
|
||||
ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
|
||||
dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
|
||||
dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
|
||||
dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
|
||||
}
|
||||
|
||||
static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
|
||||
struct sk_buff *skb,
|
||||
struct ath10k_fw_stats *stats)
|
||||
@ -2865,11 +2876,8 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
const struct wmi_10_2_4_ext_peer_stats *src;
|
||||
struct ath10k_fw_stats_peer *dst;
|
||||
int stats_len;
|
||||
bool ext_peer_stats_support;
|
||||
|
||||
ext_peer_stats_support = test_bit(WMI_SERVICE_PEER_STATS,
|
||||
ar->wmi.svc_map);
|
||||
if (ext_peer_stats_support)
|
||||
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
|
||||
stats_len = sizeof(struct wmi_10_2_4_ext_peer_stats);
|
||||
else
|
||||
stats_len = sizeof(struct wmi_10_2_4_peer_stats);
|
||||
@ -2886,7 +2894,7 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
|
||||
dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate);
|
||||
|
||||
if (ext_peer_stats_support)
|
||||
if (ath10k_peer_stats_enabled(ar))
|
||||
dst->rx_duration = __le32_to_cpu(src->rx_duration);
|
||||
/* FIXME: expose 10.2 specific values */
|
||||
|
||||
@ -2905,6 +2913,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
u32 num_pdev_ext_stats;
|
||||
u32 num_vdev_stats;
|
||||
u32 num_peer_stats;
|
||||
u32 stats_id;
|
||||
int i;
|
||||
|
||||
if (!skb_pull(skb, sizeof(*ev)))
|
||||
@ -2914,6 +2923,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
|
||||
num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
|
||||
num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
|
||||
stats_id = __le32_to_cpu(ev->stats_id);
|
||||
|
||||
for (i = 0; i < num_pdev_stats; i++) {
|
||||
const struct wmi_10_4_pdev_stats *src;
|
||||
@ -2953,22 +2963,28 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
/* fw doesn't implement vdev stats */
|
||||
|
||||
for (i = 0; i < num_peer_stats; i++) {
|
||||
const struct wmi_10_4_peer_stats *src;
|
||||
const struct wmi_10_4_peer_extd_stats *src;
|
||||
struct ath10k_fw_stats_peer *dst;
|
||||
int stats_len;
|
||||
bool extd_peer_stats = !!(stats_id & WMI_10_4_STAT_PEER_EXTD);
|
||||
|
||||
if (extd_peer_stats)
|
||||
stats_len = sizeof(struct wmi_10_4_peer_extd_stats);
|
||||
else
|
||||
stats_len = sizeof(struct wmi_10_4_peer_stats);
|
||||
|
||||
src = (void *)skb->data;
|
||||
if (!skb_pull(skb, sizeof(*src)))
|
||||
if (!skb_pull(skb, stats_len))
|
||||
return -EPROTO;
|
||||
|
||||
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
|
||||
if (!dst)
|
||||
continue;
|
||||
|
||||
ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
|
||||
dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
|
||||
dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
|
||||
dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
|
||||
ath10k_wmi_10_4_pull_peer_stats(&src->common, dst);
|
||||
/* FIXME: expose 10.4 specific values */
|
||||
if (extd_peer_stats)
|
||||
dst->rx_duration = __le32_to_cpu(src->rx_duration);
|
||||
|
||||
list_add_tail(&dst->list, &stats->peers);
|
||||
}
|
||||
@ -4617,10 +4633,16 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) {
|
||||
if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
|
||||
ar->fw_features))
|
||||
ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS_PFC +
|
||||
ar->max_num_vdevs;
|
||||
else
|
||||
ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS +
|
||||
ar->max_num_vdevs;
|
||||
|
||||
ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX +
|
||||
ar->max_num_vdevs;
|
||||
ar->num_active_peers = ar->hw_params.qcache_active_peers +
|
||||
ar->max_num_vdevs;
|
||||
ar->num_tids = ar->num_active_peers * 2;
|
||||
ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX;
|
||||
}
|
||||
@ -5517,7 +5539,8 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
|
||||
|
||||
config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
|
||||
config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
|
||||
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
|
||||
|
||||
if (ath10k_peer_stats_enabled(ar)) {
|
||||
config.num_peers = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_PEERS);
|
||||
config.num_tids = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_TIDS);
|
||||
} else {
|
||||
@ -5579,7 +5602,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
|
||||
test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
|
||||
features |= WMI_10_2_COEX_GPIO;
|
||||
|
||||
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
|
||||
if (ath10k_peer_stats_enabled(ar))
|
||||
features |= WMI_10_2_PEER_STATS;
|
||||
|
||||
cmd->resource_config.feature_mask = __cpu_to_le32(features);
|
||||
@ -7484,6 +7507,28 @@ static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar,
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_10_4_ext_resource_config(struct ath10k *ar,
|
||||
enum wmi_host_platform_type type,
|
||||
u32 fw_feature_bitmap)
|
||||
{
|
||||
struct wmi_ext_resource_config_10_4_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cmd = (struct wmi_ext_resource_config_10_4_cmd *)skb->data;
|
||||
cmd->host_platform_config = __cpu_to_le32(type);
|
||||
cmd->fw_feature_bitmap = __cpu_to_le32(fw_feature_bitmap);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi ext resource config host type %d firmware feature bitmap %08x\n",
|
||||
type, fw_feature_bitmap);
|
||||
return skb;
|
||||
}
|
||||
|
||||
static const struct wmi_ops wmi_ops = {
|
||||
.rx = ath10k_wmi_op_rx,
|
||||
.map_svc = wmi_main_svc_map,
|
||||
@ -7810,6 +7855,7 @@ static const struct wmi_ops wmi_10_4_ops = {
|
||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||
.fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill,
|
||||
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
|
||||
|
||||
/* shared with 10.2 */
|
||||
.gen_request_stats = ath10k_wmi_op_gen_request_stats,
|
||||
|
@ -816,6 +816,7 @@ struct wmi_cmd_map {
|
||||
u32 set_cca_params_cmdid;
|
||||
u32 pdev_bss_chan_info_request_cmdid;
|
||||
u32 pdev_enable_adaptive_cca_cmdid;
|
||||
u32 ext_resource_cfg_cmdid;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2667,6 +2668,31 @@ struct wmi_resource_config_10_4 {
|
||||
__le32 qwrap_config;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum wmi_10_4_feature_mask - WMI 10.4 feature enable/disable flags
|
||||
* @WMI_10_4_LTEU_SUPPORT: LTEU config
|
||||
* @WMI_10_4_COEX_GPIO_SUPPORT: COEX GPIO config
|
||||
* @WMI_10_4_AUX_RADIO_SPECTRAL_INTF: AUX Radio Enhancement for spectral scan
|
||||
* @WMI_10_4_AUX_RADIO_CHAN_LOAD_INTF: AUX Radio Enhancement for chan load scan
|
||||
* @WMI_10_4_BSS_CHANNEL_INFO_64: BSS channel info stats
|
||||
* @WMI_10_4_PEER_STATS: Per station stats
|
||||
*/
|
||||
enum wmi_10_4_feature_mask {
|
||||
WMI_10_4_LTEU_SUPPORT = BIT(0),
|
||||
WMI_10_4_COEX_GPIO_SUPPORT = BIT(1),
|
||||
WMI_10_4_AUX_RADIO_SPECTRAL_INTF = BIT(2),
|
||||
WMI_10_4_AUX_RADIO_CHAN_LOAD_INTF = BIT(3),
|
||||
WMI_10_4_BSS_CHANNEL_INFO_64 = BIT(4),
|
||||
WMI_10_4_PEER_STATS = BIT(5),
|
||||
};
|
||||
|
||||
struct wmi_ext_resource_config_10_4_cmd {
|
||||
/* contains enum wmi_host_platform_type */
|
||||
__le32 host_platform_config;
|
||||
/* see enum wmi_10_4_feature_mask */
|
||||
__le32 fw_feature_bitmap;
|
||||
};
|
||||
|
||||
/* strucutre describing host memory chunk. */
|
||||
struct host_memory_chunk {
|
||||
/* id of the request that is passed up in service ready */
|
||||
@ -3037,11 +3063,17 @@ struct wmi_10_4_mgmt_rx_event {
|
||||
u8 buf[0];
|
||||
} __packed;
|
||||
|
||||
struct wmi_mgmt_rx_ext_info {
|
||||
__le64 rx_mac_timestamp;
|
||||
} __packed __aligned(4);
|
||||
|
||||
#define WMI_RX_STATUS_OK 0x00
|
||||
#define WMI_RX_STATUS_ERR_CRC 0x01
|
||||
#define WMI_RX_STATUS_ERR_DECRYPT 0x08
|
||||
#define WMI_RX_STATUS_ERR_MIC 0x10
|
||||
#define WMI_RX_STATUS_ERR_KEY_CACHE_MISS 0x20
|
||||
/* Extension data at the end of mgmt frame */
|
||||
#define WMI_RX_STATUS_EXT_INFO 0x40
|
||||
|
||||
#define PHY_ERROR_GEN_SPECTRAL_SCAN 0x26
|
||||
#define PHY_ERROR_GEN_FALSE_RADAR_EXT 0x24
|
||||
@ -4072,6 +4104,13 @@ enum wmi_stats_id {
|
||||
WMI_STAT_VDEV_RATE = BIT(5),
|
||||
};
|
||||
|
||||
enum wmi_10_4_stats_id {
|
||||
WMI_10_4_STAT_PEER = BIT(0),
|
||||
WMI_10_4_STAT_AP = BIT(1),
|
||||
WMI_10_4_STAT_INST = BIT(2),
|
||||
WMI_10_4_STAT_PEER_EXTD = BIT(3),
|
||||
};
|
||||
|
||||
struct wlan_inst_rssi_args {
|
||||
__le16 cfg_retry_count;
|
||||
__le16 retry_count;
|
||||
@ -4271,6 +4310,15 @@ struct wmi_10_4_peer_stats {
|
||||
__le32 peer_rssi_changed;
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_4_peer_extd_stats {
|
||||
struct wmi_10_4_peer_stats common;
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
__le32 inactive_time;
|
||||
__le32 peer_chain_rssi;
|
||||
__le32 rx_duration;
|
||||
__le32 reserved[10];
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_2_pdev_ext_stats {
|
||||
__le32 rx_rssi_comb;
|
||||
__le32 rx_rssi[4];
|
||||
@ -6116,6 +6164,7 @@ struct wmi_mgmt_rx_ev_arg {
|
||||
__le32 phy_mode;
|
||||
__le32 buf_len;
|
||||
__le32 status; /* %WMI_RX_STATUS_ */
|
||||
struct wmi_mgmt_rx_ext_info ext_info;
|
||||
};
|
||||
|
||||
struct wmi_ch_info_ev_arg {
|
||||
@ -6401,6 +6450,11 @@ struct wmi_pdev_set_adaptive_cca_params {
|
||||
__le32 cca_detect_margin;
|
||||
} __packed;
|
||||
|
||||
enum wmi_host_platform_type {
|
||||
WMI_HOST_PLATFORM_HIGH_PERF,
|
||||
WMI_HOST_PLATFORM_LOW_PERF,
|
||||
};
|
||||
|
||||
struct ath10k;
|
||||
struct ath10k_vif;
|
||||
struct ath10k_fw_stats_pdev;
|
||||
|
@ -77,7 +77,7 @@ static const struct pci_device_id ath5k_led_devices[] = {
|
||||
/* HP Compaq CQ60-206US (ddreggors@jumptv.com) */
|
||||
{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) },
|
||||
/* HP Compaq C700 (nitrousnrg@gmail.com) */
|
||||
{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
|
||||
{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 0) },
|
||||
/* LiteOn AR5BXB63 (magooz@salug.it) */
|
||||
{ ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) },
|
||||
/* IBM-specific AR5212 (all others) */
|
||||
|
@ -1446,7 +1446,7 @@ ath5k_hw_channel(struct ath5k_hw *ah,
|
||||
"channel frequency (%u MHz) out of supported "
|
||||
"band range\n",
|
||||
channel->center_freq);
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -634,7 +634,7 @@ ath5k_hw_on_hold(struct ath5k_hw *ah)
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
||||
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
||||
usleep_range(2000, 2500);
|
||||
usleep_range(2000, 2500);
|
||||
} else {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
@ -699,7 +699,7 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
||||
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
||||
usleep_range(2000, 2500);
|
||||
usleep_range(2000, 2500);
|
||||
} else {
|
||||
if (ath5k_get_bus_type(ah) == ATH_AHB)
|
||||
ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
|
@ -1584,6 +1584,11 @@ static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
if (len < sizeof(*ev))
|
||||
return -EINVAL;
|
||||
|
||||
if (vif->nw_type != INFRA_NETWORK ||
|
||||
!test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
|
||||
vif->ar->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (vif->sme_state != SME_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
|
@ -331,7 +331,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -351,7 +351,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -1203,12 +1203,12 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
|
||||
static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
|
||||
{
|
||||
int offset[8] = {0}, total = 0, test;
|
||||
int agc_out, i, peak_detect_threshold;
|
||||
int agc_out, i, peak_detect_threshold = 0;
|
||||
|
||||
if (AR_SREV_9550(ah) || AR_SREV_9531(ah))
|
||||
peak_detect_threshold = 8;
|
||||
else
|
||||
peak_detect_threshold = 0;
|
||||
else if (AR_SREV_9561(ah))
|
||||
peak_detect_threshold = 11;
|
||||
|
||||
/*
|
||||
* Turn off LNA/SW.
|
||||
@ -1249,17 +1249,14 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
|
||||
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
|
||||
|
||||
if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
|
||||
AR_SREV_9561(ah)) {
|
||||
if (is_2g)
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
|
||||
AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
|
||||
peak_detect_threshold);
|
||||
else
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
|
||||
AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,
|
||||
peak_detect_threshold);
|
||||
}
|
||||
if (is_2g)
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
|
||||
AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
|
||||
peak_detect_threshold);
|
||||
else
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
|
||||
AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,
|
||||
peak_detect_threshold);
|
||||
|
||||
for (i = 6; i > 0; i--) {
|
||||
offset[i] = BIT(i - 1);
|
||||
@ -1311,9 +1308,6 @@ static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah,
|
||||
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||
int i;
|
||||
|
||||
if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
|
||||
return;
|
||||
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal)
|
||||
return;
|
||||
|
||||
@ -1641,14 +1635,12 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
|
||||
|
||||
skip_tx_iqcal:
|
||||
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
|
||||
if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) ||
|
||||
AR_SREV_9561(ah)) {
|
||||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||||
if (!(ah->rxchainmask & (1 << i)))
|
||||
continue;
|
||||
ar9003_hw_manual_peak_cal(ah, i,
|
||||
IS_CHAN_2GHZ(chan));
|
||||
}
|
||||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||||
if (!(ah->rxchainmask & (1 << i)))
|
||||
continue;
|
||||
|
||||
ar9003_hw_manual_peak_cal(ah, i,
|
||||
IS_CHAN_2GHZ(chan));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1709,7 +1701,7 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
|
||||
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
|
||||
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
|
||||
|
||||
if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9565(ah))
|
||||
if (AR_SREV_9003_PCOEM(ah))
|
||||
priv_ops->init_cal = ar9003_hw_init_cal_pcoem;
|
||||
else
|
||||
priv_ops->init_cal = ar9003_hw_init_cal_soc;
|
||||
|
@ -3590,8 +3590,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
||||
else
|
||||
gpio = AR9300_EXT_LNA_CTL_GPIO_AR9485;
|
||||
|
||||
ath9k_hw_cfg_output(ah, gpio,
|
||||
AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED);
|
||||
ath9k_hw_gpio_request_out(ah, gpio, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED);
|
||||
}
|
||||
|
||||
value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
|
||||
@ -4097,16 +4097,16 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah)
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
|
||||
AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on);
|
||||
|
||||
therm_on = (thermometer < 0) ? 0 : (thermometer == 0);
|
||||
therm_on = thermometer == 0;
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4,
|
||||
AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on);
|
||||
if (pCap->chip_chainmask & BIT(1)) {
|
||||
therm_on = (thermometer < 0) ? 0 : (thermometer == 1);
|
||||
therm_on = thermometer == 1;
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4,
|
||||
AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on);
|
||||
}
|
||||
if (pCap->chip_chainmask & BIT(2)) {
|
||||
therm_on = (thermometer < 0) ? 0 : (thermometer == 2);
|
||||
therm_on = thermometer == 2;
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4,
|
||||
AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on);
|
||||
}
|
||||
|
@ -427,21 +427,34 @@ static void ar9003_mci_observation_set_up(struct ath_hw *ah)
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
|
||||
if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
|
||||
ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
|
||||
ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
|
||||
ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
|
||||
ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
|
||||
ath9k_hw_gpio_request_out(ah, 3, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
|
||||
ath9k_hw_gpio_request_out(ah, 2, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
|
||||
ath9k_hw_gpio_request_out(ah, 1, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
|
||||
ath9k_hw_gpio_request_out(ah, 0, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
|
||||
} else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {
|
||||
ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
|
||||
ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
|
||||
ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
|
||||
ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
|
||||
ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_gpio_request_out(ah, 3, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
|
||||
ath9k_hw_gpio_request_out(ah, 2, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
|
||||
ath9k_hw_gpio_request_out(ah, 1, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
|
||||
ath9k_hw_gpio_request_out(ah, 0, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
|
||||
ath9k_hw_gpio_request_out(ah, 5, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
} else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {
|
||||
ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
|
||||
ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
|
||||
ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
|
||||
ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
|
||||
ath9k_hw_gpio_request_out(ah, 3, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
|
||||
ath9k_hw_gpio_request_out(ah, 2, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
|
||||
ath9k_hw_gpio_request_out(ah, 1, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
|
||||
ath9k_hw_gpio_request_out(ah, 0, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
|
||||
} else
|
||||
return;
|
||||
|
||||
|
@ -1337,11 +1337,11 @@ skip_ws_det:
|
||||
chan->channel,
|
||||
aniState->mrcCCK ? "on" : "off",
|
||||
is_on ? "on" : "off");
|
||||
if (is_on)
|
||||
ah->stats.ast_ani_ccklow++;
|
||||
else
|
||||
ah->stats.ast_ani_cckhigh++;
|
||||
aniState->mrcCCK = is_on;
|
||||
if (is_on)
|
||||
ah->stats.ast_ani_ccklow++;
|
||||
else
|
||||
ah->stats.ast_ani_cckhigh++;
|
||||
aniState->mrcCCK = is_on;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221},
|
||||
{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -59,7 +59,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982},
|
||||
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -345,7 +345,7 @@ static const u32 ar9331_1p2_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221},
|
||||
{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -364,7 +364,7 @@ static const u32 ar9331_1p2_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981},
|
||||
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -245,7 +245,7 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -265,7 +265,7 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
|
||||
{0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00041983, 0x00041983, 0x00041982, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -59,7 +59,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c780, 0xcfd5c280},
|
||||
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -79,7 +79,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -239,7 +239,7 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c780, 0xcfd5c280},
|
||||
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -259,7 +259,7 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -1026,7 +1026,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
|
||||
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
|
||||
{0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53},
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
{0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
|
||||
@ -1044,7 +1044,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
|
||||
{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
|
||||
{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -988,7 +988,7 @@ static const u32 qca953x_2p0_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -1008,7 +1008,7 @@ static const u32 qca953x_2p0_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
|
||||
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
|
@ -83,7 +83,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
|
||||
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
|
@ -347,7 +347,7 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003a4, 0x000003a4},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946220, 0xcf946220},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
|
@ -220,7 +220,7 @@ static const u32 qca956x_1p0_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003a6, 0x000003a6},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
|
@ -1290,7 +1290,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = {
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220},
|
||||
{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
@ -1310,7 +1310,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = {
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
|
||||
{0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
|
@ -813,7 +813,6 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
void ath_init_leds(struct ath_softc *sc);
|
||||
void ath_deinit_leds(struct ath_softc *sc);
|
||||
void ath_fill_led_pin(struct ath_softc *sc);
|
||||
#else
|
||||
static inline void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
@ -822,9 +821,6 @@ static inline void ath_init_leds(struct ath_softc *sc)
|
||||
static inline void ath_deinit_leds(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
static inline void ath_fill_led_pin(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************/
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/ath9k_platform.h>
|
||||
#include "hw.h"
|
||||
|
||||
enum ath_bt_mode {
|
||||
@ -34,6 +36,8 @@ struct ath_btcoex_config {
|
||||
u8 bt_priority_time;
|
||||
u8 bt_first_slot_time;
|
||||
bool bt_hold_rx_clear;
|
||||
u8 wl_active_time;
|
||||
u8 wl_qc_time;
|
||||
};
|
||||
|
||||
static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX]
|
||||
@ -65,31 +69,71 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
|
||||
.bt_priority_time = 2,
|
||||
.bt_first_slot_time = 5,
|
||||
.bt_hold_rx_clear = true,
|
||||
.wl_active_time = 0x20,
|
||||
.wl_qc_time = 0x20,
|
||||
};
|
||||
bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
|
||||
u8 time_extend = ath_bt_config.bt_time_extend;
|
||||
u8 first_slot_time = ath_bt_config.bt_first_slot_time;
|
||||
|
||||
if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
|
||||
|
||||
if (AR_SREV_SOC(ah)) {
|
||||
first_slot_time = 0x1d;
|
||||
time_extend = 0xa;
|
||||
|
||||
btcoex_hw->bt_coex_mode3 =
|
||||
SM(ath_bt_config.wl_active_time, AR_BT_WL_ACTIVE_TIME) |
|
||||
SM(ath_bt_config.wl_qc_time, AR_BT_WL_QC_TIME);
|
||||
|
||||
btcoex_hw->bt_coex_mode2 =
|
||||
AR_BT_PROTECT_BT_AFTER_WAKEUP |
|
||||
AR_BT_PHY_ERR_BT_COLL_ENABLE;
|
||||
}
|
||||
|
||||
btcoex_hw->bt_coex_mode =
|
||||
(btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
|
||||
SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
|
||||
SM(time_extend, AR_BT_TIME_EXTEND) |
|
||||
SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
|
||||
SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
|
||||
SM(ath_bt_config.bt_mode, AR_BT_MODE) |
|
||||
SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
|
||||
SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
|
||||
SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
|
||||
SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
|
||||
SM(first_slot_time, AR_BT_FIRST_SLOT_TIME) |
|
||||
SM(qnum, AR_BT_QCU_THRESH);
|
||||
|
||||
btcoex_hw->bt_coex_mode2 =
|
||||
btcoex_hw->bt_coex_mode2 |=
|
||||
SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
|
||||
SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
|
||||
AR_BT_DISABLE_BT_ANT;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
|
||||
|
||||
static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio,
|
||||
u8 btactive_gpio, u8 btpriority_gpio)
|
||||
{
|
||||
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
||||
struct ath9k_platform_data *pdata = ah->dev->platform_data;
|
||||
|
||||
if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE &&
|
||||
btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE)
|
||||
return;
|
||||
|
||||
/* bt priority GPIO will be ignored by 2 wire scheme */
|
||||
if (pdata && (pdata->bt_active_pin || pdata->bt_priority_pin ||
|
||||
pdata->wlan_active_pin)) {
|
||||
btcoex_hw->btactive_gpio = pdata->bt_active_pin;
|
||||
btcoex_hw->wlanactive_gpio = pdata->wlan_active_pin;
|
||||
btcoex_hw->btpriority_gpio = pdata->bt_priority_pin;
|
||||
} else {
|
||||
btcoex_hw->btactive_gpio = btactive_gpio;
|
||||
btcoex_hw->wlanactive_gpio = wlanactive_gpio;
|
||||
btcoex_hw->btpriority_gpio = btpriority_gpio;
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
@ -107,19 +151,19 @@ void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
|
||||
btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
|
||||
} else if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
|
||||
btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
|
||||
btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
|
||||
btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
|
||||
} else if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
|
||||
btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
|
||||
|
||||
if (AR_SREV_9285(ah)) {
|
||||
ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9300,
|
||||
ATH_BTACTIVE_GPIO_9300,
|
||||
ATH_BTPRIORITY_GPIO_9300);
|
||||
} else if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
if (AR_SREV_9285(ah))
|
||||
btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
|
||||
btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285;
|
||||
} else {
|
||||
else
|
||||
btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
|
||||
}
|
||||
|
||||
ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9280,
|
||||
ATH_BTACTIVE_GPIO_9280,
|
||||
ATH_BTPRIORITY_GPIO_9285);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme);
|
||||
@ -137,12 +181,14 @@ void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
|
||||
AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
|
||||
|
||||
/* Set input mux for bt_active to gpio pin */
|
||||
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
|
||||
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
|
||||
btcoex_hw->btactive_gpio);
|
||||
if (!AR_SREV_SOC(ah))
|
||||
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
|
||||
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
|
||||
btcoex_hw->btactive_gpio);
|
||||
|
||||
/* Configure the desired gpio port for input */
|
||||
ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
|
||||
ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio,
|
||||
"ath9k-btactive");
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire);
|
||||
|
||||
@ -157,21 +203,33 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
|
||||
|
||||
/* Set input mux for bt_prority_async and
|
||||
* bt_active_async to GPIO pins */
|
||||
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
|
||||
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
|
||||
btcoex_hw->btactive_gpio);
|
||||
|
||||
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
|
||||
AR_GPIO_INPUT_MUX1_BT_PRIORITY,
|
||||
btcoex_hw->btpriority_gpio);
|
||||
if (!AR_SREV_SOC(ah)) {
|
||||
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
|
||||
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
|
||||
btcoex_hw->btactive_gpio);
|
||||
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
|
||||
AR_GPIO_INPUT_MUX1_BT_PRIORITY,
|
||||
btcoex_hw->btpriority_gpio);
|
||||
}
|
||||
|
||||
/* Configure the desired GPIO ports for input */
|
||||
|
||||
ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
|
||||
ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio);
|
||||
ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio,
|
||||
"ath9k-btactive");
|
||||
ath9k_hw_gpio_request_in(ah, btcoex_hw->btpriority_gpio,
|
||||
"ath9k-btpriority");
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
|
||||
|
||||
void ath9k_hw_btcoex_deinit(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
||||
|
||||
ath9k_hw_gpio_free(ah, btcoex_hw->btactive_gpio);
|
||||
ath9k_hw_gpio_free(ah, btcoex_hw->btpriority_gpio);
|
||||
ath9k_hw_gpio_free(ah, btcoex_hw->wlanactive_gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_deinit);
|
||||
|
||||
void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
|
||||
{
|
||||
ah->btcoex_hw.mci.ready = false;
|
||||
@ -201,8 +259,9 @@ static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
|
||||
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
||||
|
||||
/* Configure the desired GPIO port for TX_FRAME output */
|
||||
ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
|
||||
AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
|
||||
ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio,
|
||||
"ath9k-wlanactive",
|
||||
AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -247,13 +306,13 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
|
||||
txprio_shift[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Last WLAN weight has to be adjusted wrt tx priority */
|
||||
if (concur_tx) {
|
||||
btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]);
|
||||
btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type]
|
||||
<< txprio_shift[i-1]);
|
||||
}
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
|
||||
|
||||
@ -268,9 +327,14 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
|
||||
* Program coex mode and weight registers to
|
||||
* enable coex 3-wire
|
||||
*/
|
||||
if (AR_SREV_SOC(ah))
|
||||
REG_CLR_BIT(ah, AR_BT_COEX_MODE2, AR_BT_PHY_ERR_BT_COLL_ENABLE);
|
||||
|
||||
REG_WRITE(ah, AR_BT_COEX_MODE, btcoex->bt_coex_mode);
|
||||
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
|
||||
|
||||
if (AR_SREV_SOC(ah))
|
||||
REG_WRITE(ah, AR_BT_COEX_MODE3, btcoex->bt_coex_mode3);
|
||||
|
||||
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, btcoex->wlan_weight[0]);
|
||||
@ -281,8 +345,6 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
|
||||
} else
|
||||
REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex->bt_coex_weights);
|
||||
|
||||
|
||||
|
||||
if (AR_SREV_9271(ah)) {
|
||||
val = REG_READ(ah, 0x50040);
|
||||
val &= 0xFFFFFEFF;
|
||||
@ -292,8 +354,9 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
|
||||
REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
|
||||
REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
|
||||
|
||||
ath9k_hw_cfg_output(ah, btcoex->wlanactive_gpio,
|
||||
AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
|
||||
ath9k_hw_gpio_request_out(ah, btcoex->wlanactive_gpio,
|
||||
"ath9k-wlanactive",
|
||||
AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
|
||||
}
|
||||
|
||||
static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah)
|
||||
@ -339,7 +402,8 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) {
|
||||
if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI &&
|
||||
!AR_SREV_SOC(ah)) {
|
||||
REG_RMW(ah, AR_GPIO_PDPU,
|
||||
(0x2 << (btcoex_hw->btactive_gpio * 2)),
|
||||
(0x3 << (btcoex_hw->btactive_gpio * 2)));
|
||||
@ -364,8 +428,8 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
|
||||
|
||||
ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio,
|
||||
NULL, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
|
||||
if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
|
||||
REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
|
||||
|
@ -115,6 +115,7 @@ struct ath_btcoex_hw {
|
||||
u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */
|
||||
u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */
|
||||
u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
|
||||
u32 bt_coex_mode3; /* Register setting for AR_BT_COEX_MODE3 */
|
||||
u32 bt_weight[AR9300_NUM_BT_WEIGHTS];
|
||||
u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
|
||||
u8 tx_prio[ATH_BTCOEX_STOMP_MAX];
|
||||
@ -123,6 +124,7 @@ struct ath_btcoex_hw {
|
||||
void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah);
|
||||
void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
|
||||
void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
|
||||
void ath9k_hw_btcoex_deinit(struct ath_hw *ah);
|
||||
void ath9k_hw_btcoex_init_mci(struct ath_hw *ah);
|
||||
void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
|
||||
void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
|
||||
|
@ -916,10 +916,21 @@ static int open_file_regdump(struct inode *inode, struct file *file)
|
||||
struct ath_softc *sc = inode->i_private;
|
||||
unsigned int len = 0;
|
||||
u8 *buf;
|
||||
int i;
|
||||
int i, j = 0;
|
||||
unsigned long num_regs, regdump_len, max_reg_offset;
|
||||
const struct reg_hole {
|
||||
u32 start;
|
||||
u32 end;
|
||||
} reg_hole_list[] = {
|
||||
{0x0200, 0x07fc},
|
||||
{0x0c00, 0x0ffc},
|
||||
{0x2000, 0x3ffc},
|
||||
{0x4100, 0x6ffc},
|
||||
{0x705c, 0x7ffc},
|
||||
{0x0000, 0x0000}
|
||||
};
|
||||
|
||||
max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x16bd4 : 0xb500;
|
||||
max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x8800 : 0xb500;
|
||||
num_regs = max_reg_offset / 4 + 1;
|
||||
regdump_len = num_regs * REGDUMP_LINE_SIZE + 1;
|
||||
buf = vmalloc(regdump_len);
|
||||
@ -927,9 +938,16 @@ static int open_file_regdump(struct inode *inode, struct file *file)
|
||||
return -ENOMEM;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
for (i = 0; i < num_regs; i++)
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
if (reg_hole_list[j].start == i << 2) {
|
||||
i = reg_hole_list[j].end >> 2;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, regdump_len - len,
|
||||
"0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2));
|
||||
}
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
file->private_data = buf;
|
||||
|
@ -21,6 +21,33 @@
|
||||
/********************************/
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
|
||||
void ath_fill_led_pin(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
/* Set default led pin if invalid */
|
||||
if (ah->led_pin < 0) {
|
||||
if (AR_SREV_9287(ah))
|
||||
ah->led_pin = ATH_LED_PIN_9287;
|
||||
else if (AR_SREV_9485(ah))
|
||||
ah->led_pin = ATH_LED_PIN_9485;
|
||||
else if (AR_SREV_9300(ah))
|
||||
ah->led_pin = ATH_LED_PIN_9300;
|
||||
else if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
|
||||
ah->led_pin = ATH_LED_PIN_9462;
|
||||
else
|
||||
ah->led_pin = ATH_LED_PIN_DEF;
|
||||
}
|
||||
|
||||
/* Configure gpio for output */
|
||||
ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led",
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
|
||||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1);
|
||||
}
|
||||
|
||||
static void ath_led_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
@ -40,6 +67,8 @@ void ath_deinit_leds(struct ath_softc *sc)
|
||||
|
||||
ath_led_brightness(&sc->led_cdev, LED_OFF);
|
||||
led_classdev_unregister(&sc->led_cdev);
|
||||
|
||||
ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin);
|
||||
}
|
||||
|
||||
void ath_init_leds(struct ath_softc *sc)
|
||||
@ -49,6 +78,8 @@ void ath_init_leds(struct ath_softc *sc)
|
||||
if (AR_SREV_9100(sc->sc_ah))
|
||||
return;
|
||||
|
||||
ath_fill_led_pin(sc);
|
||||
|
||||
if (!ath9k_led_blink)
|
||||
sc->led_cdev.default_trigger =
|
||||
ieee80211_get_radio_led_name(sc->hw);
|
||||
@ -64,37 +95,6 @@ void ath_init_leds(struct ath_softc *sc)
|
||||
|
||||
sc->led_registered = true;
|
||||
}
|
||||
|
||||
void ath_fill_led_pin(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (AR_SREV_9100(ah))
|
||||
return;
|
||||
|
||||
if (ah->led_pin >= 0) {
|
||||
if (!((1 << ah->led_pin) & AR_GPIO_OE_OUT_MASK))
|
||||
ath9k_hw_request_gpio(ah, ah->led_pin, "ath9k-led");
|
||||
return;
|
||||
}
|
||||
|
||||
if (AR_SREV_9287(ah))
|
||||
ah->led_pin = ATH_LED_PIN_9287;
|
||||
else if (AR_SREV_9485(sc->sc_ah))
|
||||
ah->led_pin = ATH_LED_PIN_9485;
|
||||
else if (AR_SREV_9300(sc->sc_ah))
|
||||
ah->led_pin = ATH_LED_PIN_9300;
|
||||
else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
|
||||
ah->led_pin = ATH_LED_PIN_9462;
|
||||
else
|
||||
ah->led_pin = ATH_LED_PIN_DEF;
|
||||
|
||||
/* Configure gpio 1 for output */
|
||||
ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
|
||||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************/
|
||||
@ -402,6 +402,13 @@ void ath9k_deinit_btcoex(struct ath_softc *sc)
|
||||
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ath_mci_cleanup(sc);
|
||||
else {
|
||||
enum ath_btcoex_scheme scheme = ath9k_hw_get_btcoex_scheme(ah);
|
||||
|
||||
if (scheme == ATH_BTCOEX_CFG_2WIRE ||
|
||||
scheme == ATH_BTCOEX_CFG_3WIRE)
|
||||
ath9k_hw_btcoex_deinit(sc->sc_ah);
|
||||
}
|
||||
}
|
||||
|
||||
int ath9k_init_btcoex(struct ath_softc *sc)
|
||||
|
@ -527,7 +527,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
|
||||
int index = 0, i = 0, len = skb->len;
|
||||
int index = 0, i, len = skb->len;
|
||||
int rx_remain_len, rx_pkt_len;
|
||||
u16 pool_index = 0;
|
||||
u8 *ptr;
|
||||
|
@ -253,17 +253,19 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
|
||||
ath9k_led_brightness(&priv->led_cdev, LED_OFF);
|
||||
led_classdev_unregister(&priv->led_cdev);
|
||||
cancel_work_sync(&priv->led_work);
|
||||
|
||||
ath9k_hw_gpio_free(priv->ah, priv->ah->led_pin);
|
||||
}
|
||||
|
||||
|
||||
void ath9k_configure_leds(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
/* Configure gpio 1 for output */
|
||||
ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_gpio_request_out(priv->ah, priv->ah->led_pin,
|
||||
"ath9k-led",
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
|
||||
|
||||
}
|
||||
|
||||
void ath9k_init_leds(struct ath9k_htc_priv *priv)
|
||||
|
@ -262,11 +262,11 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
|
||||
__be32 tmpval[8];
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
tmpaddr[i] = cpu_to_be32(addr[i]);
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
tmpaddr[i] = cpu_to_be32(addr[i]);
|
||||
}
|
||||
|
||||
ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
|
||||
ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
|
||||
(u8 *)tmpaddr , sizeof(u32) * count,
|
||||
(u8 *)tmpval, sizeof(u32) * count,
|
||||
100);
|
||||
@ -275,9 +275,9 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
|
||||
"Multiple REGISTER READ FAILED (count: %d)\n", count);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
val[i] = be32_to_cpu(tmpval[i]);
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
val[i] = be32_to_cpu(tmpval[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_regwrite_multi(struct ath_common *common)
|
||||
|
@ -1582,8 +1582,10 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
|
||||
if (!(gpio_mask & 1))
|
||||
continue;
|
||||
|
||||
ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_gpio_request_out(ah, i, NULL,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
|
||||
ath9k_hw_gpio_free(ah, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1958,7 +1960,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
ath9k_hw_init_qos(ah);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||
ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
|
||||
ath9k_hw_gpio_request_in(ah, ah->rfkill_gpio, "ath9k-rfkill");
|
||||
|
||||
ath9k_hw_init_global_settings(ah);
|
||||
|
||||
@ -2385,6 +2387,61 @@ static bool ath9k_hw_dfs_tested(struct ath_hw *ah)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_gpio_cap_init(struct ath_hw *ah)
|
||||
{
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
|
||||
if (AR_SREV_9271(ah)) {
|
||||
pCap->num_gpio_pins = AR9271_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9271_GPIO_MASK;
|
||||
} else if (AR_DEVID_7010(ah)) {
|
||||
pCap->num_gpio_pins = AR7010_NUM_GPIO;
|
||||
pCap->gpio_mask = AR7010_GPIO_MASK;
|
||||
} else if (AR_SREV_9287(ah)) {
|
||||
pCap->num_gpio_pins = AR9287_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9287_GPIO_MASK;
|
||||
} else if (AR_SREV_9285(ah)) {
|
||||
pCap->num_gpio_pins = AR9285_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9285_GPIO_MASK;
|
||||
} else if (AR_SREV_9280(ah)) {
|
||||
pCap->num_gpio_pins = AR9280_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9280_GPIO_MASK;
|
||||
} else if (AR_SREV_9300(ah)) {
|
||||
pCap->num_gpio_pins = AR9300_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9300_GPIO_MASK;
|
||||
} else if (AR_SREV_9330(ah)) {
|
||||
pCap->num_gpio_pins = AR9330_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9330_GPIO_MASK;
|
||||
} else if (AR_SREV_9340(ah)) {
|
||||
pCap->num_gpio_pins = AR9340_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9340_GPIO_MASK;
|
||||
} else if (AR_SREV_9462(ah)) {
|
||||
pCap->num_gpio_pins = AR9462_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9462_GPIO_MASK;
|
||||
} else if (AR_SREV_9485(ah)) {
|
||||
pCap->num_gpio_pins = AR9485_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9485_GPIO_MASK;
|
||||
} else if (AR_SREV_9531(ah)) {
|
||||
pCap->num_gpio_pins = AR9531_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9531_GPIO_MASK;
|
||||
} else if (AR_SREV_9550(ah)) {
|
||||
pCap->num_gpio_pins = AR9550_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9550_GPIO_MASK;
|
||||
} else if (AR_SREV_9561(ah)) {
|
||||
pCap->num_gpio_pins = AR9561_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9561_GPIO_MASK;
|
||||
} else if (AR_SREV_9565(ah)) {
|
||||
pCap->num_gpio_pins = AR9565_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9565_GPIO_MASK;
|
||||
} else if (AR_SREV_9580(ah)) {
|
||||
pCap->num_gpio_pins = AR9580_NUM_GPIO;
|
||||
pCap->gpio_mask = AR9580_GPIO_MASK;
|
||||
} else {
|
||||
pCap->num_gpio_pins = AR_NUM_GPIO;
|
||||
pCap->gpio_mask = AR_GPIO_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
||||
{
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
@ -2478,20 +2535,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
||||
else
|
||||
pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
|
||||
|
||||
if (AR_SREV_9271(ah))
|
||||
pCap->num_gpio_pins = AR9271_NUM_GPIO;
|
||||
else if (AR_DEVID_7010(ah))
|
||||
pCap->num_gpio_pins = AR7010_NUM_GPIO;
|
||||
else if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
pCap->num_gpio_pins = AR9300_NUM_GPIO;
|
||||
else if (AR_SREV_9287_11_OR_LATER(ah))
|
||||
pCap->num_gpio_pins = AR9287_NUM_GPIO;
|
||||
else if (AR_SREV_9285_12_OR_LATER(ah))
|
||||
pCap->num_gpio_pins = AR9285_NUM_GPIO;
|
||||
else if (AR_SREV_9280_20_OR_LATER(ah))
|
||||
pCap->num_gpio_pins = AR928X_NUM_GPIO;
|
||||
else
|
||||
pCap->num_gpio_pins = AR_NUM_GPIO;
|
||||
ath9k_gpio_cap_init(ah);
|
||||
|
||||
if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah))
|
||||
pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
|
||||
@ -2612,8 +2656,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
||||
/* GPIO / RFKILL / Antennae */
|
||||
/****************************/
|
||||
|
||||
static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
|
||||
u32 gpio, u32 type)
|
||||
static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type)
|
||||
{
|
||||
int addr;
|
||||
u32 gpio_shift, tmp;
|
||||
@ -2627,8 +2670,8 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
|
||||
|
||||
gpio_shift = (gpio % 6) * 5;
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah)
|
||||
|| (addr != AR_GPIO_OUTPUT_MUX1)) {
|
||||
if (AR_SREV_9280_20_OR_LATER(ah) ||
|
||||
(addr != AR_GPIO_OUTPUT_MUX1)) {
|
||||
REG_RMW(ah, addr, (type << gpio_shift),
|
||||
(0x1f << gpio_shift));
|
||||
} else {
|
||||
@ -2640,107 +2683,145 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
|
||||
/* BSP should set the corresponding MUX register correctly.
|
||||
*/
|
||||
static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
|
||||
const char *label)
|
||||
{
|
||||
u32 gpio_shift;
|
||||
if (ah->caps.gpio_requested & BIT(gpio))
|
||||
return;
|
||||
|
||||
BUG_ON(gpio >= ah->caps.num_gpio_pins);
|
||||
/* may be requested by BSP, free anyway */
|
||||
gpio_free(gpio);
|
||||
|
||||
if (gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label))
|
||||
return;
|
||||
|
||||
ah->caps.gpio_requested |= BIT(gpio);
|
||||
}
|
||||
|
||||
static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out,
|
||||
u32 ah_signal_type)
|
||||
{
|
||||
u32 gpio_set, gpio_shift = gpio;
|
||||
|
||||
if (AR_DEVID_7010(ah)) {
|
||||
gpio_shift = gpio;
|
||||
REG_RMW(ah, AR7010_GPIO_OE,
|
||||
(AR7010_GPIO_OE_AS_INPUT << gpio_shift),
|
||||
(AR7010_GPIO_OE_MASK << gpio_shift));
|
||||
return;
|
||||
}
|
||||
gpio_set = out ?
|
||||
AR7010_GPIO_OE_AS_OUTPUT : AR7010_GPIO_OE_AS_INPUT;
|
||||
REG_RMW(ah, AR7010_GPIO_OE, gpio_set << gpio_shift,
|
||||
AR7010_GPIO_OE_MASK << gpio_shift);
|
||||
} else if (AR_SREV_SOC(ah)) {
|
||||
gpio_set = out ? 1 : 0;
|
||||
REG_RMW(ah, AR_GPIO_OE_OUT, gpio_set << gpio_shift,
|
||||
gpio_set << gpio_shift);
|
||||
} else {
|
||||
gpio_shift = gpio << 1;
|
||||
gpio_set = out ?
|
||||
AR_GPIO_OE_OUT_DRV_ALL : AR_GPIO_OE_OUT_DRV_NO;
|
||||
REG_RMW(ah, AR_GPIO_OE_OUT, gpio_set << gpio_shift,
|
||||
AR_GPIO_OE_OUT_DRV << gpio_shift);
|
||||
|
||||
gpio_shift = gpio << 1;
|
||||
REG_RMW(ah,
|
||||
AR_GPIO_OE_OUT,
|
||||
(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
|
||||
(AR_GPIO_OE_OUT_DRV << gpio_shift));
|
||||
if (out)
|
||||
ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_cfg_gpio_input);
|
||||
|
||||
static void ath9k_hw_gpio_request(struct ath_hw *ah, u32 gpio, bool out,
|
||||
const char *label, u32 ah_signal_type)
|
||||
{
|
||||
WARN_ON(gpio >= ah->caps.num_gpio_pins);
|
||||
|
||||
if (BIT(gpio) & ah->caps.gpio_mask)
|
||||
ath9k_hw_gpio_cfg_wmac(ah, gpio, out, ah_signal_type);
|
||||
else if (AR_SREV_SOC(ah))
|
||||
ath9k_hw_gpio_cfg_soc(ah, gpio, out, label);
|
||||
else
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
void ath9k_hw_gpio_request_in(struct ath_hw *ah, u32 gpio, const char *label)
|
||||
{
|
||||
ath9k_hw_gpio_request(ah, gpio, false, label, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_gpio_request_in);
|
||||
|
||||
void ath9k_hw_gpio_request_out(struct ath_hw *ah, u32 gpio, const char *label,
|
||||
u32 ah_signal_type)
|
||||
{
|
||||
ath9k_hw_gpio_request(ah, gpio, true, label, ah_signal_type);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_gpio_request_out);
|
||||
|
||||
void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio)
|
||||
{
|
||||
if (!AR_SREV_SOC(ah))
|
||||
return;
|
||||
|
||||
WARN_ON(gpio >= ah->caps.num_gpio_pins);
|
||||
|
||||
if (ah->caps.gpio_requested & BIT(gpio)) {
|
||||
gpio_free(gpio);
|
||||
ah->caps.gpio_requested &= ~BIT(gpio);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_gpio_free);
|
||||
|
||||
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
|
||||
{
|
||||
u32 val = 0xffffffff;
|
||||
|
||||
#define MS_REG_READ(x, y) \
|
||||
(MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y)))
|
||||
(MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & BIT(y))
|
||||
|
||||
if (gpio >= ah->caps.num_gpio_pins)
|
||||
return 0xffffffff;
|
||||
WARN_ON(gpio >= ah->caps.num_gpio_pins);
|
||||
|
||||
if (AR_DEVID_7010(ah)) {
|
||||
u32 val;
|
||||
val = REG_READ(ah, AR7010_GPIO_IN);
|
||||
return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
|
||||
} else if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) &
|
||||
AR_GPIO_BIT(gpio)) != 0;
|
||||
else if (AR_SREV_9271(ah))
|
||||
return MS_REG_READ(AR9271, gpio) != 0;
|
||||
else if (AR_SREV_9287_11_OR_LATER(ah))
|
||||
return MS_REG_READ(AR9287, gpio) != 0;
|
||||
else if (AR_SREV_9285_12_OR_LATER(ah))
|
||||
return MS_REG_READ(AR9285, gpio) != 0;
|
||||
else if (AR_SREV_9280_20_OR_LATER(ah))
|
||||
return MS_REG_READ(AR928X, gpio) != 0;
|
||||
else
|
||||
return MS_REG_READ(AR, gpio) != 0;
|
||||
if (BIT(gpio) & ah->caps.gpio_mask) {
|
||||
if (AR_SREV_9271(ah))
|
||||
val = MS_REG_READ(AR9271, gpio);
|
||||
else if (AR_SREV_9287(ah))
|
||||
val = MS_REG_READ(AR9287, gpio);
|
||||
else if (AR_SREV_9285(ah))
|
||||
val = MS_REG_READ(AR9285, gpio);
|
||||
else if (AR_SREV_9280(ah))
|
||||
val = MS_REG_READ(AR928X, gpio);
|
||||
else if (AR_DEVID_7010(ah))
|
||||
val = REG_READ(ah, AR7010_GPIO_IN) & BIT(gpio);
|
||||
else if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
val = REG_READ(ah, AR_GPIO_IN) & BIT(gpio);
|
||||
else
|
||||
val = MS_REG_READ(AR, gpio);
|
||||
} else if (BIT(gpio) & ah->caps.gpio_requested) {
|
||||
val = gpio_get_value(gpio) & BIT(gpio);
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_gpio_get);
|
||||
|
||||
void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
|
||||
u32 ah_signal_type)
|
||||
{
|
||||
u32 gpio_shift;
|
||||
|
||||
if (AR_DEVID_7010(ah)) {
|
||||
gpio_shift = gpio;
|
||||
REG_RMW(ah, AR7010_GPIO_OE,
|
||||
(AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),
|
||||
(AR7010_GPIO_OE_MASK << gpio_shift));
|
||||
return;
|
||||
}
|
||||
|
||||
ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
|
||||
gpio_shift = 2 * gpio;
|
||||
REG_RMW(ah,
|
||||
AR_GPIO_OE_OUT,
|
||||
(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
|
||||
(AR_GPIO_OE_OUT_DRV << gpio_shift));
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_cfg_output);
|
||||
|
||||
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
|
||||
{
|
||||
if (AR_DEVID_7010(ah)) {
|
||||
val = val ? 0 : 1;
|
||||
REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),
|
||||
AR_GPIO_BIT(gpio));
|
||||
return;
|
||||
}
|
||||
WARN_ON(gpio >= ah->caps.num_gpio_pins);
|
||||
|
||||
if (AR_SREV_9271(ah))
|
||||
val = ~val;
|
||||
|
||||
if ((1 << gpio) & AR_GPIO_OE_OUT_MASK)
|
||||
REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
|
||||
AR_GPIO_BIT(gpio));
|
||||
if (AR_DEVID_7010(ah) || AR_SREV_9271(ah))
|
||||
val = !val;
|
||||
else
|
||||
gpio_set_value(gpio, val & 1);
|
||||
val = !!val;
|
||||
|
||||
if (BIT(gpio) & ah->caps.gpio_mask) {
|
||||
u32 out_addr = AR_DEVID_7010(ah) ?
|
||||
AR7010_GPIO_OUT : AR_GPIO_IN_OUT;
|
||||
|
||||
REG_RMW(ah, out_addr, val << gpio, BIT(gpio));
|
||||
} else if (BIT(gpio) & ah->caps.gpio_requested) {
|
||||
gpio_set_value(gpio, val);
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_set_gpio);
|
||||
|
||||
void ath9k_hw_request_gpio(struct ath_hw *ah, u32 gpio, const char *label)
|
||||
{
|
||||
if (gpio >= ah->caps.num_gpio_pins)
|
||||
return;
|
||||
|
||||
gpio_request_one(gpio, GPIOF_DIR_OUT | GPIOF_INIT_LOW, label);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_request_gpio);
|
||||
|
||||
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
|
||||
{
|
||||
REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
|
||||
|
@ -160,7 +160,6 @@
|
||||
#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA 0x1e
|
||||
|
||||
#define AR_GPIOD_MASK 0x00001FFF
|
||||
#define AR_GPIO_BIT(_gpio) (1 << (_gpio))
|
||||
|
||||
#define BASE_ACTIVATE_DELAY 100
|
||||
#define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100)
|
||||
@ -301,6 +300,8 @@ struct ath9k_hw_capabilities {
|
||||
u8 max_txchains;
|
||||
u8 max_rxchains;
|
||||
u8 num_gpio_pins;
|
||||
u32 gpio_mask;
|
||||
u32 gpio_requested;
|
||||
u8 rx_hp_qdepth;
|
||||
u8 rx_lp_qdepth;
|
||||
u8 rx_status_len;
|
||||
@ -1019,12 +1020,12 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah);
|
||||
u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
|
||||
|
||||
/* GPIO / RFKILL / Antennae */
|
||||
void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
|
||||
void ath9k_hw_gpio_request_in(struct ath_hw *ah, u32 gpio, const char *label);
|
||||
void ath9k_hw_gpio_request_out(struct ath_hw *ah, u32 gpio, const char *label,
|
||||
u32 ah_signal_type);
|
||||
void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio);
|
||||
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
|
||||
void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
|
||||
u32 ah_signal_type);
|
||||
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
|
||||
void ath9k_hw_request_gpio(struct ath_hw *ah, u32 gpio, const char *label);
|
||||
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
|
||||
|
||||
/* General Operation */
|
||||
|
@ -660,7 +660,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
|
||||
ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
ath9k_init_misc(sc);
|
||||
ath_fill_led_pin(sc);
|
||||
ath_chanctx_init(sc);
|
||||
ath9k_offchannel_init(sc);
|
||||
|
||||
|
@ -718,12 +718,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
if (!ath_complete_reset(sc, false))
|
||||
ah->reset_power_on = false;
|
||||
|
||||
if (ah->led_pin >= 0) {
|
||||
ath9k_hw_cfg_output(ah, ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
if (ah->led_pin >= 0)
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin,
|
||||
(ah->config.led_active_high) ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset key cache to sane defaults (all entries cleared) instead of
|
||||
@ -867,11 +864,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
if (ah->led_pin >= 0) {
|
||||
if (ah->led_pin >= 0)
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin,
|
||||
(ah->config.led_active_high) ? 0 : 1);
|
||||
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
|
||||
}
|
||||
|
||||
ath_prepare_reset(sc);
|
||||
|
||||
|
@ -985,6 +985,10 @@
|
||||
#define AR_SREV_9561(_ah) \
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9561))
|
||||
|
||||
#define AR_SREV_SOC(_ah) \
|
||||
(AR_SREV_9340(_ah) || AR_SREV_9531(_ah) || AR_SREV_9550(ah) || \
|
||||
AR_SREV_9561(ah))
|
||||
|
||||
/* NOTE: When adding chips newer than Peacock, add chip check here */
|
||||
#define AR_SREV_9580_10_OR_LATER(_ah) \
|
||||
(AR_SREV_9580(_ah))
|
||||
@ -1104,14 +1108,46 @@ enum {
|
||||
|
||||
#define AR_PCIE_PHY_REG3 0x18c08
|
||||
|
||||
/* Define correct GPIO numbers and MASK bits to indicate the WMAC
|
||||
* GPIO resource.
|
||||
* Allow SOC chips(AR9340, AR9531, AR9550, AR9561) to access all GPIOs
|
||||
* which rely on gpiolib framework. But restrict SOC AR9330 only to
|
||||
* access WMAC GPIO which has the same design with the old chips.
|
||||
*/
|
||||
#define AR_NUM_GPIO 14
|
||||
#define AR928X_NUM_GPIO 10
|
||||
#define AR9280_NUM_GPIO 10
|
||||
#define AR9285_NUM_GPIO 12
|
||||
#define AR9287_NUM_GPIO 11
|
||||
#define AR9287_NUM_GPIO 10
|
||||
#define AR9271_NUM_GPIO 16
|
||||
#define AR9300_NUM_GPIO 17
|
||||
#define AR9300_NUM_GPIO 16
|
||||
#define AR9330_NUM_GPIO 16
|
||||
#define AR9340_NUM_GPIO 23
|
||||
#define AR9462_NUM_GPIO 10
|
||||
#define AR9485_NUM_GPIO 12
|
||||
#define AR9531_NUM_GPIO 18
|
||||
#define AR9550_NUM_GPIO 24
|
||||
#define AR9561_NUM_GPIO 23
|
||||
#define AR9565_NUM_GPIO 12
|
||||
#define AR9580_NUM_GPIO 16
|
||||
#define AR7010_NUM_GPIO 16
|
||||
|
||||
#define AR_GPIO_MASK 0x00003FFF
|
||||
#define AR9271_GPIO_MASK 0x0000FFFF
|
||||
#define AR9280_GPIO_MASK 0x000003FF
|
||||
#define AR9285_GPIO_MASK 0x00000FFF
|
||||
#define AR9287_GPIO_MASK 0x000003FF
|
||||
#define AR9300_GPIO_MASK 0x0000F4FF
|
||||
#define AR9330_GPIO_MASK 0x0000F4FF
|
||||
#define AR9340_GPIO_MASK 0x0000000F
|
||||
#define AR9462_GPIO_MASK 0x000003FF
|
||||
#define AR9485_GPIO_MASK 0x00000FFF
|
||||
#define AR9531_GPIO_MASK 0x0000000F
|
||||
#define AR9550_GPIO_MASK 0x0000000F
|
||||
#define AR9561_GPIO_MASK 0x0000000F
|
||||
#define AR9565_GPIO_MASK 0x00000FFF
|
||||
#define AR9580_GPIO_MASK 0x0000F4FF
|
||||
#define AR7010_GPIO_MASK 0x0000FFFF
|
||||
|
||||
#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048)
|
||||
#define AR_GPIO_IN_VAL 0x0FFFC000
|
||||
#define AR_GPIO_IN_VAL_S 14
|
||||
@ -1132,8 +1168,6 @@ enum {
|
||||
|
||||
#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \
|
||||
(AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c))
|
||||
#define AR_GPIO_OE_OUT_MASK (AR_SREV_9550_OR_LATER(ah) ? \
|
||||
0x0000000F : 0xFFFFFFFF)
|
||||
#define AR_GPIO_OE_OUT_DRV 0x3
|
||||
#define AR_GPIO_OE_OUT_DRV_NO 0x0
|
||||
#define AR_GPIO_OE_OUT_DRV_LOW 0x1
|
||||
@ -1858,15 +1892,33 @@ enum {
|
||||
|
||||
#define AR9300_BT_WGHT 0xcccc4444
|
||||
|
||||
#define AR_BT_COEX_MODE2 0x817c
|
||||
#define AR_BT_BCN_MISS_THRESH 0x000000ff
|
||||
#define AR_BT_BCN_MISS_THRESH_S 0
|
||||
#define AR_BT_BCN_MISS_CNT 0x0000ff00
|
||||
#define AR_BT_BCN_MISS_CNT_S 8
|
||||
#define AR_BT_HOLD_RX_CLEAR 0x00010000
|
||||
#define AR_BT_HOLD_RX_CLEAR_S 16
|
||||
#define AR_BT_DISABLE_BT_ANT 0x00100000
|
||||
#define AR_BT_DISABLE_BT_ANT_S 20
|
||||
#define AR_BT_COEX_MODE2 0x817c
|
||||
#define AR_BT_BCN_MISS_THRESH 0x000000ff
|
||||
#define AR_BT_BCN_MISS_THRESH_S 0
|
||||
#define AR_BT_BCN_MISS_CNT 0x0000ff00
|
||||
#define AR_BT_BCN_MISS_CNT_S 8
|
||||
#define AR_BT_HOLD_RX_CLEAR 0x00010000
|
||||
#define AR_BT_HOLD_RX_CLEAR_S 16
|
||||
#define AR_BT_PROTECT_BT_AFTER_WAKEUP 0x00080000
|
||||
#define AR_BT_PROTECT_BT_AFTER_WAKEUP_S 19
|
||||
#define AR_BT_DISABLE_BT_ANT 0x00100000
|
||||
#define AR_BT_DISABLE_BT_ANT_S 20
|
||||
#define AR_BT_QUIET_2_WIRE 0x00200000
|
||||
#define AR_BT_QUIET_2_WIRE_S 21
|
||||
#define AR_BT_WL_ACTIVE_MODE 0x00c00000
|
||||
#define AR_BT_WL_ACTIVE_MODE_S 22
|
||||
#define AR_BT_WL_TXRX_SEPARATE 0x01000000
|
||||
#define AR_BT_WL_TXRX_SEPARATE_S 24
|
||||
#define AR_BT_RS_DISCARD_EXTEND 0x02000000
|
||||
#define AR_BT_RS_DISCARD_EXTEND_S 25
|
||||
#define AR_BT_TSF_BT_ACTIVE_CTRL 0x0c000000
|
||||
#define AR_BT_TSF_BT_ACTIVE_CTRL_S 26
|
||||
#define AR_BT_TSF_BT_PRIORITY_CTRL 0x30000000
|
||||
#define AR_BT_TSF_BT_PRIORITY_CTRL_S 28
|
||||
#define AR_BT_INTERRUPT_ENABLE 0x40000000
|
||||
#define AR_BT_INTERRUPT_ENABLE_S 30
|
||||
#define AR_BT_PHY_ERR_BT_COLL_ENABLE 0x80000000
|
||||
#define AR_BT_PHY_ERR_BT_COLL_ENABLE_S 31
|
||||
|
||||
#define AR_TXSIFS 0x81d0
|
||||
#define AR_TXSIFS_TIME 0x000000FF
|
||||
@ -1875,6 +1927,16 @@ enum {
|
||||
#define AR_TXSIFS_ACK_SHIFT 0x00007000
|
||||
#define AR_TXSIFS_ACK_SHIFT_S 12
|
||||
|
||||
#define AR_BT_COEX_MODE3 0x81d4
|
||||
#define AR_BT_WL_ACTIVE_TIME 0x000000ff
|
||||
#define AR_BT_WL_ACTIVE_TIME_S 0
|
||||
#define AR_BT_WL_QC_TIME 0x0000ff00
|
||||
#define AR_BT_WL_QC_TIME_S 8
|
||||
#define AR_BT_ALLOW_CONCURRENT_ACCESS 0x000f0000
|
||||
#define AR_BT_ALLOW_CONCURRENT_ACCESS_S 16
|
||||
#define AR_BT_AGC_SATURATION_CNT_ENABLE 0x00100000
|
||||
#define AR_BT_AGC_SATURATION_CNT_ENABLE_S 20
|
||||
|
||||
#define AR_TXOP_X 0x81ec
|
||||
#define AR_TXOP_X_VAL 0x000000FF
|
||||
|
||||
|
@ -55,11 +55,26 @@ static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
|
||||
return j << 2;
|
||||
}
|
||||
|
||||
static u32 ath9k_rng_delay_get(u32 fail_stats)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
if (fail_stats < 100)
|
||||
delay = 10;
|
||||
else if (fail_stats < 105)
|
||||
delay = 1000;
|
||||
else
|
||||
delay = 10000;
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
static int ath9k_rng_kthread(void *data)
|
||||
{
|
||||
int bytes_read;
|
||||
struct ath_softc *sc = data;
|
||||
u32 *rng_buf;
|
||||
u32 delay, fail_stats = 0;
|
||||
|
||||
rng_buf = kmalloc_array(ATH9K_RNG_BUF_SIZE, sizeof(u32), GFP_KERNEL);
|
||||
if (!rng_buf)
|
||||
@ -69,10 +84,13 @@ static int ath9k_rng_kthread(void *data)
|
||||
bytes_read = ath9k_rng_data_read(sc, rng_buf,
|
||||
ATH9K_RNG_BUF_SIZE);
|
||||
if (unlikely(!bytes_read)) {
|
||||
msleep_interruptible(10);
|
||||
delay = ath9k_rng_delay_get(++fail_stats);
|
||||
msleep_interruptible(delay);
|
||||
continue;
|
||||
}
|
||||
|
||||
fail_stats = 0;
|
||||
|
||||
/* sleep until entropy bits under write_wakeup_threshold */
|
||||
add_hwgenerator_randomness((void *)rng_buf, bytes_read,
|
||||
ATH9K_RNG_ENTROPY(bytes_read));
|
||||
|
@ -18,6 +18,7 @@ wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
|
||||
wil6210-y += wil_platform.o
|
||||
wil6210-y += ethtool.o
|
||||
wil6210-y += wil_crash_dump.o
|
||||
wil6210-y += p2p.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
|
||||
#define WIL_MAX_ROC_DURATION_MS 5000
|
||||
|
||||
#define CHAN60G(_channel, _flags) { \
|
||||
.band = IEEE80211_BAND_60GHZ, \
|
||||
.center_freq = 56160 + (2160 * (_channel)), \
|
||||
@ -76,12 +78,24 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_DEVICE] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
};
|
||||
|
||||
static const u32 wil_cipher_suites[] = {
|
||||
WLAN_CIPHER_SUITE_GCMP,
|
||||
};
|
||||
|
||||
static const char * const key_usage_str[] = {
|
||||
[WMI_KEY_USE_PAIRWISE] = "PTK",
|
||||
[WMI_KEY_USE_RX_GROUP] = "RX_GTK",
|
||||
[WMI_KEY_USE_TX_GROUP] = "TX_GTK",
|
||||
};
|
||||
|
||||
int wil_iftype_nl2wmi(enum nl80211_iftype type)
|
||||
{
|
||||
static const struct {
|
||||
@ -113,7 +127,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
.interval_usec = 0,
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_notify_req_done_event evt;
|
||||
} __packed reply;
|
||||
struct wil_net_stats *stats = &wil->sta[cid].stats;
|
||||
@ -226,13 +240,82 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct wireless_dev *
|
||||
wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags, struct vif_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *p2p_wdev;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
if (type != NL80211_IFTYPE_P2P_DEVICE) {
|
||||
wil_err(wil, "%s: unsupported iftype %d\n", __func__, type);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (wil->p2p_wdev) {
|
||||
wil_err(wil, "%s: P2P_DEVICE interface already created\n",
|
||||
__func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
|
||||
if (!p2p_wdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p2p_wdev->iftype = type;
|
||||
p2p_wdev->wiphy = wiphy;
|
||||
/* use our primary ethernet address */
|
||||
ether_addr_copy(p2p_wdev->address, ndev->perm_addr);
|
||||
|
||||
wil->p2p_wdev = p2p_wdev;
|
||||
|
||||
return p2p_wdev;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_del_iface(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
if (wdev != wil->p2p_wdev) {
|
||||
wil_err(wil, "%s: delete of incorrect interface 0x%p\n",
|
||||
__func__, wdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_p2p_wdev_free(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "%s() type=%d\n", __func__, type);
|
||||
|
||||
if (netif_running(wil_to_ndev(wil)) && !wil_is_recovery_blocked(wil)) {
|
||||
wil_dbg_misc(wil, "interface is up. resetting...\n");
|
||||
mutex_lock(&wil->mutex);
|
||||
__wil_down(wil);
|
||||
rc = __wil_up(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@ -260,7 +343,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wireless_dev *wdev = request->wdev;
|
||||
struct {
|
||||
struct wmi_start_scan_cmd cmd;
|
||||
u16 chnl[4];
|
||||
@ -268,6 +351,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
uint i, n;
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n",
|
||||
__func__, wdev, wdev->iftype);
|
||||
|
||||
if (wil->scan_request) {
|
||||
wil_err(wil, "Already scanning\n");
|
||||
return -EAGAIN;
|
||||
@ -277,6 +363,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
@ -288,6 +375,20 @@ 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) {
|
||||
wil->scan_request = request;
|
||||
wil->radio_wdev = wdev;
|
||||
rc = wil_p2p_search(wil, request);
|
||||
if (rc) {
|
||||
wil->radio_wdev = wil_to_wdev(wil);
|
||||
wil->scan_request = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
(void)wil_p2p_stop_discovery(wil);
|
||||
|
||||
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
|
||||
wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
|
||||
|
||||
@ -313,6 +414,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
|
||||
cmd.cmd.num_channels = 0;
|
||||
n = min(request->n_channels, 4U);
|
||||
for (i = 0; i < n; i++) {
|
||||
@ -340,12 +442,19 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
|
||||
cmd.cmd.discovery_mode = 1;
|
||||
wil_dbg_misc(wil, "active scan with discovery_mode=1\n");
|
||||
}
|
||||
|
||||
wil->radio_wdev = wdev;
|
||||
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
|
||||
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
|
||||
|
||||
out:
|
||||
if (rc) {
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
wil->radio_wdev = wil_to_wdev(wil);
|
||||
wil->scan_request = NULL;
|
||||
}
|
||||
|
||||
@ -390,6 +499,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
|
||||
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
|
||||
16, 1, sme->ssid, sme->ssid_len, true);
|
||||
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
|
||||
wil_info(wil, " PBSS: %d\n", sme->pbss);
|
||||
wil_print_crypto(wil, &sme->crypto);
|
||||
}
|
||||
|
||||
@ -404,7 +514,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
const u8 *rsn_eid;
|
||||
int ch;
|
||||
int rc = 0;
|
||||
enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
wil_print_connect_params(wil, sme);
|
||||
|
||||
if (test_bit(wil_status_fwconnecting, wil->status) ||
|
||||
@ -422,14 +534,12 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
if (sme->privacy && !rsn_eid)
|
||||
wil_info(wil, "WSC connection\n");
|
||||
|
||||
if (sme->pbss) {
|
||||
wil_err(wil, "connect - PBSS not yet supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (sme->pbss)
|
||||
bss_type = IEEE80211_BSS_TYPE_PBSS;
|
||||
|
||||
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
||||
sme->ssid, sme->ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||
bss_type, IEEE80211_PRIVACY_ANY);
|
||||
if (!bss) {
|
||||
wil_err(wil, "Unable to find BSS\n");
|
||||
return -ENOENT;
|
||||
@ -568,10 +678,20 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
|
||||
struct wmi_sw_tx_req_cmd *cmd;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_sw_tx_complete_event evt;
|
||||
} __packed evt;
|
||||
|
||||
/* Note, currently we do not support the "wait" parameter, user-space
|
||||
* must call remain_on_channel before mgmt_tx or listen on a channel
|
||||
* another way (AP/PCP or connected station)
|
||||
* in addition we need to check if specified "chan" argument is
|
||||
* different from currently "listened" channel and fail if it is.
|
||||
*/
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len);
|
||||
|
||||
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
@ -598,7 +718,7 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
|
||||
wdev->preset_chandef = *chandef;
|
||||
|
||||
@ -608,22 +728,19 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
|
||||
bool pairwise)
|
||||
{
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
enum wmi_key_usage rc;
|
||||
static const char * const key_usage_str[] = {
|
||||
[WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE",
|
||||
[WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP",
|
||||
[WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP",
|
||||
};
|
||||
|
||||
if (pairwise) {
|
||||
rc = WMI_KEY_USE_PAIRWISE;
|
||||
} else {
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
rc = WMI_KEY_USE_RX_GROUP;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
rc = WMI_KEY_USE_TX_GROUP;
|
||||
break;
|
||||
default:
|
||||
@ -638,20 +755,86 @@ static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct wil_tid_crypto_rx_single *
|
||||
wil_find_crypto_ctx(struct wil6210_priv *wil, u8 key_index,
|
||||
enum wmi_key_usage key_usage, const u8 *mac_addr)
|
||||
{
|
||||
int cid = -EINVAL;
|
||||
int tid = 0;
|
||||
struct wil_sta_info *s;
|
||||
struct wil_tid_crypto_rx *c;
|
||||
|
||||
if (key_usage == WMI_KEY_USE_TX_GROUP)
|
||||
return NULL; /* not needed */
|
||||
|
||||
/* supplicant provides Rx group key in STA mode with NULL MAC address */
|
||||
if (mac_addr)
|
||||
cid = wil_find_cid(wil, mac_addr);
|
||||
else if (key_usage == WMI_KEY_USE_RX_GROUP)
|
||||
cid = wil_find_cid_by_idx(wil, 0);
|
||||
if (cid < 0) {
|
||||
wil_err(wil, "No CID for %pM %s[%d]\n", mac_addr,
|
||||
key_usage_str[key_usage], key_index);
|
||||
return ERR_PTR(cid);
|
||||
}
|
||||
|
||||
s = &wil->sta[cid];
|
||||
if (key_usage == WMI_KEY_USE_PAIRWISE)
|
||||
c = &s->tid_crypto_rx[tid];
|
||||
else
|
||||
c = &s->group_crypto_rx;
|
||||
|
||||
return &c->key_id[key_index];
|
||||
}
|
||||
|
||||
static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 key_index, bool pairwise,
|
||||
const u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
{
|
||||
int rc;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
|
||||
struct wil_tid_crypto_rx_single *cc = wil_find_crypto_ctx(wil,
|
||||
key_index,
|
||||
key_usage,
|
||||
mac_addr);
|
||||
|
||||
wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
|
||||
pairwise ? "PTK" : "GTK");
|
||||
wil_dbg_misc(wil, "%s(%pM %s[%d] PN %*phN)\n", __func__,
|
||||
mac_addr, key_usage_str[key_usage], key_index,
|
||||
params->seq_len, params->seq);
|
||||
|
||||
return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
|
||||
params->key, key_usage);
|
||||
if (IS_ERR(cc)) {
|
||||
wil_err(wil, "Not connected, %s(%pM %s[%d] PN %*phN)\n",
|
||||
__func__, mac_addr, key_usage_str[key_usage], key_index,
|
||||
params->seq_len, params->seq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cc)
|
||||
cc->key_set = false;
|
||||
|
||||
if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
|
||||
wil_err(wil,
|
||||
"Wrong PN len %d, %s(%pM %s[%d] PN %*phN)\n",
|
||||
params->seq_len, __func__, mac_addr,
|
||||
key_usage_str[key_usage], key_index,
|
||||
params->seq_len, params->seq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
|
||||
params->key, key_usage);
|
||||
if ((rc == 0) && cc) {
|
||||
if (params->seq)
|
||||
memcpy(cc->pn, params->seq, IEEE80211_GCMP_PN_LEN);
|
||||
else
|
||||
memset(cc->pn, 0, IEEE80211_GCMP_PN_LEN);
|
||||
cc->key_set = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_del_key(struct wiphy *wiphy,
|
||||
@ -661,9 +844,20 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
|
||||
struct wil_tid_crypto_rx_single *cc = wil_find_crypto_ctx(wil,
|
||||
key_index,
|
||||
key_usage,
|
||||
mac_addr);
|
||||
|
||||
wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
|
||||
pairwise ? "PTK" : "GTK");
|
||||
wil_dbg_misc(wil, "%s(%pM %s[%d])\n", __func__, mac_addr,
|
||||
key_usage_str[key_usage], key_index);
|
||||
|
||||
if (IS_ERR(cc))
|
||||
wil_info(wil, "Not connected, %s(%pM %s[%d])\n", __func__,
|
||||
mac_addr, key_usage_str[key_usage], key_index);
|
||||
|
||||
if (!IS_ERR_OR_NULL(cc))
|
||||
cc->key_set = false;
|
||||
|
||||
return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
|
||||
}
|
||||
@ -674,6 +868,9 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
|
||||
u8 key_index, bool unicast,
|
||||
bool multicast)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s: entered\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -686,16 +883,19 @@ static int wil_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
|
||||
/* TODO: handle duration */
|
||||
wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration);
|
||||
wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n",
|
||||
__func__, chan->center_freq, duration, wdev->iftype);
|
||||
|
||||
rc = wmi_set_channel(wil, chan->hw_value);
|
||||
rc = wil_p2p_listen(wil, duration, chan, cookie);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = wmi_rxon(wil, true);
|
||||
wil->radio_wdev = wdev;
|
||||
|
||||
return rc;
|
||||
cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
|
||||
GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||
@ -703,13 +903,10 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||
u64 cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
|
||||
wil_info(wil, "%s()\n", __func__);
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
rc = wmi_rxon(wil, false);
|
||||
|
||||
return rc;
|
||||
return wil_p2p_cancel_listen(wil, cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -852,12 +1049,22 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
const u8 *ssid, size_t ssid_len, u32 privacy,
|
||||
int bi, u8 chan,
|
||||
struct cfg80211_beacon_data *bcon,
|
||||
u8 hidden_ssid)
|
||||
u8 hidden_ssid, u32 pbss)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
|
||||
|
||||
if (pbss)
|
||||
wmi_nettype = WMI_NETTYPE_P2P;
|
||||
|
||||
wil_dbg_misc(wil, "%s: is_go=%d\n", __func__, is_go);
|
||||
if (is_go && !pbss) {
|
||||
wil_err(wil, "%s: P2P GO must be in PBSS\n", __func__);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
wil_set_recovery_state(wil, fw_recovery_idle);
|
||||
|
||||
@ -879,10 +1086,11 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
wil->privacy = privacy;
|
||||
wil->channel = chan;
|
||||
wil->hidden_ssid = hidden_ssid;
|
||||
wil->pbss = pbss;
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
|
||||
rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid);
|
||||
rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go);
|
||||
if (rc)
|
||||
goto err_pcp_start;
|
||||
|
||||
@ -928,7 +1136,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
wdev->ssid_len, privacy,
|
||||
wdev->beacon_interval,
|
||||
wil->channel, bcon,
|
||||
wil->hidden_ssid);
|
||||
wil->hidden_ssid,
|
||||
wil->pbss);
|
||||
} else {
|
||||
rc = _wil_cfg80211_set_ies(wiphy, bcon);
|
||||
}
|
||||
@ -954,11 +1163,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->pbss) {
|
||||
wil_err(wil, "AP: PBSS not yet supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (info->hidden_ssid) {
|
||||
case NL80211_HIDDEN_SSID_NOT_IN_USE:
|
||||
hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
|
||||
@ -984,6 +1188,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
info->hidden_ssid);
|
||||
wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
|
||||
info->dtim_period);
|
||||
wil_dbg_misc(wil, "PBSS %d\n", info->pbss);
|
||||
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
|
||||
info->ssid, info->ssid_len);
|
||||
wil_print_bcon_data(bcon);
|
||||
@ -992,7 +1197,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
rc = _wil_cfg80211_start_ap(wiphy, ndev,
|
||||
info->ssid, info->ssid_len, info->privacy,
|
||||
info->beacon_interval, channel->hw_value,
|
||||
bcon, hidden_ssid);
|
||||
bcon, hidden_ssid, info->pbss);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1139,7 +1344,26 @@ static int wil_cfg80211_change_bss(struct wiphy *wiphy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s: entered\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s: entered\n", __func__);
|
||||
}
|
||||
|
||||
static struct cfg80211_ops wil_cfg80211_ops = {
|
||||
.add_virtual_intf = wil_cfg80211_add_iface,
|
||||
.del_virtual_intf = wil_cfg80211_del_iface,
|
||||
.scan = wil_cfg80211_scan,
|
||||
.connect = wil_cfg80211_connect,
|
||||
.disconnect = wil_cfg80211_disconnect,
|
||||
@ -1160,20 +1384,25 @@ static struct cfg80211_ops wil_cfg80211_ops = {
|
||||
.del_station = wil_cfg80211_del_station,
|
||||
.probe_client = wil_cfg80211_probe_client,
|
||||
.change_bss = wil_cfg80211_change_bss,
|
||||
/* P2P device */
|
||||
.start_p2p_device = wil_cfg80211_start_p2p_device,
|
||||
.stop_p2p_device = wil_cfg80211_stop_p2p_device,
|
||||
};
|
||||
|
||||
static void wil_wiphy_init(struct wiphy *wiphy)
|
||||
{
|
||||
wiphy->max_scan_ssids = 1;
|
||||
wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
|
||||
wiphy->max_remain_on_channel_duration = WIL_MAX_ROC_DURATION_MS;
|
||||
wiphy->max_num_pmkids = 0 /* TODO: */;
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE) |
|
||||
BIT(NL80211_IFTYPE_MONITOR);
|
||||
/* TODO: enable P2P when integrated with supplicant:
|
||||
* BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)
|
||||
*/
|
||||
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
|
||||
dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
|
||||
__func__, wiphy->flags);
|
||||
@ -1241,3 +1470,18 @@ void wil_wdev_free(struct wil6210_priv *wil)
|
||||
wiphy_free(wdev->wiphy);
|
||||
kfree(wdev);
|
||||
}
|
||||
|
||||
void wil_p2p_wdev_free(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wireless_dev *p2p_wdev;
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
p2p_wdev = wil->p2p_wdev;
|
||||
if (p2p_wdev) {
|
||||
wil->p2p_wdev = NULL;
|
||||
wil->radio_wdev = wil_to_wdev(wil);
|
||||
cfg80211_unregister_wdev(p2p_wdev);
|
||||
kfree(p2p_wdev);
|
||||
}
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ enum dbg_off_type {
|
||||
doff_x32 = 1,
|
||||
doff_ulong = 2,
|
||||
doff_io32 = 3,
|
||||
doff_u8 = 4
|
||||
};
|
||||
|
||||
/* offset to "wil" */
|
||||
@ -346,6 +347,10 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
|
||||
tbl[i].mode, dbg,
|
||||
base + tbl[i].off);
|
||||
break;
|
||||
case doff_u8:
|
||||
f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
|
||||
base + tbl[i].off);
|
||||
break;
|
||||
default:
|
||||
f = ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -821,13 +826,13 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wil6210_mbox_hdr_wmi *wmi;
|
||||
struct wmi_cmd_hdr *wmi;
|
||||
void *cmd;
|
||||
int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi);
|
||||
int cmdlen = len - sizeof(struct wmi_cmd_hdr);
|
||||
u16 cmdid;
|
||||
int rc, rc1;
|
||||
|
||||
if (cmdlen <= 0)
|
||||
if (cmdlen < 0)
|
||||
return -EINVAL;
|
||||
|
||||
wmi = kmalloc(len, GFP_KERNEL);
|
||||
@ -840,8 +845,8 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmd = &wmi[1];
|
||||
cmdid = le16_to_cpu(wmi->id);
|
||||
cmd = (cmdlen > 0) ? &wmi[1] : NULL;
|
||||
cmdid = le16_to_cpu(wmi->command_id);
|
||||
|
||||
rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
|
||||
kfree(wmi);
|
||||
@ -985,7 +990,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
|
||||
.interval_usec = 0,
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_notify_req_done_event evt;
|
||||
} __packed reply;
|
||||
|
||||
@ -1333,6 +1338,34 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
|
||||
r->ssn_last_drop);
|
||||
}
|
||||
|
||||
static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
|
||||
struct wil_tid_crypto_rx *c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
|
||||
|
||||
if (cc->key_set)
|
||||
goto has_keys;
|
||||
}
|
||||
return;
|
||||
|
||||
has_keys:
|
||||
if (tid < WIL_STA_TID_NUM)
|
||||
seq_printf(s, " [%2d] PN", tid);
|
||||
else
|
||||
seq_puts(s, " [GR] PN");
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
struct wil_tid_crypto_rx_single *cc = &c->key_id[i];
|
||||
|
||||
seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-",
|
||||
cc->pn);
|
||||
}
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
|
||||
static int wil_sta_debugfs_show(struct seq_file *s, void *data)
|
||||
__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
||||
{
|
||||
@ -1360,18 +1393,25 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
||||
spin_lock_bh(&p->tid_rx_lock);
|
||||
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
|
||||
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
|
||||
struct wil_tid_crypto_rx *c =
|
||||
&p->tid_crypto_rx[tid];
|
||||
|
||||
if (r) {
|
||||
seq_printf(s, "[%2d] ", tid);
|
||||
seq_printf(s, " [%2d] ", tid);
|
||||
wil_print_rxtid(s, r);
|
||||
}
|
||||
|
||||
wil_print_rxtid_crypto(s, tid, c);
|
||||
}
|
||||
wil_print_rxtid_crypto(s, WIL_STA_TID_NUM,
|
||||
&p->group_crypto_rx);
|
||||
spin_unlock_bh(&p->tid_rx_lock);
|
||||
seq_printf(s,
|
||||
"Rx invalid frame: non-data %lu, short %lu, large %lu\n",
|
||||
"Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n",
|
||||
p->stats.rx_non_data_frame,
|
||||
p->stats.rx_short_frame,
|
||||
p->stats.rx_large_frame);
|
||||
p->stats.rx_large_frame,
|
||||
p->stats.rx_replay);
|
||||
|
||||
seq_puts(s, "Rx/MCS:");
|
||||
for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
|
||||
@ -1487,6 +1527,7 @@ static const struct dbg_off dbg_wil_off[] = {
|
||||
WIL_FIELD(hw_version, S_IRUGO, doff_x32),
|
||||
WIL_FIELD(recovery_count, S_IRUGO, doff_u32),
|
||||
WIL_FIELD(ap_isolate, S_IRUGO, doff_u32),
|
||||
WIL_FIELD(discovery_mode, S_IRUGO | S_IWUSR, doff_u8),
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -391,12 +391,14 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
|
||||
wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
|
||||
|
||||
if (isr & ISR_MISC_FW_ERROR) {
|
||||
wil->recovery_state = fw_recovery_pending;
|
||||
wil_fw_core_dump(wil);
|
||||
wil_notify_fw_error(wil);
|
||||
isr &= ~ISR_MISC_FW_ERROR;
|
||||
if (wil->platform_ops.notify_crash) {
|
||||
if (wil->platform_ops.notify) {
|
||||
wil_err(wil, "notify platform driver about FW crash");
|
||||
wil->platform_ops.notify_crash(wil->platform_handle);
|
||||
wil->platform_ops.notify(wil->platform_handle,
|
||||
WIL_PLATFORM_EVT_FW_CRASH);
|
||||
} else {
|
||||
wil_fw_error_recovery(wil);
|
||||
}
|
||||
|
@ -161,13 +161,20 @@ out_free:
|
||||
|
||||
int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (cmd) {
|
||||
case WIL_IOCTL_MEMIO:
|
||||
return wil_ioc_memio_dword(wil, data);
|
||||
ret = wil_ioc_memio_dword(wil, data);
|
||||
break;
|
||||
case WIL_IOCTL_MEMIO_BLOCK:
|
||||
return wil_ioc_memio_block(wil, data);
|
||||
ret = wil_ioc_memio_block(wil, data);
|
||||
break;
|
||||
default:
|
||||
wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
wil_dbg_ioctl(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -27,6 +27,11 @@ bool debug_fw; /* = false; */
|
||||
module_param(debug_fw, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
|
||||
|
||||
static bool oob_mode;
|
||||
module_param(oob_mode, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(oob_mode,
|
||||
" enable out of the box (OOB) mode in FW, for diagnostics and certification");
|
||||
|
||||
bool no_fw_recovery;
|
||||
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
|
||||
@ -149,7 +154,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
might_sleep();
|
||||
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
|
||||
sta->status);
|
||||
|
||||
/* inform upper/lower layers */
|
||||
if (sta->status != wil_sta_unused) {
|
||||
if (!from_event)
|
||||
wmi_disconnect_sta(wil, sta->addr, reason_code, true);
|
||||
@ -165,7 +170,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
}
|
||||
sta->status = wil_sta_unused;
|
||||
}
|
||||
|
||||
/* reorder buffers */
|
||||
for (i = 0; i < WIL_STA_TID_NUM; i++) {
|
||||
struct wil_tid_ampdu_rx *r;
|
||||
|
||||
@ -177,10 +182,15 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
|
||||
spin_unlock_bh(&sta->tid_rx_lock);
|
||||
}
|
||||
/* crypto context */
|
||||
memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx));
|
||||
memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx));
|
||||
/* release vrings */
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
if (wil->vring2cid_tid[i][0] == cid)
|
||||
wil_vring_fini_tx(wil, i);
|
||||
}
|
||||
/* statistics */
|
||||
memset(&sta->stats, 0, sizeof(sta->stats));
|
||||
}
|
||||
|
||||
@ -300,6 +310,11 @@ void wil_set_recovery_state(struct wil6210_priv *wil, int state)
|
||||
wake_up_interruptible(&wil->wq);
|
||||
}
|
||||
|
||||
bool wil_is_recovery_blocked(struct wil6210_priv *wil)
|
||||
{
|
||||
return no_fw_recovery && (wil->recovery_state == fw_recovery_pending);
|
||||
}
|
||||
|
||||
static void wil_fw_error_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
@ -440,9 +455,8 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||
|
||||
mutex_init(&wil->mutex);
|
||||
mutex_init(&wil->wmi_mutex);
|
||||
mutex_init(&wil->back_rx_mutex);
|
||||
mutex_init(&wil->back_tx_mutex);
|
||||
mutex_init(&wil->probe_client_mutex);
|
||||
mutex_init(&wil->p2p_wdev_mutex);
|
||||
|
||||
init_completion(&wil->wmi_ready);
|
||||
init_completion(&wil->wmi_call);
|
||||
@ -450,17 +464,15 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||
wil->bcast_vring = -1;
|
||||
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
|
||||
setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
|
||||
setup_timer(&wil->p2p.discovery_timer, wil_p2p_discovery_timer_fn,
|
||||
(ulong)wil);
|
||||
|
||||
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
|
||||
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
|
||||
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
|
||||
INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
|
||||
INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
|
||||
INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
|
||||
|
||||
INIT_LIST_HEAD(&wil->pending_wmi_ev);
|
||||
INIT_LIST_HEAD(&wil->back_rx_pending);
|
||||
INIT_LIST_HEAD(&wil->back_tx_pending);
|
||||
INIT_LIST_HEAD(&wil->probe_client_pending);
|
||||
spin_lock_init(&wil->wmi_ev_lock);
|
||||
init_waitqueue_head(&wil->wq);
|
||||
@ -514,16 +526,14 @@ void wil_priv_deinit(struct wil6210_priv *wil)
|
||||
|
||||
wil_set_recovery_state(wil, fw_recovery_idle);
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
del_timer_sync(&wil->p2p.discovery_timer);
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
cancel_work_sync(&wil->fw_error_worker);
|
||||
cancel_work_sync(&wil->p2p.discovery_expired_work);
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
wmi_event_flush(wil);
|
||||
wil_back_rx_flush(wil);
|
||||
cancel_work_sync(&wil->back_rx_worker);
|
||||
wil_back_tx_flush(wil);
|
||||
cancel_work_sync(&wil->back_tx_worker);
|
||||
wil_probe_client_flush(wil);
|
||||
cancel_work_sync(&wil->probe_client_worker);
|
||||
destroy_workqueue(wil->wq_service);
|
||||
@ -542,6 +552,16 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
|
||||
wil_w(wil, RGF_USER_USER_CPU_0, 1);
|
||||
}
|
||||
|
||||
static void wil_set_oob_mode(struct wil6210_priv *wil, bool enable)
|
||||
{
|
||||
wil_info(wil, "%s: enable=%d\n", __func__, enable);
|
||||
if (enable) {
|
||||
wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
|
||||
} else {
|
||||
wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_target_reset(struct wil6210_priv *wil)
|
||||
{
|
||||
int delay = 0;
|
||||
@ -637,6 +657,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
|
||||
static int wil_get_bl_info(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
union {
|
||||
struct bl_dedicated_registers_v0 bl0;
|
||||
struct bl_dedicated_registers_v1 bl1;
|
||||
@ -681,6 +702,7 @@ static int wil_get_bl_info(struct wil6210_priv *wil)
|
||||
}
|
||||
|
||||
ether_addr_copy(ndev->perm_addr, mac);
|
||||
ether_addr_copy(wiphy->perm_addr, mac);
|
||||
if (!is_valid_ether_addr(ndev->dev_addr))
|
||||
ether_addr_copy(ndev->dev_addr, mac);
|
||||
|
||||
@ -767,6 +789,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
if (wil->hw_version == HW_VER_UNKNOWN)
|
||||
return -ENODEV;
|
||||
|
||||
if (wil->platform_ops.notify) {
|
||||
rc = wil->platform_ops.notify(wil->platform_handle,
|
||||
WIL_PLATFORM_EVT_PRE_RESET);
|
||||
if (rc)
|
||||
wil_err(wil,
|
||||
"%s: PRE_RESET platform notify failed, rc %d\n",
|
||||
__func__, rc);
|
||||
}
|
||||
|
||||
set_bit(wil_status_resetting, wil->status);
|
||||
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
@ -807,6 +838,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
wil_set_oob_mode(wil, oob_mode);
|
||||
if (load_fw) {
|
||||
wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME,
|
||||
WIL_FW2_NAME);
|
||||
@ -846,8 +878,27 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
|
||||
/* we just started MAC, wait for FW ready */
|
||||
rc = wil_wait_for_fw_ready(wil);
|
||||
if (rc == 0) /* check FW is responsive */
|
||||
rc = wmi_echo(wil);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* check FW is responsive */
|
||||
rc = wmi_echo(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_echo failed, rc %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (wil->platform_ops.notify) {
|
||||
rc = wil->platform_ops.notify(wil->platform_handle,
|
||||
WIL_PLATFORM_EVT_FW_RDY);
|
||||
if (rc) {
|
||||
wil_err(wil,
|
||||
"%s: FW_RDY notify failed, rc %d\n",
|
||||
__func__, rc);
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -954,6 +1005,8 @@ int __wil_down(struct wil6210_priv *wil)
|
||||
}
|
||||
wil_enable_irq(wil);
|
||||
|
||||
(void)wil_p2p_stop_discovery(wil);
|
||||
|
||||
if (wil->scan_request) {
|
||||
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
|
||||
wil->scan_request);
|
||||
|
@ -60,11 +60,7 @@ static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
|
||||
int ret = wil_ioctl(wil, ifr->ifr_data, cmd);
|
||||
|
||||
wil_dbg_misc(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
|
||||
|
||||
return ret;
|
||||
return wil_ioctl(wil, ifr->ifr_data, cmd);
|
||||
}
|
||||
|
||||
static const struct net_device_ops wil_netdev_ops = {
|
||||
@ -149,6 +145,7 @@ void *wil_if_alloc(struct device *dev)
|
||||
|
||||
wil = wdev_to_wil(wdev);
|
||||
wil->wdev = wdev;
|
||||
wil->radio_wdev = wdev;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
|
253
drivers/net/wireless/ath/wil6210/p2p.c
Normal file
253
drivers/net/wireless/ath/wil6210/p2p.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
|
||||
#define P2P_WILDCARD_SSID "DIRECT-"
|
||||
#define P2P_DMG_SOCIAL_CHANNEL 2
|
||||
#define P2P_SEARCH_DURATION_MS 500
|
||||
#define P2P_DEFAULT_BI 100
|
||||
|
||||
void wil_p2p_discovery_timer_fn(ulong x)
|
||||
{
|
||||
struct wil6210_priv *wil = (void *)x;
|
||||
|
||||
wil_dbg_misc(wil, "%s\n", __func__);
|
||||
|
||||
schedule_work(&wil->p2p.discovery_expired_work);
|
||||
}
|
||||
|
||||
int wil_p2p_search(struct wil6210_priv *wil,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
int rc;
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
|
||||
wil_dbg_misc(wil, "%s: channel %d\n",
|
||||
__func__, P2P_DMG_SOCIAL_CHANNEL);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
if (p2p->discovery_started) {
|
||||
wil_err(wil, "%s: search failed. discovery already ongoing\n",
|
||||
__func__);
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
/* Set application IE to probe request and probe response */
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
|
||||
request->ie_len, request->ie);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n",
|
||||
__func__);
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
/* supplicant doesn't provide Probe Response IEs. As a workaround -
|
||||
* re-use Probe Request IEs
|
||||
*/
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
|
||||
request->ie_len, request->ie);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n",
|
||||
__func__);
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
rc = wmi_start_search(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_start_search failed\n", __func__);
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
p2p->discovery_started = 1;
|
||||
INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
|
||||
mod_timer(&p2p->discovery_timer,
|
||||
jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
|
||||
|
||||
out_stop:
|
||||
if (rc)
|
||||
wmi_stop_discovery(wil);
|
||||
|
||||
out:
|
||||
mutex_unlock(&wil->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
|
||||
struct ieee80211_channel *chan, u64 *cookie)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
u8 channel = P2P_DMG_SOCIAL_CHANNEL;
|
||||
int rc;
|
||||
|
||||
if (chan)
|
||||
channel = chan->hw_value;
|
||||
|
||||
wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
if (p2p->discovery_started) {
|
||||
wil_err(wil, "%s: discovery already ongoing\n", __func__);
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
rc = wmi_start_listen(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_start_listen failed\n", __func__);
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
memcpy(&p2p->listen_chan, chan, sizeof(*chan));
|
||||
*cookie = ++p2p->cookie;
|
||||
|
||||
p2p->discovery_started = 1;
|
||||
INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
|
||||
mod_timer(&p2p->discovery_timer,
|
||||
jiffies + msecs_to_jiffies(duration));
|
||||
|
||||
out_stop:
|
||||
if (rc)
|
||||
wmi_stop_discovery(wil);
|
||||
|
||||
out:
|
||||
mutex_unlock(&wil->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
u8 started = p2p->discovery_started;
|
||||
|
||||
if (p2p->discovery_started) {
|
||||
del_timer_sync(&p2p->discovery_timer);
|
||||
p2p->discovery_started = 0;
|
||||
wmi_stop_discovery(wil);
|
||||
}
|
||||
|
||||
return started;
|
||||
}
|
||||
|
||||
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
u8 started;
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
if (cookie != p2p->cookie) {
|
||||
wil_info(wil, "%s: Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
|
||||
__func__, p2p->cookie, cookie);
|
||||
mutex_unlock(&wil->mutex);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (!started) {
|
||||
wil_err(wil, "%s: listen not started\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_p2p_listen_expired(struct work_struct *work)
|
||||
{
|
||||
struct wil_p2p_info *p2p = container_of(work,
|
||||
struct wil_p2p_info, discovery_expired_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
u8 started;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (started) {
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void wil_p2p_search_expired(struct work_struct *work)
|
||||
{
|
||||
struct wil_p2p_info *p2p = container_of(work,
|
||||
struct wil_p2p_info, discovery_expired_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
u8 started;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (started) {
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_scan_done(wil->scan_request, 0);
|
||||
wil->scan_request = NULL;
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
}
|
@ -275,6 +275,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
|
||||
pci_disable_device(pdev);
|
||||
if (wil->platform_ops.uninit)
|
||||
wil->platform_ops.uninit(wil->platform_handle);
|
||||
wil_p2p_wdev_free(wil);
|
||||
wil_if_free(wil);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -291,35 +291,15 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
|
||||
return min(max_agg_size, req_agg_wsize);
|
||||
}
|
||||
|
||||
/* Block Ack - Rx side (recipient */
|
||||
/* Block Ack - Rx side (recipient) */
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
|
||||
u8 dialog_token, __le16 ba_param_set,
|
||||
__le16 ba_timeout, __le16 ba_seq_ctrl)
|
||||
{
|
||||
struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->cidxtid = cidxtid;
|
||||
req->dialog_token = dialog_token;
|
||||
req->ba_param_set = le16_to_cpu(ba_param_set);
|
||||
req->ba_timeout = le16_to_cpu(ba_timeout);
|
||||
req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl);
|
||||
|
||||
mutex_lock(&wil->back_rx_mutex);
|
||||
list_add_tail(&req->list, &wil->back_rx_pending);
|
||||
mutex_unlock(&wil->back_rx_mutex);
|
||||
|
||||
queue_work(wil->wq_service, &wil->back_rx_worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wil_back_rx_handle(struct wil6210_priv *wil,
|
||||
struct wil_back_rx *req)
|
||||
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
{
|
||||
u16 param_set = le16_to_cpu(ba_param_set);
|
||||
u16 agg_timeout = le16_to_cpu(ba_timeout);
|
||||
u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl);
|
||||
struct wil_sta_info *sta;
|
||||
u8 cid, tid;
|
||||
u16 agg_wsize = 0;
|
||||
@ -328,34 +308,35 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
* bits 2..5: TID
|
||||
* bits 6..15: buffer size
|
||||
*/
|
||||
u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15);
|
||||
bool agg_amsdu = !!(req->ba_param_set & BIT(0));
|
||||
int ba_policy = req->ba_param_set & BIT(1);
|
||||
u16 agg_timeout = req->ba_timeout;
|
||||
u16 req_agg_wsize = WIL_GET_BITS(param_set, 6, 15);
|
||||
bool agg_amsdu = !!(param_set & BIT(0));
|
||||
int ba_policy = param_set & BIT(1);
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
u16 ssn = req->ba_seq_ctrl >> 4;
|
||||
u16 ssn = seq_ctrl >> 4;
|
||||
struct wil_tid_ampdu_rx *r;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
might_sleep();
|
||||
parse_cidxtid(req->cidxtid, &cid, &tid);
|
||||
parse_cidxtid(cidxtid, &cid, &tid);
|
||||
|
||||
/* sanity checks */
|
||||
if (cid >= WIL6210_MAX_CID) {
|
||||
wil_err(wil, "BACK: invalid CID %d\n", cid);
|
||||
return;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sta = &wil->sta[cid];
|
||||
if (sta->status != wil_sta_connected) {
|
||||
wil_err(wil, "BACK: CID %d not connected\n", cid);
|
||||
return;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil,
|
||||
"ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n",
|
||||
cid, sta->addr, tid, req_agg_wsize, req->ba_timeout,
|
||||
agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn);
|
||||
cid, sta->addr, tid, req_agg_wsize, agg_timeout,
|
||||
agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn);
|
||||
|
||||
/* apply policies */
|
||||
if (ba_policy) {
|
||||
@ -365,10 +346,13 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
if (status == WLAN_STATUS_SUCCESS)
|
||||
agg_wsize = wil_agg_size(wil, req_agg_wsize);
|
||||
|
||||
rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status,
|
||||
rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status,
|
||||
agg_amsdu, agg_wsize, agg_timeout);
|
||||
if (rc || (status != WLAN_STATUS_SUCCESS))
|
||||
return;
|
||||
if (rc || (status != WLAN_STATUS_SUCCESS)) {
|
||||
wil_err(wil, "%s: do not apply ba, rc(%d), status(%d)\n",
|
||||
__func__, rc, status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* apply */
|
||||
r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
|
||||
@ -376,143 +360,37 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
|
||||
sta->tid_rx[tid] = r;
|
||||
spin_unlock_bh(&sta->tid_rx_lock);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_back_rx_flush(struct wil6210_priv *wil)
|
||||
/* BACK - Tx side (originator) */
|
||||
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
|
||||
{
|
||||
struct wil_back_rx *evt, *t;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
mutex_lock(&wil->back_rx_mutex);
|
||||
|
||||
list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) {
|
||||
list_del(&evt->list);
|
||||
kfree(evt);
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->back_rx_mutex);
|
||||
}
|
||||
|
||||
/* Retrieve next ADDBA request from the pending list */
|
||||
static struct list_head *next_back_rx(struct wil6210_priv *wil)
|
||||
{
|
||||
struct list_head *ret = NULL;
|
||||
|
||||
mutex_lock(&wil->back_rx_mutex);
|
||||
|
||||
if (!list_empty(&wil->back_rx_pending)) {
|
||||
ret = wil->back_rx_pending.next;
|
||||
list_del(ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->back_rx_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wil_back_rx_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
back_rx_worker);
|
||||
struct wil_back_rx *evt;
|
||||
struct list_head *lh;
|
||||
|
||||
while ((lh = next_back_rx(wil)) != NULL) {
|
||||
evt = list_entry(lh, struct wil_back_rx, list);
|
||||
|
||||
wil_back_rx_handle(wil, evt);
|
||||
kfree(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/* BACK - Tx (originator) side */
|
||||
static void wil_back_tx_handle(struct wil6210_priv *wil,
|
||||
struct wil_back_tx *req)
|
||||
{
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid];
|
||||
int rc;
|
||||
u8 agg_wsize = wil_agg_size(wil, wsize);
|
||||
u16 agg_timeout = 0;
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
|
||||
int rc = 0;
|
||||
|
||||
if (txdata->addba_in_progress) {
|
||||
wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n",
|
||||
req->ringid);
|
||||
return;
|
||||
ringid);
|
||||
goto out;
|
||||
}
|
||||
if (txdata->agg_wsize) {
|
||||
wil_dbg_misc(wil,
|
||||
"ADDBA for vring[%d] already established wsize %d\n",
|
||||
req->ringid, txdata->agg_wsize);
|
||||
return;
|
||||
"ADDBA for vring[%d] already done for wsize %d\n",
|
||||
ringid, txdata->agg_wsize);
|
||||
goto out;
|
||||
}
|
||||
txdata->addba_in_progress = true;
|
||||
rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout);
|
||||
if (rc)
|
||||
rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout);
|
||||
if (rc) {
|
||||
wil_err(wil, "%s: wmi_addba failed, rc (%d)", __func__, rc);
|
||||
txdata->addba_in_progress = false;
|
||||
}
|
||||
|
||||
static struct list_head *next_back_tx(struct wil6210_priv *wil)
|
||||
{
|
||||
struct list_head *ret = NULL;
|
||||
|
||||
mutex_lock(&wil->back_tx_mutex);
|
||||
|
||||
if (!list_empty(&wil->back_tx_pending)) {
|
||||
ret = wil->back_tx_pending.next;
|
||||
list_del(ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->back_tx_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wil_back_tx_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
back_tx_worker);
|
||||
struct wil_back_tx *evt;
|
||||
struct list_head *lh;
|
||||
|
||||
while ((lh = next_back_tx(wil)) != NULL) {
|
||||
evt = list_entry(lh, struct wil_back_tx, list);
|
||||
|
||||
wil_back_tx_handle(wil, evt);
|
||||
kfree(evt);
|
||||
}
|
||||
}
|
||||
|
||||
void wil_back_tx_flush(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_back_tx *evt, *t;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
mutex_lock(&wil->back_tx_mutex);
|
||||
|
||||
list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) {
|
||||
list_del(&evt->list);
|
||||
kfree(evt);
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->back_tx_mutex);
|
||||
}
|
||||
|
||||
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
|
||||
{
|
||||
struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->ringid = ringid;
|
||||
req->agg_wsize = wil_agg_size(wil, wsize);
|
||||
req->agg_timeout = 0;
|
||||
|
||||
mutex_lock(&wil->back_tx_mutex);
|
||||
list_add_tail(&req->list, &wil->back_tx_pending);
|
||||
mutex_unlock(&wil->back_tx_mutex);
|
||||
|
||||
queue_work(wil->wq_service, &wil->back_tx_worker);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2013-2016 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -37,39 +37,40 @@ static inline void trace_ ## name(proto) {}
|
||||
#endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */
|
||||
|
||||
DECLARE_EVENT_CLASS(wil6210_wmi,
|
||||
TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
|
||||
TP_PROTO(struct wmi_cmd_hdr *wmi, void *buf, u16 buf_len),
|
||||
|
||||
TP_ARGS(wmi, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u8, mid)
|
||||
__field(u16, id)
|
||||
__field(u32, timestamp)
|
||||
__field(u16, command_id)
|
||||
__field(u32, fw_timestamp)
|
||||
__field(u16, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->mid = wmi->mid;
|
||||
__entry->id = le16_to_cpu(wmi->id);
|
||||
__entry->timestamp = le32_to_cpu(wmi->timestamp);
|
||||
__entry->command_id = le16_to_cpu(wmi->command_id);
|
||||
__entry->fw_timestamp = le32_to_cpu(wmi->fw_timestamp);
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"MID %d id 0x%04x len %d timestamp %d",
|
||||
__entry->mid, __entry->id, __entry->buf_len, __entry->timestamp
|
||||
__entry->mid, __entry->command_id, __entry->buf_len,
|
||||
__entry->fw_timestamp
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd,
|
||||
TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
|
||||
TP_PROTO(struct wmi_cmd_hdr *wmi, void *buf, u16 buf_len),
|
||||
TP_ARGS(wmi, buf, buf_len)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event,
|
||||
TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
|
||||
TP_PROTO(struct wmi_cmd_hdr *wmi, void *buf, u16 buf_len),
|
||||
TP_ARGS(wmi, buf, buf_len)
|
||||
);
|
||||
|
||||
|
@ -549,6 +549,60 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* reverse_memcmp - Compare two areas of memory, in reverse order
|
||||
* @cs: One area of memory
|
||||
* @ct: Another area of memory
|
||||
* @count: The size of the area.
|
||||
*
|
||||
* Cut'n'paste from original memcmp (see lib/string.c)
|
||||
* with minimal modifications
|
||||
*/
|
||||
static int reverse_memcmp(const void *cs, const void *ct, size_t count)
|
||||
{
|
||||
const unsigned char *su1, *su2;
|
||||
int res = 0;
|
||||
|
||||
for (su1 = cs + count - 1, su2 = ct + count - 1; count > 0;
|
||||
--su1, --su2, count--) {
|
||||
res = *su1 - *su2;
|
||||
if (res)
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
|
||||
{
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int cid = wil_rxdesc_cid(d);
|
||||
int tid = wil_rxdesc_tid(d);
|
||||
int key_id = wil_rxdesc_key_id(d);
|
||||
int mc = wil_rxdesc_mcast(d);
|
||||
struct wil_sta_info *s = &wil->sta[cid];
|
||||
struct wil_tid_crypto_rx *c = mc ? &s->group_crypto_rx :
|
||||
&s->tid_crypto_rx[tid];
|
||||
struct wil_tid_crypto_rx_single *cc = &c->key_id[key_id];
|
||||
const u8 *pn = (u8 *)&d->mac.pn_15_0;
|
||||
|
||||
if (!cc->key_set) {
|
||||
wil_err_ratelimited(wil,
|
||||
"Key missing. CID %d TID %d MCast %d KEY_ID %d\n",
|
||||
cid, tid, mc, key_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reverse_memcmp(pn, cc->pn, IEEE80211_GCMP_PN_LEN) <= 0) {
|
||||
wil_err_ratelimited(wil,
|
||||
"Replay attack. CID %d TID %d MCast %d KEY_ID %d PN %6phN last %6phN\n",
|
||||
cid, tid, mc, key_id, pn, cc->pn);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(cc->pn, pn, IEEE80211_GCMP_PN_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass Rx packet to the netif. Update statistics.
|
||||
* Called in softirq context (NAPI poll).
|
||||
@ -561,6 +615,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
unsigned int len = skb->len;
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
|
||||
int security = wil_rxdesc_security(d);
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
/* here looking for DA, not A1, thus Rxdesc's 'mcast' indication
|
||||
* is not suitable, need to look at data
|
||||
@ -586,6 +641,13 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
if (security && (wil_rx_crypto_check(wil, skb) != 0)) {
|
||||
rc = GRO_DROP;
|
||||
dev_kfree_skb(skb);
|
||||
stats->rx_replay++;
|
||||
goto stats;
|
||||
}
|
||||
|
||||
if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) {
|
||||
if (mcast) {
|
||||
/* send multicast frames both to higher layers in
|
||||
@ -627,6 +689,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
|
||||
len, gro_res_str[rc]);
|
||||
}
|
||||
stats:
|
||||
/* statistics. rc set to GRO_NORMAL for AP bridging */
|
||||
if (unlikely(rc == GRO_DROP)) {
|
||||
ndev->stats.rx_dropped++;
|
||||
@ -757,7 +820,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
},
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_vring_cfg_done_event cmd;
|
||||
} __packed reply;
|
||||
struct vring *vring = &wil->vring_tx[id];
|
||||
@ -834,7 +897,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||
},
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_vring_cfg_done_event cmd;
|
||||
} __packed reply;
|
||||
struct vring *vring = &wil->vring_tx[id];
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -480,6 +480,16 @@ static inline int wil_rxdesc_ext_subtype(struct vring_rx_desc *d)
|
||||
return WIL_GET_BITS(d->mac.d0, 28, 31);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_key_id(struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d1, 4, 5);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_security(struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d1, 7, 7);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_ds_bits(struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d1, 8, 9);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <net/cfg80211.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/types.h>
|
||||
#include "wmi.h"
|
||||
#include "wil_platform.h"
|
||||
|
||||
extern bool no_fw_recovery;
|
||||
@ -131,6 +132,7 @@ struct RGF_ICR {
|
||||
/* registers - FW addresses */
|
||||
#define RGF_USER_USAGE_1 (0x880004)
|
||||
#define RGF_USER_USAGE_6 (0x880018)
|
||||
#define BIT_USER_OOB_MODE BIT(31)
|
||||
#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
|
||||
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
|
||||
#define RGF_USER_USER_CPU_0 (0x8801e0)
|
||||
@ -334,29 +336,11 @@ struct wil6210_mbox_hdr {
|
||||
/* max. value for wil6210_mbox_hdr.len */
|
||||
#define MAX_MBOXITEM_SIZE (240)
|
||||
|
||||
/**
|
||||
* struct wil6210_mbox_hdr_wmi - WMI header
|
||||
*
|
||||
* @mid: MAC ID
|
||||
* 00 - default, created by FW
|
||||
* 01..0f - WiFi ports, driver to create
|
||||
* 10..fe - debug
|
||||
* ff - broadcast
|
||||
* @id: command/event ID
|
||||
* @timestamp: FW fills for events, free-running msec timer
|
||||
*/
|
||||
struct wil6210_mbox_hdr_wmi {
|
||||
u8 mid;
|
||||
u8 reserved;
|
||||
__le16 id;
|
||||
__le32 timestamp;
|
||||
} __packed;
|
||||
|
||||
struct pending_wmi_event {
|
||||
struct list_head list;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr hdr;
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
u8 data[0];
|
||||
} __packed event;
|
||||
};
|
||||
@ -455,6 +439,29 @@ struct wil_tid_ampdu_rx {
|
||||
bool first_time; /* is it 1-st time this buffer used? */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wil_tid_crypto_rx_single - TID crypto information (Rx).
|
||||
*
|
||||
* @pn: GCMP PN for the session
|
||||
* @key_set: valid key present
|
||||
*/
|
||||
struct wil_tid_crypto_rx_single {
|
||||
u8 pn[IEEE80211_GCMP_PN_LEN];
|
||||
bool key_set;
|
||||
};
|
||||
|
||||
struct wil_tid_crypto_rx {
|
||||
struct wil_tid_crypto_rx_single key_id[4];
|
||||
};
|
||||
|
||||
struct wil_p2p_info {
|
||||
struct ieee80211_channel listen_chan;
|
||||
u8 discovery_started;
|
||||
u64 cookie;
|
||||
struct timer_list discovery_timer; /* listen/search duration */
|
||||
struct work_struct discovery_expired_work; /* listen/search expire */
|
||||
};
|
||||
|
||||
enum wil_sta_status {
|
||||
wil_sta_unused = 0,
|
||||
wil_sta_conn_pending = 1,
|
||||
@ -474,6 +481,7 @@ struct wil_net_stats {
|
||||
unsigned long rx_non_data_frame;
|
||||
unsigned long rx_short_frame;
|
||||
unsigned long rx_large_frame;
|
||||
unsigned long rx_replay;
|
||||
u16 last_mcs_rx;
|
||||
u64 rx_per_mcs[WIL_MCS_MAX + 1];
|
||||
};
|
||||
@ -495,6 +503,8 @@ struct wil_sta_info {
|
||||
spinlock_t tid_rx_lock; /* guarding tid_rx array */
|
||||
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
|
||||
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
|
||||
struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM];
|
||||
struct wil_tid_crypto_rx group_crypto_rx;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -507,24 +517,6 @@ enum {
|
||||
hw_capability_last
|
||||
};
|
||||
|
||||
struct wil_back_rx {
|
||||
struct list_head list;
|
||||
/* request params, converted to CPU byte order - what we asked for */
|
||||
u8 cidxtid;
|
||||
u8 dialog_token;
|
||||
u16 ba_param_set;
|
||||
u16 ba_timeout;
|
||||
u16 ba_seq_ctrl;
|
||||
};
|
||||
|
||||
struct wil_back_tx {
|
||||
struct list_head list;
|
||||
/* request params, converted to CPU byte order - what we asked for */
|
||||
u8 ringid;
|
||||
u8 agg_wsize;
|
||||
u16 agg_timeout;
|
||||
};
|
||||
|
||||
struct wil_probe_client_req {
|
||||
struct list_head list;
|
||||
u64 cookie;
|
||||
@ -595,13 +587,6 @@ struct wil6210_priv {
|
||||
spinlock_t wmi_ev_lock;
|
||||
struct napi_struct napi_rx;
|
||||
struct napi_struct napi_tx;
|
||||
/* BACK */
|
||||
struct list_head back_rx_pending;
|
||||
struct mutex back_rx_mutex; /* protect @back_rx_pending */
|
||||
struct work_struct back_rx_worker;
|
||||
struct list_head back_tx_pending;
|
||||
struct mutex back_tx_mutex; /* protect @back_tx_pending */
|
||||
struct work_struct back_tx_worker;
|
||||
/* keep alive */
|
||||
struct list_head probe_client_pending;
|
||||
struct mutex probe_client_mutex; /* protect @probe_client_pending */
|
||||
@ -622,11 +607,21 @@ struct wil6210_priv {
|
||||
/* debugfs */
|
||||
struct dentry *debug;
|
||||
struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
|
||||
u8 discovery_mode;
|
||||
|
||||
void *platform_handle;
|
||||
struct wil_platform_ops platform_ops;
|
||||
|
||||
struct pmc_ctx pmc;
|
||||
|
||||
bool pbss;
|
||||
|
||||
struct wil_p2p_info p2p;
|
||||
|
||||
/* P2P_DEVICE vif */
|
||||
struct wireless_dev *p2p_wdev;
|
||||
struct mutex p2p_wdev_mutex; /* protect @p2p_wdev */
|
||||
struct wireless_dev *radio_wdev;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wdev->wiphy)
|
||||
@ -722,6 +717,7 @@ void wil_priv_deinit(struct wil6210_priv *wil);
|
||||
int wil_reset(struct wil6210_priv *wil, bool no_fw);
|
||||
void wil_fw_error_recovery(struct wil6210_priv *wil);
|
||||
void wil_set_recovery_state(struct wil6210_priv *wil, int state);
|
||||
bool wil_is_recovery_blocked(struct wil6210_priv *wil);
|
||||
int wil_up(struct wil6210_priv *wil);
|
||||
int __wil_up(struct wil6210_priv *wil);
|
||||
int wil_down(struct wil6210_priv *wil);
|
||||
@ -752,7 +748,6 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
int wmi_echo(struct wil6210_priv *wil);
|
||||
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
|
||||
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
|
||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
|
||||
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
||||
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
||||
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
|
||||
@ -765,11 +760,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
|
||||
u8 dialog_token, __le16 ba_param_set,
|
||||
__le16 ba_timeout, __le16 ba_seq_ctrl);
|
||||
void wil_back_rx_worker(struct work_struct *work);
|
||||
void wil_back_rx_flush(struct wil6210_priv *wil);
|
||||
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
|
||||
void wil_back_tx_worker(struct work_struct *work);
|
||||
void wil_back_tx_flush(struct wil6210_priv *wil);
|
||||
|
||||
void wil6210_clear_irq(struct wil6210_priv *wil);
|
||||
int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi);
|
||||
@ -779,6 +770,24 @@ void wil_unmask_irq(struct wil6210_priv *wil);
|
||||
void wil_configure_interrupt_moderation(struct wil6210_priv *wil);
|
||||
void wil_disable_irq(struct wil6210_priv *wil);
|
||||
void wil_enable_irq(struct wil6210_priv *wil);
|
||||
|
||||
/* P2P */
|
||||
void wil_p2p_discovery_timer_fn(ulong x);
|
||||
int wil_p2p_search(struct wil6210_priv *wil,
|
||||
struct cfg80211_scan_request *request);
|
||||
int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
|
||||
struct ieee80211_channel *chan, u64 *cookie);
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
|
||||
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
|
||||
void wil_p2p_listen_expired(struct work_struct *work);
|
||||
void wil_p2p_search_expired(struct work_struct *work);
|
||||
|
||||
/* WMI for P2P */
|
||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi);
|
||||
int wmi_start_listen(struct wil6210_priv *wil);
|
||||
int wmi_start_search(struct wil6210_priv *wil);
|
||||
int wmi_stop_discovery(struct wil6210_priv *wil);
|
||||
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie);
|
||||
@ -790,10 +799,11 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
|
||||
struct wireless_dev *wil_cfg80211_init(struct device *dev);
|
||||
void wil_wdev_free(struct wil6210_priv *wil);
|
||||
void wil_p2p_wdev_free(struct wil6210_priv *wil);
|
||||
|
||||
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 chan, u8 hidden_ssid, u8 is_go);
|
||||
int wmi_pcp_stop(struct wil6210_priv *wil);
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
u16 reason_code, bool from_event);
|
||||
|
@ -19,6 +19,12 @@
|
||||
|
||||
struct device;
|
||||
|
||||
enum wil_platform_event {
|
||||
WIL_PLATFORM_EVT_FW_CRASH = 0,
|
||||
WIL_PLATFORM_EVT_PRE_RESET = 1,
|
||||
WIL_PLATFORM_EVT_FW_RDY = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wil_platform_ops - wil platform module calls from this
|
||||
* driver to platform driver
|
||||
@ -28,7 +34,7 @@ struct wil_platform_ops {
|
||||
int (*suspend)(void *handle);
|
||||
int (*resume)(void *handle);
|
||||
void (*uninit)(void *handle);
|
||||
int (*notify_crash)(void *handle);
|
||||
int (*notify)(void *handle, enum wil_platform_event evt);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -176,7 +176,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
{
|
||||
struct {
|
||||
struct wil6210_mbox_hdr hdr;
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
} __packed cmd = {
|
||||
.hdr = {
|
||||
.type = WIL_MBOX_HDR_TYPE_WMI,
|
||||
@ -185,7 +185,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
},
|
||||
.wmi = {
|
||||
.mid = 0,
|
||||
.id = cpu_to_le16(cmdid),
|
||||
.command_id = cpu_to_le16(cmdid),
|
||||
},
|
||||
};
|
||||
struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
|
||||
@ -368,6 +368,8 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
|
||||
ie_len, true);
|
||||
|
||||
wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
|
||||
|
||||
bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
|
||||
d_len, signal, GFP_KERNEL);
|
||||
if (bss) {
|
||||
@ -378,8 +380,10 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
|
||||
}
|
||||
} else {
|
||||
cfg80211_rx_mgmt(wil->wdev, freq, signal,
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_rx_mgmt(wil->radio_wdev, freq, signal,
|
||||
(void *)rx_mgmt_frame, d_len, 0);
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,7 +410,10 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
|
||||
wil->scan_request, aborted);
|
||||
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_scan_done(wil->scan_request, aborted);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
wil->scan_request = NULL;
|
||||
} else {
|
||||
wil_err(wil, "SCAN_COMPLETE while not scanning\n");
|
||||
@ -487,6 +494,14 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
return;
|
||||
}
|
||||
del_timer_sync(&wil->connect_timer);
|
||||
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
|
||||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
|
||||
if (wil->sta[evt->cid].status != wil_sta_unused) {
|
||||
wil_err(wil, "%s: AP: Invalid status %d for CID %d\n",
|
||||
__func__, wil->sta[evt->cid].status, evt->cid);
|
||||
mutex_unlock(&wil->mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME FW can transmit only ucast frames to peer */
|
||||
@ -648,7 +663,7 @@ static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
|
||||
int len)
|
||||
{
|
||||
struct wmi_vring_ba_status_event *evt = d;
|
||||
struct wmi_ba_status_event *evt = d;
|
||||
struct vring_tx_data *txdata;
|
||||
|
||||
wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
|
||||
@ -834,10 +849,10 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
||||
offsetof(struct wil6210_mbox_ring_desc, sync), 0);
|
||||
/* indicate */
|
||||
if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
|
||||
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
|
||||
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
|
||||
u16 id = le16_to_cpu(wmi->id);
|
||||
u32 tstamp = le32_to_cpu(wmi->timestamp);
|
||||
(len >= sizeof(struct wmi_cmd_hdr))) {
|
||||
struct wmi_cmd_hdr *wmi = &evt->event.wmi;
|
||||
u16 id = le16_to_cpu(wmi->command_id);
|
||||
u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
|
||||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||
if (wil->reply_id && wil->reply_id == id) {
|
||||
if (wil->reply_buf) {
|
||||
@ -947,7 +962,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 chan, u8 hidden_ssid, u8 is_go)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@ -958,9 +973,10 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
|
||||
.channel = chan - 1,
|
||||
.pcp_max_assoc_sta = max_assoc_sta,
|
||||
.hidden_ssid = hidden_ssid,
|
||||
.is_go = is_go,
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_pcp_started_event evt;
|
||||
} __packed reply;
|
||||
|
||||
@ -1014,7 +1030,7 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_set_ssid_cmd cmd;
|
||||
} __packed reply;
|
||||
int len; /* reply.cmd.ssid_len in CPU order */
|
||||
@ -1047,7 +1063,7 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_set_pcp_channel_cmd cmd;
|
||||
} __packed reply;
|
||||
|
||||
@ -1064,14 +1080,86 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
|
||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
|
||||
{
|
||||
int rc;
|
||||
struct wmi_p2p_cfg_cmd cmd = {
|
||||
.discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD,
|
||||
.discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER,
|
||||
.bcon_interval = cpu_to_le16(bi),
|
||||
.channel = channel - 1,
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_p2p_cfg_done_event evt;
|
||||
} __packed reply;
|
||||
|
||||
return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
|
||||
wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
|
||||
|
||||
rc = wmi_call(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300);
|
||||
if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_start_listen(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_listen_started_event evt;
|
||||
} __packed reply;
|
||||
|
||||
wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
|
||||
|
||||
rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
|
||||
WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300);
|
||||
if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "device failed to start listen. status %d\n",
|
||||
reply.evt.status);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_start_search(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_search_started_event evt;
|
||||
} __packed reply;
|
||||
|
||||
wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
|
||||
|
||||
rc = wmi_call(wil, WMI_START_SEARCH_CMDID, NULL, 0,
|
||||
WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300);
|
||||
if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "device failed to start search. status %d\n",
|
||||
reply.evt.status);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_stop_discovery(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
|
||||
wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
|
||||
|
||||
rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
|
||||
WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
|
||||
|
||||
if (rc)
|
||||
wil_err(wil, "Failed to stop discovery\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
@ -1155,7 +1243,7 @@ int wmi_rxon(struct wil6210_priv *wil, bool on)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_listen_started_event evt;
|
||||
} __packed reply;
|
||||
|
||||
@ -1192,7 +1280,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
|
||||
.host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_cfg_rx_chain_done_event evt;
|
||||
} __packed evt;
|
||||
int rc;
|
||||
@ -1246,7 +1334,7 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
|
||||
.measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_temp_sense_done_event evt;
|
||||
} __packed reply;
|
||||
|
||||
@ -1272,7 +1360,7 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
|
||||
.disconnect_reason = cpu_to_le16(reason),
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_disconnect_event evt;
|
||||
} __packed reply;
|
||||
|
||||
@ -1364,7 +1452,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
|
||||
.ba_timeout = cpu_to_le16(timeout),
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_rcp_addba_resp_sent_event evt;
|
||||
} __packed reply;
|
||||
|
||||
@ -1420,10 +1508,10 @@ static void wmi_event_handle(struct wil6210_priv *wil,
|
||||
u16 len = le16_to_cpu(hdr->len);
|
||||
|
||||
if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
|
||||
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
|
||||
struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
|
||||
(len >= sizeof(struct wmi_cmd_hdr))) {
|
||||
struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]);
|
||||
void *evt_data = (void *)(&wmi[1]);
|
||||
u16 id = le16_to_cpu(wmi->id);
|
||||
u16 id = le16_to_cpu(wmi->command_id);
|
||||
|
||||
wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
|
||||
id, wil->reply_id);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5680,11 +5680,12 @@ static int b43_bcma_probe(struct bcma_device *core)
|
||||
INIT_WORK(&wl->firmware_load, b43_request_firmware);
|
||||
schedule_work(&wl->firmware_load);
|
||||
|
||||
bcma_out:
|
||||
return err;
|
||||
|
||||
bcma_err_wireless_exit:
|
||||
ieee80211_free_hw(wl->hw);
|
||||
bcma_out:
|
||||
kfree(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -5712,8 +5713,8 @@ static void b43_bcma_remove(struct bcma_device *core)
|
||||
b43_rng_exit(wl);
|
||||
|
||||
b43_leds_unregister(wl);
|
||||
|
||||
ieee80211_free_hw(wl->hw);
|
||||
kfree(wldev->dev);
|
||||
}
|
||||
|
||||
static struct bcma_driver b43_bcma_driver = {
|
||||
@ -5796,6 +5797,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
|
||||
|
||||
b43_leds_unregister(wl);
|
||||
b43_wireless_exit(dev, wl);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct ssb_driver b43_ssb_driver = {
|
||||
|
@ -250,7 +250,7 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
|
||||
u32 addr, u8 regsz, void *data, bool write)
|
||||
{
|
||||
struct sdio_func *func;
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
|
||||
write, fn, addr, regsz);
|
||||
|
@ -535,9 +535,6 @@ static int qcount[NUMPRIO];
|
||||
|
||||
#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
|
||||
|
||||
/* Retry count for register access failures */
|
||||
static const uint retry_limit = 2;
|
||||
|
||||
/* Limit on rounding up frames */
|
||||
static const uint max_roundup = 512;
|
||||
|
||||
@ -3261,7 +3258,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
|
||||
const struct firmware *fw,
|
||||
void *nvram, u32 nvlen)
|
||||
{
|
||||
int bcmerror = -EFAULT;
|
||||
int bcmerror;
|
||||
u32 rstvec;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
|
@ -3521,7 +3521,7 @@ static void ipw2100_msg_free(struct ipw2100_priv *priv)
|
||||
static ssize_t show_pci(struct device *d, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
|
||||
struct pci_dev *pci_dev = to_pci_dev(d);
|
||||
char *out = buf;
|
||||
int i, j;
|
||||
u32 val;
|
||||
|
@ -5553,6 +5553,7 @@ __il4965_up(struct il_priv *il)
|
||||
|
||||
il4965_prepare_card_hw(il);
|
||||
if (!il->hw_ready) {
|
||||
il_dealloc_bcast_stations(il);
|
||||
IL_ERR("HW not ready\n");
|
||||
return -EIO;
|
||||
}
|
||||
@ -5564,6 +5565,7 @@ __il4965_up(struct il_priv *il)
|
||||
set_bit(S_RFKILL, &il->status);
|
||||
wiphy_rfkill_set_hw_state(il->hw->wiphy, true);
|
||||
|
||||
il_dealloc_bcast_stations(il);
|
||||
il_enable_rfkill_int(il);
|
||||
IL_WARN("Radio disabled by HW RF Kill switch\n");
|
||||
return 0;
|
||||
@ -5577,6 +5579,7 @@ __il4965_up(struct il_priv *il)
|
||||
ret = il4965_hw_nic_init(il);
|
||||
if (ret) {
|
||||
IL_ERR("Unable to init nic\n");
|
||||
il_dealloc_bcast_stations(il);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -723,10 +723,9 @@ il_eeprom_init(struct il_priv *il)
|
||||
sz = il->cfg->eeprom_size;
|
||||
D_EEPROM("NVM size = %d\n", sz);
|
||||
il->eeprom = kzalloc(sz, GFP_KERNEL);
|
||||
if (!il->eeprom) {
|
||||
ret = -ENOMEM;
|
||||
goto alloc_err;
|
||||
}
|
||||
if (!il->eeprom)
|
||||
return -ENOMEM;
|
||||
|
||||
e = (__le16 *) il->eeprom;
|
||||
|
||||
il->ops->apm_init(il);
|
||||
@ -778,7 +777,6 @@ err:
|
||||
il_eeprom_free(il);
|
||||
/* Reset chip to save power until we load uCode during "up". */
|
||||
il_apm_stop(il);
|
||||
alloc_err:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(il_eeprom_init);
|
||||
@ -2794,8 +2792,10 @@ il_tx_queue_free(struct il_priv *il, int txq_id)
|
||||
il_tx_queue_unmap(il, txq_id);
|
||||
|
||||
/* De-alloc array of command/tx buffers */
|
||||
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
if (txq->cmd) {
|
||||
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
}
|
||||
|
||||
/* De-alloc circular buffer of TFDs */
|
||||
if (txq->q.n_bd)
|
||||
@ -2873,8 +2873,10 @@ il_cmd_queue_free(struct il_priv *il)
|
||||
il_cmd_queue_unmap(il);
|
||||
|
||||
/* De-alloc array of command/tx buffers */
|
||||
for (i = 0; i <= TFD_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
if (txq->cmd) {
|
||||
for (i = 0; i <= TFD_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
}
|
||||
|
||||
/* De-alloc circular buffer of TFDs */
|
||||
if (txq->q.n_bd)
|
||||
@ -3080,7 +3082,9 @@ err:
|
||||
kfree(txq->cmd[i]);
|
||||
out_free_arrays:
|
||||
kfree(txq->meta);
|
||||
txq->meta = NULL;
|
||||
kfree(txq->cmd);
|
||||
txq->cmd = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -88,16 +88,6 @@ config IWLWIFI_BCAST_FILTERING
|
||||
If unsure, don't enable this option, as some programs might
|
||||
expect incoming broadcasts for their normal operations.
|
||||
|
||||
config IWLWIFI_UAPSD
|
||||
bool "enable U-APSD by default"
|
||||
depends on IWLMVM
|
||||
help
|
||||
Say Y here to enable U-APSD by default. This may cause
|
||||
interoperability problems with some APs, manifesting in lower than
|
||||
expected throughput due to those APs not enabling aggregation
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config IWLWIFI_PCIE_RTPM
|
||||
bool "Enable runtime power management mode for PCIe devices"
|
||||
depends on IWLMVM && PM
|
||||
|
@ -1071,7 +1071,7 @@ static void iwl_bg_restart(struct work_struct *data)
|
||||
|
||||
static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
priv->workqueue = create_singlethread_workqueue(DRV_NAME);
|
||||
priv->workqueue = alloc_ordered_workqueue(DRV_NAME, 0);
|
||||
|
||||
INIT_WORK(&priv->restart, iwl_bg_restart);
|
||||
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
|
||||
|
@ -34,10 +34,6 @@
|
||||
#define IWL1000_UCODE_API_MAX 5
|
||||
#define IWL100_UCODE_API_MAX 5
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL1000_UCODE_API_OK 5
|
||||
#define IWL100_UCODE_API_OK 5
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL1000_UCODE_API_MIN 1
|
||||
#define IWL100_UCODE_API_MIN 5
|
||||
@ -86,7 +82,6 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = {
|
||||
#define IWL_DEVICE_1000 \
|
||||
.fw_name_pre = IWL1000_FW_PRE, \
|
||||
.ucode_api_max = IWL1000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL1000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL1000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_1000, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
@ -112,7 +107,6 @@ const struct iwl_cfg iwl1000_bg_cfg = {
|
||||
#define IWL_DEVICE_100 \
|
||||
.fw_name_pre = IWL100_FW_PRE, \
|
||||
.ucode_api_max = IWL100_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL100_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL100_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_100, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
@ -136,5 +130,5 @@ const struct iwl_cfg iwl100_bg_cfg = {
|
||||
IWL_DEVICE_100,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_MAX));
|
||||
|
@ -36,12 +36,6 @@
|
||||
#define IWL105_UCODE_API_MAX 6
|
||||
#define IWL135_UCODE_API_MAX 6
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL2030_UCODE_API_OK 6
|
||||
#define IWL2000_UCODE_API_OK 6
|
||||
#define IWL105_UCODE_API_OK 6
|
||||
#define IWL135_UCODE_API_OK 6
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL2030_UCODE_API_MIN 5
|
||||
#define IWL2000_UCODE_API_MIN 5
|
||||
@ -114,7 +108,6 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
|
||||
#define IWL_DEVICE_2000 \
|
||||
.fw_name_pre = IWL2000_FW_PRE, \
|
||||
.ucode_api_max = IWL2000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL2000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL2000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_2000, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -142,7 +135,6 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
|
||||
#define IWL_DEVICE_2030 \
|
||||
.fw_name_pre = IWL2030_FW_PRE, \
|
||||
.ucode_api_max = IWL2030_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL2030_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL2030_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_2030, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -163,7 +155,6 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
|
||||
#define IWL_DEVICE_105 \
|
||||
.fw_name_pre = IWL105_FW_PRE, \
|
||||
.ucode_api_max = IWL105_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL105_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL105_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_105, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -191,7 +182,6 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
|
||||
#define IWL_DEVICE_135 \
|
||||
.fw_name_pre = IWL135_FW_PRE, \
|
||||
.ucode_api_max = IWL135_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL135_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL135_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_135, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -210,7 +200,7 @@ const struct iwl_cfg iwl135_bgn_cfg = {
|
||||
.ht_params = &iwl2000_ht_params,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_MAX));
|
||||
|
@ -34,10 +34,6 @@
|
||||
#define IWL5000_UCODE_API_MAX 5
|
||||
#define IWL5150_UCODE_API_MAX 2
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL5000_UCODE_API_OK 5
|
||||
#define IWL5150_UCODE_API_OK 2
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL5000_UCODE_API_MIN 1
|
||||
#define IWL5150_UCODE_API_MIN 1
|
||||
@ -84,7 +80,6 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = {
|
||||
#define IWL_DEVICE_5000 \
|
||||
.fw_name_pre = IWL5000_FW_PRE, \
|
||||
.ucode_api_max = IWL5000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL5000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL5000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_5000, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
@ -132,7 +127,6 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
||||
.name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
|
||||
.fw_name_pre = IWL5000_FW_PRE,
|
||||
.ucode_api_max = IWL5000_UCODE_API_MAX,
|
||||
.ucode_api_ok = IWL5000_UCODE_API_OK,
|
||||
.ucode_api_min = IWL5000_UCODE_API_MIN,
|
||||
.device_family = IWL_DEVICE_FAMILY_5000,
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE,
|
||||
@ -149,7 +143,6 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
||||
#define IWL_DEVICE_5150 \
|
||||
.fw_name_pre = IWL5150_FW_PRE, \
|
||||
.ucode_api_max = IWL5150_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL5150_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL5150_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_5150, \
|
||||
.max_inst_size = IWLAGN_RTC_INST_SIZE, \
|
||||
@ -174,5 +167,5 @@ const struct iwl_cfg iwl5150_abg_cfg = {
|
||||
IWL_DEVICE_5150,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
|
||||
|
@ -36,13 +36,6 @@
|
||||
#define IWL6000G2_UCODE_API_MAX 6
|
||||
#define IWL6035_UCODE_API_MAX 6
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL6000_UCODE_API_OK 4
|
||||
#define IWL6000G2_UCODE_API_OK 5
|
||||
#define IWL6050_UCODE_API_OK 5
|
||||
#define IWL6000G2B_UCODE_API_OK 6
|
||||
#define IWL6035_UCODE_API_OK 6
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL6000_UCODE_API_MIN 4
|
||||
#define IWL6050_UCODE_API_MIN 4
|
||||
@ -136,7 +129,6 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
|
||||
#define IWL_DEVICE_6005 \
|
||||
.fw_name_pre = IWL6005_FW_PRE, \
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6000G2_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6005, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -191,7 +183,6 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
|
||||
#define IWL_DEVICE_6030 \
|
||||
.fw_name_pre = IWL6030_FW_PRE, \
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6000G2B_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6030, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -228,7 +219,6 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
|
||||
#define IWL_DEVICE_6035 \
|
||||
.fw_name_pre = IWL6030_FW_PRE, \
|
||||
.ucode_api_max = IWL6035_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6035_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6035_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6030, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -282,7 +272,6 @@ const struct iwl_cfg iwl130_bg_cfg = {
|
||||
#define IWL_DEVICE_6000i \
|
||||
.fw_name_pre = IWL6000_FW_PRE, \
|
||||
.ucode_api_max = IWL6000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6000i, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -370,7 +359,6 @@ const struct iwl_cfg iwl6000_3agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
|
||||
.fw_name_pre = IWL6000_FW_PRE,
|
||||
.ucode_api_max = IWL6000_UCODE_API_MAX,
|
||||
.ucode_api_ok = IWL6000_UCODE_API_OK,
|
||||
.ucode_api_min = IWL6000_UCODE_API_MIN,
|
||||
.device_family = IWL_DEVICE_FAMILY_6000,
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE,
|
||||
@ -383,7 +371,7 @@ const struct iwl_cfg iwl6000_3agn_cfg = {
|
||||
.led_mode = IWL_LED_BLINK,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_MAX));
|
||||
|
@ -76,16 +76,10 @@
|
||||
#define IWL7265D_UCODE_API_MAX 21
|
||||
#define IWL3168_UCODE_API_MAX 21
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL7260_UCODE_API_OK 13
|
||||
#define IWL7265_UCODE_API_OK 13
|
||||
#define IWL7265D_UCODE_API_OK 13
|
||||
#define IWL3168_UCODE_API_OK 20
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL7260_UCODE_API_MIN 13
|
||||
#define IWL7265_UCODE_API_MIN 13
|
||||
#define IWL7265D_UCODE_API_MIN 13
|
||||
#define IWL7260_UCODE_API_MIN 16
|
||||
#define IWL7265_UCODE_API_MIN 16
|
||||
#define IWL7265D_UCODE_API_MIN 16
|
||||
#define IWL3168_UCODE_API_MIN 20
|
||||
|
||||
/* NVM versions */
|
||||
@ -179,25 +173,21 @@ static const struct iwl_ht_params iwl7000_ht_params = {
|
||||
#define IWL_DEVICE_7000 \
|
||||
IWL_DEVICE_7000_COMMON, \
|
||||
.ucode_api_max = IWL7260_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL7260_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL7260_UCODE_API_MIN
|
||||
|
||||
#define IWL_DEVICE_7005 \
|
||||
IWL_DEVICE_7000_COMMON, \
|
||||
.ucode_api_max = IWL7265_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL7265_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL7265_UCODE_API_MIN
|
||||
|
||||
#define IWL_DEVICE_3008 \
|
||||
IWL_DEVICE_7000_COMMON, \
|
||||
.ucode_api_max = IWL3168_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL3168_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL3168_UCODE_API_MIN
|
||||
|
||||
#define IWL_DEVICE_7005D \
|
||||
IWL_DEVICE_7000_COMMON, \
|
||||
.ucode_api_max = IWL7265D_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL7265D_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL7265D_UCODE_API_MIN
|
||||
|
||||
const struct iwl_cfg iwl7260_2ac_cfg = {
|
||||
@ -388,8 +378,8 @@ const struct iwl_cfg iwl7265d_n_cfg = {
|
||||
.dccm_len = IWL7265_DCCM_LEN,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL3168_MODULE_FIRMWARE(IWL3168_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL3168_MODULE_FIRMWARE(IWL3168_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_MAX));
|
||||
|
@ -73,12 +73,8 @@
|
||||
#define IWL8000_UCODE_API_MAX 21
|
||||
#define IWL8265_UCODE_API_MAX 21
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL8000_UCODE_API_OK 13
|
||||
#define IWL8265_UCODE_API_OK 20
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL8000_UCODE_API_MIN 13
|
||||
#define IWL8000_UCODE_API_MIN 16
|
||||
#define IWL8265_UCODE_API_MIN 20
|
||||
|
||||
/* NVM versions */
|
||||
@ -175,19 +171,16 @@ static const struct iwl_tt_params iwl8000_tt_params = {
|
||||
#define IWL_DEVICE_8000 \
|
||||
IWL_DEVICE_8000_COMMON, \
|
||||
.ucode_api_max = IWL8000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL8000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL8000_UCODE_API_MIN \
|
||||
|
||||
#define IWL_DEVICE_8260 \
|
||||
IWL_DEVICE_8000_COMMON, \
|
||||
.ucode_api_max = IWL8000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL8000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL8000_UCODE_API_MIN \
|
||||
|
||||
#define IWL_DEVICE_8265 \
|
||||
IWL_DEVICE_8000_COMMON, \
|
||||
.ucode_api_max = IWL8265_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL8265_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL8265_UCODE_API_MIN \
|
||||
|
||||
const struct iwl_cfg iwl8260_2n_cfg = {
|
||||
@ -259,5 +252,5 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
|
||||
.max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_MAX));
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
* Copyright(c) 2015-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
|
||||
@ -18,7 +18,7 @@
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
* Copyright(c) 2015-2016 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -57,11 +57,8 @@
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL9000_UCODE_API_MAX 21
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL9000_UCODE_API_OK 13
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL9000_UCODE_API_MIN 13
|
||||
#define IWL9000_UCODE_API_MIN 16
|
||||
|
||||
/* NVM versions */
|
||||
#define IWL9000_NVM_VERSION 0x0a1d
|
||||
@ -122,7 +119,6 @@ static const struct iwl_tt_params iwl9000_tt_params = {
|
||||
|
||||
#define IWL_DEVICE_9000 \
|
||||
.ucode_api_max = IWL9000_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL9000_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL9000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_8000, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
@ -137,14 +133,15 @@ static const struct iwl_tt_params iwl9000_tt_params = {
|
||||
.dccm2_len = IWL9000_DCCM2_LEN, \
|
||||
.smem_offset = IWL9000_SMEM_OFFSET, \
|
||||
.smem_len = IWL9000_SMEM_LEN, \
|
||||
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \
|
||||
.thermal_params = &iwl9000_tt_params, \
|
||||
.apmg_not_supported = true, \
|
||||
.mq_rx_supported = true, \
|
||||
.vht_mu_mimo_supported = true, \
|
||||
.mac_addr_from_csr = true
|
||||
|
||||
const struct iwl_cfg iwl9260_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC 9260",
|
||||
const struct iwl_cfg iwl9560_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC 9560",
|
||||
.fw_name_pre = IWL9000_FW_PRE,
|
||||
IWL_DEVICE_9000,
|
||||
.ht_params = &iwl9000_ht_params,
|
||||
@ -163,4 +160,4 @@ const struct iwl_cfg iwl5165_2ac_cfg = {
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
|
||||
|
@ -131,6 +131,8 @@ enum iwl_led_mode {
|
||||
#define IWL_MAX_WD_TIMEOUT 120000
|
||||
|
||||
#define IWL_DEFAULT_MAX_TX_POWER 22
|
||||
#define IWL_TX_CSUM_NETIF_FLAGS (NETIF_F_IPV6_CSUM | NETIF_F_IP_CSUM |\
|
||||
NETIF_F_TSO | NETIF_F_TSO6)
|
||||
|
||||
/* Antenna presence definitions */
|
||||
#define ANT_NONE 0x0
|
||||
@ -277,8 +279,6 @@ struct iwl_pwr_tx_backoff {
|
||||
* (.ucode) will be added to filename before loading from disk. The
|
||||
* filename is constructed as fw_name_pre<api>.ucode.
|
||||
* @ucode_api_max: Highest version of uCode API supported by driver.
|
||||
* @ucode_api_ok: oldest version of the uCode API that is OK to load
|
||||
* without a warning, for use in transitions
|
||||
* @ucode_api_min: Lowest version of uCode API supported by driver.
|
||||
* @max_inst_size: The maximal length of the fw inst section
|
||||
* @max_data_size: The maximal length of the fw data section
|
||||
@ -324,7 +324,6 @@ struct iwl_cfg {
|
||||
const char *name;
|
||||
const char *fw_name_pre;
|
||||
const unsigned int ucode_api_max;
|
||||
const unsigned int ucode_api_ok;
|
||||
const unsigned int ucode_api_min;
|
||||
const enum iwl_device_family device_family;
|
||||
const u32 max_data_size;
|
||||
@ -439,7 +438,7 @@ 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 iwl4165_2ac_sdio_cfg;
|
||||
extern const struct iwl_cfg iwl9260_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl9560_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl5165_2ac_cfg;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
|
@ -179,6 +179,8 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
|
||||
kfree(drv->fw.dbg_conf_tlv[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
|
||||
kfree(drv->fw.dbg_trigger_tlv[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++)
|
||||
kfree(drv->fw.dbg_mem_tlv[i]);
|
||||
|
||||
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
|
||||
iwl_free_fw_img(drv, drv->fw.img + i);
|
||||
@ -297,6 +299,7 @@ struct iwl_firmware_pieces {
|
||||
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
|
||||
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
||||
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1041,6 +1044,37 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len);
|
||||
gscan_capa = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_FW_MEM_SEG: {
|
||||
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem =
|
||||
(void *)tlv_data;
|
||||
u32 type;
|
||||
|
||||
if (tlv_len != (sizeof(*dbg_mem)))
|
||||
goto invalid_tlv_len;
|
||||
|
||||
type = le32_to_cpu(dbg_mem->data_type);
|
||||
drv->fw.dbg_dynamic_mem = true;
|
||||
|
||||
if (type >= ARRAY_SIZE(drv->fw.dbg_mem_tlv)) {
|
||||
IWL_ERR(drv,
|
||||
"Skip unknown dbg mem segment: %u\n",
|
||||
dbg_mem->data_type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pieces->dbg_mem_tlv[type]) {
|
||||
IWL_ERR(drv,
|
||||
"Ignore duplicate mem segment: %u\n",
|
||||
dbg_mem->data_type);
|
||||
break;
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
|
||||
dbg_mem->data_type);
|
||||
|
||||
pieces->dbg_mem_tlv[type] = dbg_mem;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
|
||||
break;
|
||||
@ -1060,11 +1094,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (WARN(fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) &&
|
||||
!gscan_capa,
|
||||
"GSCAN is supported but capabilities TLV is unavailable\n"))
|
||||
/*
|
||||
* If ucode advertises that it supports GSCAN but GSCAN
|
||||
* capabilities TLV is not present, or if it has an old format,
|
||||
* warn and continue without GSCAN.
|
||||
*/
|
||||
if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) &&
|
||||
!gscan_capa) {
|
||||
IWL_DEBUG_INFO(drv,
|
||||
"GSCAN is supported but capabilities TLV is unavailable\n");
|
||||
__clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT,
|
||||
capa->_capa);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1199,7 +1240,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
int err;
|
||||
struct iwl_firmware_pieces *pieces;
|
||||
const unsigned int api_max = drv->cfg->ucode_api_max;
|
||||
unsigned int api_ok = drv->cfg->ucode_api_ok;
|
||||
const unsigned int api_min = drv->cfg->ucode_api_min;
|
||||
size_t trigger_tlv_sz[FW_DBG_TRIGGER_MAX];
|
||||
u32 api_ver;
|
||||
@ -1212,20 +1252,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
|
||||
fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS;
|
||||
|
||||
if (!api_ok)
|
||||
api_ok = api_max;
|
||||
|
||||
pieces = kzalloc(sizeof(*pieces), GFP_KERNEL);
|
||||
if (!pieces)
|
||||
return;
|
||||
|
||||
if (!ucode_raw) {
|
||||
if (drv->fw_index <= api_ok)
|
||||
IWL_ERR(drv,
|
||||
"request for firmware file '%s' failed.\n",
|
||||
drv->firmware_name);
|
||||
if (!ucode_raw)
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(drv, "Loaded firmware file '%s' (%zd bytes).\n",
|
||||
drv->firmware_name, ucode_raw->size);
|
||||
@ -1248,10 +1280,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
if (err)
|
||||
goto try_again;
|
||||
|
||||
if (fw_has_api(&drv->fw.ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION))
|
||||
api_ver = drv->fw.ucode_ver;
|
||||
else
|
||||
api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
|
||||
api_ver = drv->fw.ucode_ver;
|
||||
|
||||
/*
|
||||
* api_ver should match the api version forming part of the
|
||||
@ -1267,19 +1296,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
api_max, api_ver);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (api_ver < api_ok) {
|
||||
if (api_ok != api_max)
|
||||
IWL_ERR(drv, "Firmware has old API version, "
|
||||
"expected v%u through v%u, got v%u.\n",
|
||||
api_ok, api_max, api_ver);
|
||||
else
|
||||
IWL_ERR(drv, "Firmware has old API version, "
|
||||
"expected v%u, got v%u.\n",
|
||||
api_max, api_ver);
|
||||
IWL_ERR(drv, "New firmware can be obtained from "
|
||||
"http://www.intellinuxwireless.org/.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1368,6 +1384,17 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++) {
|
||||
if (pieces->dbg_mem_tlv[i]) {
|
||||
drv->fw.dbg_mem_tlv[i] =
|
||||
kmemdup(pieces->dbg_mem_tlv[i],
|
||||
sizeof(*drv->fw.dbg_mem_tlv[i]),
|
||||
GFP_KERNEL);
|
||||
if (!drv->fw.dbg_mem_tlv[i])
|
||||
goto out_free_fw;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we can no longer fail, copy information */
|
||||
|
||||
/*
|
||||
@ -1560,9 +1587,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
|
||||
.power_level = IWL_POWER_INDEX_1,
|
||||
.d0i3_disable = true,
|
||||
.d0i3_entry_delay = 1000,
|
||||
#ifndef CONFIG_IWLWIFI_UAPSD
|
||||
.uapsd_disable = true,
|
||||
#endif /* CONFIG_IWLWIFI_UAPSD */
|
||||
.uapsd_disable = IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT,
|
||||
/* the rest are 0 by default */
|
||||
};
|
||||
IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
|
||||
@ -1681,12 +1706,9 @@ module_param_named(lar_disable, iwlwifi_mod_params.lar_disable,
|
||||
MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)");
|
||||
|
||||
module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
|
||||
bool, S_IRUGO | S_IWUSR);
|
||||
#ifdef CONFIG_IWLWIFI_UAPSD
|
||||
MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)");
|
||||
#else
|
||||
MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)");
|
||||
#endif
|
||||
uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(uapsd_disable,
|
||||
"disable U-APSD functionality bitmap 1: BSS 2: P2P Client (default: 3)");
|
||||
|
||||
/*
|
||||
* set bt_coex_active to true, uCode will do kill/defer
|
||||
|
@ -105,6 +105,7 @@ enum iwl_fw_error_dump_type {
|
||||
IWL_FW_ERROR_DUMP_RB = 11,
|
||||
IWL_FW_ERROR_DUMP_PAGING = 12,
|
||||
IWL_FW_ERROR_DUMP_RADIO_REG = 13,
|
||||
IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14,
|
||||
|
||||
IWL_FW_ERROR_DUMP_MAX,
|
||||
};
|
||||
|
@ -142,6 +142,7 @@ enum iwl_ucode_tlv_type {
|
||||
IWL_UCODE_TLV_FW_DBG_CONF = 39,
|
||||
IWL_UCODE_TLV_FW_DBG_TRIGGER = 40,
|
||||
IWL_UCODE_TLV_FW_GSCAN_CAPA = 50,
|
||||
IWL_UCODE_TLV_FW_MEM_SEG = 51,
|
||||
};
|
||||
|
||||
struct iwl_ucode_tlv {
|
||||
@ -245,13 +246,11 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
|
||||
|
||||
/**
|
||||
* enum iwl_ucode_tlv_api - ucode api
|
||||
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
|
||||
* @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
|
||||
* longer than the passive one, which is essential for fragmented scan.
|
||||
* @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
|
||||
* @IWL_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header
|
||||
* @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
|
||||
* @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format
|
||||
* @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority
|
||||
* instead of 3.
|
||||
* @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size
|
||||
@ -260,12 +259,10 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
|
||||
* @NUM_IWL_UCODE_TLV_API: number of bits used
|
||||
*/
|
||||
enum iwl_ucode_tlv_api {
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3,
|
||||
IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8,
|
||||
IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9,
|
||||
IWL_UCODE_TLV_API_WIDE_CMD_HDR = (__force iwl_ucode_tlv_api_t)14,
|
||||
IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18,
|
||||
IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20,
|
||||
IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24,
|
||||
IWL_UCODE_TLV_API_TX_POWER_CHAIN = (__force iwl_ucode_tlv_api_t)27,
|
||||
|
||||
@ -324,6 +321,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
|
||||
* @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command
|
||||
* @IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in
|
||||
* regular image.
|
||||
* @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared
|
||||
* memory addresses from the firmware.
|
||||
* @IWL_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
|
||||
*/
|
||||
@ -361,6 +361,8 @@ enum iwl_ucode_tlv_capa {
|
||||
IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75,
|
||||
IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76,
|
||||
IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80,
|
||||
IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81,
|
||||
|
||||
NUM_IWL_UCODE_TLV_CAPA
|
||||
#ifdef __CHECKER__
|
||||
@ -490,6 +492,37 @@ enum iwl_fw_dbg_monitor_mode {
|
||||
MIPI_MODE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_fw_mem_seg_type - data types for dumping on error
|
||||
*
|
||||
* @FW_DBG_MEM_SMEM: the data type is SMEM
|
||||
* @FW_DBG_MEM_DCCM_LMAC: the data type is DCCM_LMAC
|
||||
* @FW_DBG_MEM_DCCM_UMAC: the data type is DCCM_UMAC
|
||||
*/
|
||||
enum iwl_fw_dbg_mem_seg_type {
|
||||
FW_DBG_MEM_DCCM_LMAC = 0,
|
||||
FW_DBG_MEM_DCCM_UMAC,
|
||||
FW_DBG_MEM_SMEM,
|
||||
|
||||
/* Must be last */
|
||||
FW_DBG_MEM_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
|
||||
*
|
||||
* @data_type: enum %iwl_fw_mem_seg_type
|
||||
* @ofs: the memory segment offset
|
||||
* @len: the memory segment length, in bytes
|
||||
*
|
||||
* This parses IWL_UCODE_TLV_FW_MEM_SEG
|
||||
*/
|
||||
struct iwl_fw_dbg_mem_seg_tlv {
|
||||
__le32 data_type;
|
||||
__le32 ofs;
|
||||
__le32 len;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data
|
||||
*
|
||||
|
@ -286,6 +286,8 @@ struct iwl_fw {
|
||||
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
|
||||
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
|
||||
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
|
||||
bool dbg_dynamic_mem;
|
||||
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
||||
u8 dbg_dest_reg_num;
|
||||
struct iwl_gscan_capabilities gscan_capa;
|
||||
|
@ -92,6 +92,11 @@ enum iwl_amsdu_size {
|
||||
IWL_AMSDU_12K = 2,
|
||||
};
|
||||
|
||||
enum iwl_uapsd_disable {
|
||||
IWL_DISABLE_UAPSD_BSS = BIT(0),
|
||||
IWL_DISABLE_UAPSD_P2P_CLIENT = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mod_params
|
||||
*
|
||||
@ -109,7 +114,8 @@ enum iwl_amsdu_size {
|
||||
* @debug_level: levels are IWL_DL_*
|
||||
* @ant_coupling: antenna coupling in dB, default = 0
|
||||
* @nvm_file: specifies a external NVM file
|
||||
* @uapsd_disable: disable U-APSD, default = 1
|
||||
* @uapsd_disable: disable U-APSD, see %enum iwl_uapsd_disable, default =
|
||||
* IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT
|
||||
* @d0i3_disable: disable d0i3, default = 1,
|
||||
* @d0i3_entry_delay: time to wait after no refs are taken before
|
||||
* entering D0i3 (in msecs)
|
||||
@ -131,7 +137,7 @@ struct iwl_mod_params {
|
||||
#endif
|
||||
int ant_coupling;
|
||||
char *nvm_file;
|
||||
bool uapsd_disable;
|
||||
u32 uapsd_disable;
|
||||
bool d0i3_disable;
|
||||
unsigned int d0i3_entry_delay;
|
||||
bool lar_disable;
|
||||
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* 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
|
||||
@ -33,6 +34,7 @@
|
||||
*
|
||||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -345,6 +347,16 @@ enum secure_load_status_reg {
|
||||
#define TXF_READ_MODIFY_DATA (0xa00448)
|
||||
#define TXF_READ_MODIFY_ADDR (0xa0044c)
|
||||
|
||||
/* UMAC Internal Tx Fifo */
|
||||
#define TXF_CPU2_FIFO_ITEM_CNT (0xA00538)
|
||||
#define TXF_CPU2_WR_PTR (0xA00514)
|
||||
#define TXF_CPU2_RD_PTR (0xA00510)
|
||||
#define TXF_CPU2_FENCE_PTR (0xA00518)
|
||||
#define TXF_CPU2_LOCK_FENCE (0xA00524)
|
||||
#define TXF_CPU2_NUM (0xA0053C)
|
||||
#define TXF_CPU2_READ_MODIFY_DATA (0xA00548)
|
||||
#define TXF_CPU2_READ_MODIFY_ADDR (0xA0054C)
|
||||
|
||||
/* Radio registers access */
|
||||
#define RSP_RADIO_CMD (0xa02804)
|
||||
#define RSP_RADIO_RDDAT (0xa02814)
|
||||
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* 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
|
||||
@ -33,6 +34,7 @@
|
||||
*
|
||||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -519,7 +521,7 @@ struct iwl_trans;
|
||||
|
||||
struct iwl_trans_txq_scd_cfg {
|
||||
u8 fifo;
|
||||
s8 sta_id;
|
||||
u8 sta_id;
|
||||
u8 tid;
|
||||
bool aggregate;
|
||||
int frame_limit;
|
||||
|
@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o
|
||||
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
|
||||
iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o
|
||||
iwlmvm-y += scan.o time-event.o rs.o
|
||||
iwlmvm-y += power.o coex.o coex_legacy.o
|
||||
iwlmvm-y += power.o coex.o
|
||||
iwlmvm-y += tt.o offloading.o tdls.o
|
||||
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
|
||||
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
|
||||
|
@ -411,9 +411,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
||||
struct iwl_bt_coex_cmd bt_cmd = {};
|
||||
u32 mode;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_send_bt_init_conf_old(mvm);
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
|
||||
@ -728,12 +725,6 @@ void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
|
||||
iwl_mvm_rx_bt_coex_notif_old(mvm, rxb);
|
||||
return;
|
||||
}
|
||||
|
||||
IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
|
||||
IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
|
||||
IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
|
||||
@ -755,12 +746,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
|
||||
iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event);
|
||||
return;
|
||||
}
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* Ignore updates if we are in force mode */
|
||||
@ -807,9 +792,6 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
|
||||
enum iwl_bt_coex_lut_type lut_type;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
|
||||
|
||||
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
|
||||
return LINK_QUAL_AGG_TIME_LIMIT_DEF;
|
||||
|
||||
@ -834,9 +816,6 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
|
||||
enum iwl_bt_coex_lut_type lut_type;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);
|
||||
|
||||
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
|
||||
return true;
|
||||
|
||||
@ -864,9 +843,6 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
|
||||
if (ant & mvm->cfg->non_shared_ant)
|
||||
return true;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
|
||||
|
||||
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
|
||||
BT_HIGH_TRAFFIC;
|
||||
}
|
||||
@ -877,9 +853,6 @@ bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
|
||||
if (mvm->cfg->bt_shared_single_ant)
|
||||
return true;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
|
||||
|
||||
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
|
||||
}
|
||||
|
||||
@ -888,9 +861,6 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
|
||||
{
|
||||
u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band);
|
||||
|
||||
if (band != IEEE80211_BAND_2GHZ)
|
||||
return false;
|
||||
|
||||
@ -937,12 +907,6 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
|
||||
|
||||
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
|
||||
{
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
|
||||
iwl_mvm_bt_coex_vif_change_old(mvm);
|
||||
return;
|
||||
}
|
||||
|
||||
iwl_mvm_bt_coex_notif_handle(mvm);
|
||||
}
|
||||
|
||||
@ -955,12 +919,6 @@ void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
|
||||
u8 __maybe_unused lower_bound, upper_bound;
|
||||
u8 lut;
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
|
||||
iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iwl_mvm_bt_is_plcr_supported(mvm))
|
||||
return;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -75,7 +75,6 @@
|
||||
#define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
|
||||
#define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */
|
||||
#define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */
|
||||
#define IWL_MVM_P2P_UAPSD_STANDALONE 0
|
||||
#define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE 0
|
||||
#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
|
||||
#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
|
||||
|
@ -723,7 +723,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false);
|
||||
ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
|
||||
|
@ -1425,6 +1425,89 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const char * const chanwidths[] = {
|
||||
[NL80211_CHAN_WIDTH_20_NOHT] = "noht",
|
||||
[NL80211_CHAN_WIDTH_20] = "ht20",
|
||||
[NL80211_CHAN_WIDTH_40] = "ht40",
|
||||
[NL80211_CHAN_WIDTH_80] = "vht80",
|
||||
[NL80211_CHAN_WIDTH_80P80] = "vht80p80",
|
||||
[NL80211_CHAN_WIDTH_160] = "vht160",
|
||||
};
|
||||
|
||||
static bool iwl_mvm_lqm_notif_wait(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_rx_packet *pkt, void *data)
|
||||
{
|
||||
struct ieee80211_vif *vif = data;
|
||||
struct iwl_mvm *mvm =
|
||||
container_of(notif_wait, struct iwl_mvm, notif_wait);
|
||||
struct iwl_link_qual_msrmnt_notif *report = (void *)pkt->data;
|
||||
u32 num_of_stations = le32_to_cpu(report->number_of_stations);
|
||||
int i;
|
||||
|
||||
IWL_INFO(mvm, "LQM report:\n");
|
||||
IWL_INFO(mvm, "\tstatus: %d\n", report->status);
|
||||
IWL_INFO(mvm, "\tmacID: %d\n", le32_to_cpu(report->mac_id));
|
||||
IWL_INFO(mvm, "\ttx_frame_dropped: %d\n",
|
||||
le32_to_cpu(report->tx_frame_dropped));
|
||||
IWL_INFO(mvm, "\ttime_in_measurement_window: %d us\n",
|
||||
le32_to_cpu(report->time_in_measurement_window));
|
||||
IWL_INFO(mvm, "\ttotal_air_time_other_stations: %d\n",
|
||||
le32_to_cpu(report->total_air_time_other_stations));
|
||||
IWL_INFO(mvm, "\tchannel_freq: %d\n",
|
||||
vif->bss_conf.chandef.center_freq1);
|
||||
IWL_INFO(mvm, "\tchannel_width: %s\n",
|
||||
chanwidths[vif->bss_conf.chandef.width]);
|
||||
IWL_INFO(mvm, "\tnumber_of_stations: %d\n", num_of_stations);
|
||||
for (i = 0; i < num_of_stations; i++)
|
||||
IWL_INFO(mvm, "\t\tsta[%d]: %d\n", i,
|
||||
report->frequent_stations_air_time[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_lqm_send_cmd_write(struct ieee80211_vif *vif,
|
||||
char *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm *mvm = mvmvif->mvm;
|
||||
struct iwl_notification_wait wait_lqm_notif;
|
||||
static u16 lqm_notif[] = {
|
||||
WIDE_ID(MAC_CONF_GROUP,
|
||||
LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF)
|
||||
};
|
||||
int err;
|
||||
u32 duration;
|
||||
u32 timeout;
|
||||
|
||||
if (sscanf(buf, "%d,%d", &duration, &timeout) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait, &wait_lqm_notif,
|
||||
lqm_notif, ARRAY_SIZE(lqm_notif),
|
||||
iwl_mvm_lqm_notif_wait, vif);
|
||||
mutex_lock(&mvm->mutex);
|
||||
err = iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_START_MEASUREMENT,
|
||||
duration, timeout);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
if (err) {
|
||||
IWL_ERR(mvm, "Failed to send lqm cmdf(err=%d)\n", err);
|
||||
iwl_remove_notification(&mvm->notif_wait, &wait_lqm_notif);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* wait for 2 * timeout (safety guard) and convert to jiffies*/
|
||||
timeout = msecs_to_jiffies((timeout * 2) / 1000);
|
||||
|
||||
err = iwl_wait_notification(&mvm->notif_wait, &wait_lqm_notif,
|
||||
timeout);
|
||||
if (err)
|
||||
IWL_ERR(mvm, "Getting lqm notif timed out\n");
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
|
||||
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
|
||||
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
|
||||
@ -1449,6 +1532,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64);
|
||||
|
||||
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
@ -1488,6 +1572,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
|
||||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
|
||||
mvmvif == mvm->bf_allowed_vif)
|
||||
|
@ -65,6 +65,7 @@
|
||||
*****************************************************************************/
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "mvm.h"
|
||||
#include "fw-dbg.h"
|
||||
@ -463,69 +464,11 @@ int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static
|
||||
int iwl_mvm_coex_dump_mbox_old(struct iwl_bt_coex_profile_notif_old *notif,
|
||||
char *buf, int pos, int bufsz)
|
||||
{
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
|
||||
|
||||
BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
|
||||
BT_MBOX_PRINT(0, LE_PROF1, false);
|
||||
BT_MBOX_PRINT(0, LE_PROF2, false);
|
||||
BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
|
||||
BT_MBOX_PRINT(0, CHL_SEQ_N, false);
|
||||
BT_MBOX_PRINT(0, INBAND_S, false);
|
||||
BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
|
||||
BT_MBOX_PRINT(0, LE_SCAN, false);
|
||||
BT_MBOX_PRINT(0, LE_ADV, false);
|
||||
BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
|
||||
BT_MBOX_PRINT(0, OPEN_CON_1, true);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
|
||||
|
||||
BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
|
||||
BT_MBOX_PRINT(1, IP_SR, false);
|
||||
BT_MBOX_PRINT(1, LE_MSTR, false);
|
||||
BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
|
||||
BT_MBOX_PRINT(1, MSG_TYPE, false);
|
||||
BT_MBOX_PRINT(1, SSN, true);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
|
||||
|
||||
BT_MBOX_PRINT(2, SNIFF_ACT, false);
|
||||
BT_MBOX_PRINT(2, PAG, false);
|
||||
BT_MBOX_PRINT(2, INQUIRY, false);
|
||||
BT_MBOX_PRINT(2, CONN, false);
|
||||
BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
|
||||
BT_MBOX_PRINT(2, DISC, false);
|
||||
BT_MBOX_PRINT(2, SCO_TX_ACT, false);
|
||||
BT_MBOX_PRINT(2, SCO_RX_ACT, false);
|
||||
BT_MBOX_PRINT(2, ESCO_RE_TX, false);
|
||||
BT_MBOX_PRINT(2, SCO_DURATION, true);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
|
||||
|
||||
BT_MBOX_PRINT(3, SCO_STATE, false);
|
||||
BT_MBOX_PRINT(3, SNIFF_STATE, false);
|
||||
BT_MBOX_PRINT(3, A2DP_STATE, false);
|
||||
BT_MBOX_PRINT(3, ACL_STATE, false);
|
||||
BT_MBOX_PRINT(3, MSTR_STATE, false);
|
||||
BT_MBOX_PRINT(3, OBX_STATE, false);
|
||||
BT_MBOX_PRINT(3, OPEN_CON_2, false);
|
||||
BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
|
||||
BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
|
||||
BT_MBOX_PRINT(3, INBAND_P, false);
|
||||
BT_MBOX_PRINT(3, MSG_TYPE_2, false);
|
||||
BT_MBOX_PRINT(3, SSN_2, false);
|
||||
BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
|
||||
char *buf;
|
||||
int ret, pos = 0, bufsz = sizeof(char) * 1024;
|
||||
|
||||
@ -535,52 +478,24 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
|
||||
struct iwl_bt_coex_profile_notif_old *notif =
|
||||
&mvm->last_bt_notif_old;
|
||||
pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz);
|
||||
|
||||
pos += iwl_mvm_coex_dump_mbox_old(notif, buf, pos, bufsz);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
|
||||
notif->bt_ci_compliance);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->primary_ch_lut));
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->secondary_ch_lut));
|
||||
pos += scnprintf(buf+pos,
|
||||
bufsz-pos, "bt_activity_grading = %d\n",
|
||||
le32_to_cpu(notif->bt_activity_grading));
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"antenna isolation = %d CORUN LUT index = %d\n",
|
||||
mvm->last_ant_isol, mvm->last_corun_lut);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n",
|
||||
notif->rrc_enabled);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n",
|
||||
notif->ttc_enabled);
|
||||
} else {
|
||||
struct iwl_bt_coex_profile_notif *notif =
|
||||
&mvm->last_bt_notif;
|
||||
|
||||
pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
|
||||
notif->bt_ci_compliance);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->primary_ch_lut));
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->secondary_ch_lut));
|
||||
pos += scnprintf(buf+pos,
|
||||
bufsz-pos, "bt_activity_grading = %d\n",
|
||||
le32_to_cpu(notif->bt_activity_grading));
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"antenna isolation = %d CORUN LUT index = %d\n",
|
||||
mvm->last_ant_isol, mvm->last_corun_lut);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n",
|
||||
(notif->ttc_rrc_status >> 4) & 0xF);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n",
|
||||
notif->ttc_rrc_status & 0xF);
|
||||
}
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n",
|
||||
notif->bt_ci_compliance);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "primary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->primary_ch_lut));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "secondary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->secondary_ch_lut));
|
||||
pos += scnprintf(buf + pos,
|
||||
bufsz - pos, "bt_activity_grading = %d\n",
|
||||
le32_to_cpu(notif->bt_activity_grading));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"antenna isolation = %d CORUN LUT index = %d\n",
|
||||
mvm->last_ant_isol, mvm->last_corun_lut);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n",
|
||||
(notif->ttc_rrc_status >> 4) & 0xF);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n",
|
||||
notif->ttc_rrc_status & 0xF);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n",
|
||||
IWL_MVM_BT_COEX_SYNC2SCO);
|
||||
@ -602,44 +517,20 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
|
||||
char buf[256];
|
||||
int bufsz = sizeof(buf);
|
||||
int pos = 0;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
|
||||
struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd_old;
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"Channel inhibition CMD\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_primary_ci));
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_secondary_ci));
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"BT Configuration CMD - 0=default, 1=never, 2=always\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill msk idx %d\n",
|
||||
mvm->bt_ack_kill_msk[0]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill msk idx %d\n",
|
||||
mvm->bt_cts_kill_msk[0]);
|
||||
|
||||
} else {
|
||||
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"Channel inhibition CMD\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_primary_ci));
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_secondary_ci));
|
||||
}
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Channel inhibition CMD\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tPrimary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_primary_ci));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\tSecondary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_secondary_ci));
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
@ -990,8 +881,10 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
|
||||
struct iwl_rss_config_cmd cmd = {
|
||||
.flags = cpu_to_le32(IWL_RSS_ENABLE),
|
||||
.hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
|
||||
IWL_RSS_HASH_TYPE_IPV4_UDP |
|
||||
IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
|
||||
IWL_RSS_HASH_TYPE_IPV6_TCP |
|
||||
IWL_RSS_HASH_TYPE_IPV6_UDP |
|
||||
IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
|
||||
};
|
||||
int ret, i, num_repeats, nbytes = count / 2;
|
||||
@ -1015,7 +908,7 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
|
||||
memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
|
||||
ARRAY_SIZE(cmd.indirection_table) % nbytes);
|
||||
|
||||
memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key));
|
||||
netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key));
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user