Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for v5.17. Major changes: ath11k * support PCI devices with 1 MSI vector * WCN6855 hw2.1 support * 11d scan offload support * full monitor mode, only supported on QCN9074 * scan MAC address randomization support * reserved host DDR addresses from DT for PCI devices support ath9k * switch to rate table based lookup ath * extend South Korea regulatory domain support wcn36xx * beacon filter support
This commit is contained in:
commit
fd5e3c4ab9
@ -150,6 +150,12 @@ properties:
|
|||||||
string to uniquely identify variant of the calibration data in the
|
string to uniquely identify variant of the calibration data in the
|
||||||
board-2.bin for designs with colliding bus and device specific ids
|
board-2.bin for designs with colliding bus and device specific ids
|
||||||
|
|
||||||
|
memory-region:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
phandle to a node describing reserved memory (System RAM memory)
|
||||||
|
used by ath11k firmware (see bindings/reserved-memory/reserved-memory.txt)
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
@ -279,3 +285,27 @@ examples:
|
|||||||
"tcl2host-status-ring";
|
"tcl2host-status-ring";
|
||||||
qcom,rproc = <&q6v5_wcss>;
|
qcom,rproc = <&q6v5_wcss>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
|
||||||
|
reserved-memory {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
|
||||||
|
qcn9074_0: qcn9074_0@51100000 {
|
||||||
|
no-map;
|
||||||
|
reg = <0x0 0x51100000 0x0 0x03500000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pci {
|
||||||
|
pcie0 {
|
||||||
|
#size-cells = <2>;
|
||||||
|
#address-cells = <3>;
|
||||||
|
|
||||||
|
wifi_0: wifi@0 {
|
||||||
|
reg = <0 0 0 0 0>;
|
||||||
|
memory-region = <&qcn9074_0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -90,6 +90,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = true,
|
.tx_stats_over_pktlog = true,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -125,6 +126,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = true,
|
.tx_stats_over_pktlog = true,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -161,6 +163,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -191,6 +194,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.num_wds_entries = 0x20,
|
.num_wds_entries = 0x20,
|
||||||
.uart_pin_workaround = true,
|
.uart_pin_workaround = true,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.bmi_large_size_download = true,
|
.bmi_large_size_download = true,
|
||||||
.supports_peer_stats_info = true,
|
.supports_peer_stats_info = true,
|
||||||
.dynamic_sar_support = true,
|
.dynamic_sar_support = true,
|
||||||
@ -227,6 +231,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -262,6 +267,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -297,6 +303,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -335,6 +342,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = true,
|
.fw_diag_ce_download = true,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.supports_peer_stats_info = true,
|
.supports_peer_stats_info = true,
|
||||||
.dynamic_sar_support = true,
|
.dynamic_sar_support = true,
|
||||||
@ -377,6 +385,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -425,6 +434,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -470,6 +480,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -505,6 +516,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -542,6 +554,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = true,
|
.fw_diag_ce_download = true,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -571,6 +584,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.ast_skid_limit = 0x10,
|
.ast_skid_limit = 0x10,
|
||||||
.num_wds_entries = 0x20,
|
.num_wds_entries = 0x20,
|
||||||
.uart_pin_workaround = true,
|
.uart_pin_workaround = true,
|
||||||
|
.credit_size_workaround = true,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -612,6 +626,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = false,
|
.rri_on_ddr = false,
|
||||||
.hw_filter_reset_required = true,
|
.hw_filter_reset_required = true,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = false,
|
.dynamic_sar_support = false,
|
||||||
},
|
},
|
||||||
@ -640,6 +655,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||||||
.rri_on_ddr = true,
|
.rri_on_ddr = true,
|
||||||
.hw_filter_reset_required = false,
|
.hw_filter_reset_required = false,
|
||||||
.fw_diag_ce_download = false,
|
.fw_diag_ce_download = false,
|
||||||
|
.credit_size_workaround = false,
|
||||||
.tx_stats_over_pktlog = false,
|
.tx_stats_over_pktlog = false,
|
||||||
.dynamic_sar_support = true,
|
.dynamic_sar_support = true,
|
||||||
},
|
},
|
||||||
@ -715,6 +731,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
|
|||||||
|
|
||||||
static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||||
{
|
{
|
||||||
|
bool mtu_workaround = ar->hw_params.credit_size_workaround;
|
||||||
int ret;
|
int ret;
|
||||||
u32 param = 0;
|
u32 param = 0;
|
||||||
|
|
||||||
@ -732,7 +749,7 @@ static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
|||||||
|
|
||||||
param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
|
param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
|
||||||
|
|
||||||
if (mode == ATH10K_FIRMWARE_MODE_NORMAL)
|
if (mode == ATH10K_FIRMWARE_MODE_NORMAL && !mtu_workaround)
|
||||||
param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
||||||
else
|
else
|
||||||
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
||||||
|
@ -1400,115 +1400,6 @@ enum htt_dbg_stats_status {
|
|||||||
HTT_DBG_STATS_STATUS_SERIES_DONE = 7
|
HTT_DBG_STATS_STATUS_SERIES_DONE = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* target -> host statistics upload
|
|
||||||
*
|
|
||||||
* The following field definitions describe the format of the HTT target
|
|
||||||
* to host stats upload confirmation message.
|
|
||||||
* The message contains a cookie echoed from the HTT host->target stats
|
|
||||||
* upload request, which identifies which request the confirmation is
|
|
||||||
* for, and a series of tag-length-value stats information elements.
|
|
||||||
* The tag-length header for each stats info element also includes a
|
|
||||||
* status field, to indicate whether the request for the stat type in
|
|
||||||
* question was fully met, partially met, unable to be met, or invalid
|
|
||||||
* (if the stat type in question is disabled in the target).
|
|
||||||
* A special value of all 1's in this status field is used to indicate
|
|
||||||
* the end of the series of stats info elements.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* |31 16|15 8|7 5|4 0|
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | reserved | msg type |
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | cookie LSBs |
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | cookie MSBs |
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | stats entry length | reserved | S |stat type|
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | |
|
|
||||||
* | type-specific stats info |
|
|
||||||
* | |
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | stats entry length | reserved | S |stat type|
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | |
|
|
||||||
* | type-specific stats info |
|
|
||||||
* | |
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* | n/a | reserved | 111 | n/a |
|
|
||||||
* |------------------------------------------------------------|
|
|
||||||
* Header fields:
|
|
||||||
* - MSG_TYPE
|
|
||||||
* Bits 7:0
|
|
||||||
* Purpose: identifies this is a statistics upload confirmation message
|
|
||||||
* Value: 0x9
|
|
||||||
* - COOKIE_LSBS
|
|
||||||
* Bits 31:0
|
|
||||||
* Purpose: Provide a mechanism to match a target->host stats confirmation
|
|
||||||
* message with its preceding host->target stats request message.
|
|
||||||
* Value: LSBs of the opaque cookie specified by the host-side requestor
|
|
||||||
* - COOKIE_MSBS
|
|
||||||
* Bits 31:0
|
|
||||||
* Purpose: Provide a mechanism to match a target->host stats confirmation
|
|
||||||
* message with its preceding host->target stats request message.
|
|
||||||
* Value: MSBs of the opaque cookie specified by the host-side requestor
|
|
||||||
*
|
|
||||||
* Stats Information Element tag-length header fields:
|
|
||||||
* - STAT_TYPE
|
|
||||||
* Bits 4:0
|
|
||||||
* Purpose: identifies the type of statistics info held in the
|
|
||||||
* following information element
|
|
||||||
* Value: htt_dbg_stats_type
|
|
||||||
* - STATUS
|
|
||||||
* Bits 7:5
|
|
||||||
* Purpose: indicate whether the requested stats are present
|
|
||||||
* Value: htt_dbg_stats_status, including a special value (0x7) to mark
|
|
||||||
* the completion of the stats entry series
|
|
||||||
* - LENGTH
|
|
||||||
* Bits 31:16
|
|
||||||
* Purpose: indicate the stats information size
|
|
||||||
* Value: This field specifies the number of bytes of stats information
|
|
||||||
* that follows the element tag-length header.
|
|
||||||
* It is expected but not required that this length is a multiple of
|
|
||||||
* 4 bytes. Even if the length is not an integer multiple of 4, the
|
|
||||||
* subsequent stats entry header will begin on a 4-byte aligned
|
|
||||||
* boundary.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HTT_STATS_CONF_ITEM_INFO_STAT_TYPE_MASK 0x1F
|
|
||||||
#define HTT_STATS_CONF_ITEM_INFO_STAT_TYPE_LSB 0
|
|
||||||
#define HTT_STATS_CONF_ITEM_INFO_STATUS_MASK 0xE0
|
|
||||||
#define HTT_STATS_CONF_ITEM_INFO_STATUS_LSB 5
|
|
||||||
|
|
||||||
struct htt_stats_conf_item {
|
|
||||||
union {
|
|
||||||
u8 info;
|
|
||||||
struct {
|
|
||||||
u8 stat_type:5; /* %HTT_DBG_STATS_ */
|
|
||||||
u8 status:3; /* %HTT_DBG_STATS_STATUS_ */
|
|
||||||
} __packed;
|
|
||||||
} __packed;
|
|
||||||
u8 pad;
|
|
||||||
__le16 length;
|
|
||||||
u8 payload[]; /* roundup(length, 4) long */
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct htt_stats_conf {
|
|
||||||
u8 pad[3];
|
|
||||||
__le32 cookie_lsb;
|
|
||||||
__le32 cookie_msb;
|
|
||||||
|
|
||||||
/* each item has variable length! */
|
|
||||||
struct htt_stats_conf_item items[];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
static inline struct htt_stats_conf_item *htt_stats_conf_next_item(
|
|
||||||
const struct htt_stats_conf_item *item)
|
|
||||||
{
|
|
||||||
return (void *)item + sizeof(*item) + roundup(item->length, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank
|
* host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank
|
||||||
*
|
*
|
||||||
@ -1828,7 +1719,6 @@ struct htt_resp {
|
|||||||
struct htt_rc_update rc_update;
|
struct htt_rc_update rc_update;
|
||||||
struct htt_rx_test rx_test;
|
struct htt_rx_test rx_test;
|
||||||
struct htt_pktlog_msg pktlog_msg;
|
struct htt_pktlog_msg pktlog_msg;
|
||||||
struct htt_stats_conf stats_conf;
|
|
||||||
struct htt_rx_pn_ind rx_pn_ind;
|
struct htt_rx_pn_ind rx_pn_ind;
|
||||||
struct htt_rx_offload_ind rx_offload_ind;
|
struct htt_rx_offload_ind rx_offload_ind;
|
||||||
struct htt_rx_in_ord_ind rx_in_ord_ind;
|
struct htt_rx_in_ord_ind rx_in_ord_ind;
|
||||||
|
@ -147,6 +147,9 @@ void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
|||||||
htt->num_pending_tx--;
|
htt->num_pending_tx--;
|
||||||
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
|
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
|
||||||
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||||
|
|
||||||
|
if (htt->num_pending_tx == 0)
|
||||||
|
wake_up(&htt->empty_tx_wq);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
||||||
|
@ -618,6 +618,9 @@ struct ath10k_hw_params {
|
|||||||
*/
|
*/
|
||||||
bool uart_pin_workaround;
|
bool uart_pin_workaround;
|
||||||
|
|
||||||
|
/* Workaround for the credit size calculation */
|
||||||
|
bool credit_size_workaround;
|
||||||
|
|
||||||
/* tx stats support over pktlog */
|
/* tx stats support over pktlog */
|
||||||
bool tx_stats_over_pktlog;
|
bool tx_stats_over_pktlog;
|
||||||
|
|
||||||
|
@ -6380,13 +6380,14 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
|
|||||||
scan_timeout = min_t(u32, arg.max_rest_time *
|
scan_timeout = min_t(u32, arg.max_rest_time *
|
||||||
(arg.n_channels - 1) + (req->duration +
|
(arg.n_channels - 1) + (req->duration +
|
||||||
ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) *
|
ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) *
|
||||||
arg.n_channels, arg.max_scan_time + 200);
|
arg.n_channels, arg.max_scan_time);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Add a 200ms margin to account for event/command processing */
|
scan_timeout = arg.max_scan_time;
|
||||||
scan_timeout = arg.max_scan_time + 200;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add a 200ms margin to account for event/command processing */
|
||||||
|
scan_timeout += 200;
|
||||||
|
|
||||||
ret = ath10k_start_scan(ar, &arg);
|
ret = ath10k_start_scan(ar, &arg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
|
ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
|
||||||
|
@ -82,8 +82,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
|||||||
flags = skb_cb->flags;
|
flags = skb_cb->flags;
|
||||||
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
||||||
ath10k_htt_tx_dec_pending(htt);
|
ath10k_htt_tx_dec_pending(htt);
|
||||||
if (htt->num_pending_tx == 0)
|
|
||||||
wake_up(&htt->empty_tx_wq);
|
|
||||||
spin_unlock_bh(&htt->tx_lock);
|
spin_unlock_bh(&htt->tx_lock);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
@ -2611,9 +2611,30 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||||||
ath10k_mac_handle_beacon(ar, skb);
|
ath10k_mac_handle_beacon(ar, skb);
|
||||||
|
|
||||||
if (ieee80211_is_beacon(hdr->frame_control) ||
|
if (ieee80211_is_beacon(hdr->frame_control) ||
|
||||||
ieee80211_is_probe_resp(hdr->frame_control))
|
ieee80211_is_probe_resp(hdr->frame_control)) {
|
||||||
|
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||||
|
u8 *ies;
|
||||||
|
int ies_ch;
|
||||||
|
|
||||||
status->boottime_ns = ktime_get_boottime_ns();
|
status->boottime_ns = ktime_get_boottime_ns();
|
||||||
|
|
||||||
|
if (!ar->scan_channel)
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
ies = mgmt->u.beacon.variable;
|
||||||
|
|
||||||
|
ies_ch = cfg80211_get_ies_channel_number(mgmt->u.beacon.variable,
|
||||||
|
skb_tail_pointer(skb) - ies,
|
||||||
|
sband->band);
|
||||||
|
|
||||||
|
if (ies_ch > 0 && ies_ch != channel) {
|
||||||
|
ath10k_dbg(ar, ATH10K_DBG_MGMT,
|
||||||
|
"channel mismatched ds channel %d scan channel %d\n",
|
||||||
|
ies_ch, channel);
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ath10k_dbg(ar, ATH10K_DBG_MGMT,
|
ath10k_dbg(ar, ATH10K_DBG_MGMT,
|
||||||
"event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
|
"event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
|
||||||
skb, skb->len,
|
skb, skb->len,
|
||||||
@ -2627,6 +2648,10 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||||||
ieee80211_rx_ni(ar->hw, skb);
|
ieee80211_rx_ni(ar->hw, skb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int freq_to_idx(struct ath10k *ar, int freq)
|
static int freq_to_idx(struct ath10k *ar, int freq)
|
||||||
|
@ -3478,7 +3478,9 @@ struct wmi_phyerr_event {
|
|||||||
__le32 num_phyerrs;
|
__le32 num_phyerrs;
|
||||||
__le32 tsf_l32;
|
__le32 tsf_l32;
|
||||||
__le32 tsf_u32;
|
__le32 tsf_u32;
|
||||||
struct wmi_phyerr phyerrs[];
|
|
||||||
|
/* array of struct wmi_phyerr */
|
||||||
|
u8 phyerrs[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct wmi_10_4_phyerr_event {
|
struct wmi_10_4_phyerr_event {
|
||||||
|
@ -206,13 +206,13 @@ static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
|
|||||||
|
|
||||||
static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
|
static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
|
||||||
{
|
{
|
||||||
const struct ce_pipe_config *ce_config;
|
const struct ce_attr *ce_attr;
|
||||||
|
|
||||||
ce_config = &ab->hw_params.target_ce_config[ce_id];
|
ce_attr = &ab->hw_params.host_ce_config[ce_id];
|
||||||
if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
|
if (ce_attr->src_nentries)
|
||||||
ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
|
ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
|
||||||
|
|
||||||
if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
|
if (ce_attr->dest_nentries) {
|
||||||
ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
|
ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
|
||||||
ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
|
ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
|
||||||
CE_HOST_IE_3_ADDRESS);
|
CE_HOST_IE_3_ADDRESS);
|
||||||
@ -221,13 +221,13 @@ static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
|
|||||||
|
|
||||||
static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
|
static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
|
||||||
{
|
{
|
||||||
const struct ce_pipe_config *ce_config;
|
const struct ce_attr *ce_attr;
|
||||||
|
|
||||||
ce_config = &ab->hw_params.target_ce_config[ce_id];
|
ce_attr = &ab->hw_params.host_ce_config[ce_id];
|
||||||
if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
|
if (ce_attr->src_nentries)
|
||||||
ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
|
ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
|
||||||
|
|
||||||
if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
|
if (ce_attr->dest_nentries) {
|
||||||
ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
|
ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
|
||||||
ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
|
ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
|
||||||
CE_HOST_IE_3_ADDRESS);
|
CE_HOST_IE_3_ADDRESS);
|
||||||
|
@ -74,10 +74,14 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||||||
BIT(NL80211_IFTYPE_AP) |
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT),
|
BIT(NL80211_IFTYPE_MESH_POINT),
|
||||||
.supports_monitor = true,
|
.supports_monitor = true,
|
||||||
|
.full_monitor_mode = false,
|
||||||
.supports_shadow_regs = false,
|
.supports_shadow_regs = false,
|
||||||
.idle_ps = false,
|
.idle_ps = false,
|
||||||
.supports_sta_ps = false,
|
.supports_sta_ps = false,
|
||||||
.cold_boot_calib = true,
|
.cold_boot_calib = true,
|
||||||
|
.fw_mem_mode = 0,
|
||||||
|
.num_vdevs = 16 + 1,
|
||||||
|
.num_peers = 512,
|
||||||
.supports_suspend = false,
|
.supports_suspend = false,
|
||||||
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
||||||
.fix_l1ss = true,
|
.fix_l1ss = true,
|
||||||
@ -128,10 +132,14 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||||||
BIT(NL80211_IFTYPE_AP) |
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT),
|
BIT(NL80211_IFTYPE_MESH_POINT),
|
||||||
.supports_monitor = true,
|
.supports_monitor = true,
|
||||||
|
.full_monitor_mode = false,
|
||||||
.supports_shadow_regs = false,
|
.supports_shadow_regs = false,
|
||||||
.idle_ps = false,
|
.idle_ps = false,
|
||||||
.supports_sta_ps = false,
|
.supports_sta_ps = false,
|
||||||
.cold_boot_calib = true,
|
.cold_boot_calib = true,
|
||||||
|
.fw_mem_mode = 0,
|
||||||
|
.num_vdevs = 16 + 1,
|
||||||
|
.num_peers = 512,
|
||||||
.supports_suspend = false,
|
.supports_suspend = false,
|
||||||
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
||||||
.fix_l1ss = true,
|
.fix_l1ss = true,
|
||||||
@ -181,10 +189,14 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||||||
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||||
BIT(NL80211_IFTYPE_AP),
|
BIT(NL80211_IFTYPE_AP),
|
||||||
.supports_monitor = false,
|
.supports_monitor = false,
|
||||||
|
.full_monitor_mode = false,
|
||||||
.supports_shadow_regs = true,
|
.supports_shadow_regs = true,
|
||||||
.idle_ps = true,
|
.idle_ps = true,
|
||||||
.supports_sta_ps = true,
|
.supports_sta_ps = true,
|
||||||
.cold_boot_calib = false,
|
.cold_boot_calib = false,
|
||||||
|
.fw_mem_mode = 0,
|
||||||
|
.num_vdevs = 16 + 1,
|
||||||
|
.num_peers = 512,
|
||||||
.supports_suspend = true,
|
.supports_suspend = true,
|
||||||
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
|
||||||
.fix_l1ss = true,
|
.fix_l1ss = true,
|
||||||
@ -234,10 +246,14 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||||||
BIT(NL80211_IFTYPE_AP) |
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT),
|
BIT(NL80211_IFTYPE_MESH_POINT),
|
||||||
.supports_monitor = true,
|
.supports_monitor = true,
|
||||||
|
.full_monitor_mode = true,
|
||||||
.supports_shadow_regs = false,
|
.supports_shadow_regs = false,
|
||||||
.idle_ps = false,
|
.idle_ps = false,
|
||||||
.supports_sta_ps = false,
|
.supports_sta_ps = false,
|
||||||
.cold_boot_calib = false,
|
.cold_boot_calib = false,
|
||||||
|
.fw_mem_mode = 2,
|
||||||
|
.num_vdevs = 8,
|
||||||
|
.num_peers = 128,
|
||||||
.supports_suspend = false,
|
.supports_suspend = false,
|
||||||
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
|
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
|
||||||
.fix_l1ss = true,
|
.fix_l1ss = true,
|
||||||
@ -287,10 +303,70 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
|
|||||||
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||||
BIT(NL80211_IFTYPE_AP),
|
BIT(NL80211_IFTYPE_AP),
|
||||||
.supports_monitor = false,
|
.supports_monitor = false,
|
||||||
|
.full_monitor_mode = false,
|
||||||
.supports_shadow_regs = true,
|
.supports_shadow_regs = true,
|
||||||
.idle_ps = true,
|
.idle_ps = true,
|
||||||
.supports_sta_ps = true,
|
.supports_sta_ps = true,
|
||||||
.cold_boot_calib = false,
|
.cold_boot_calib = false,
|
||||||
|
.fw_mem_mode = 0,
|
||||||
|
.num_vdevs = 16 + 1,
|
||||||
|
.num_peers = 512,
|
||||||
|
.supports_suspend = true,
|
||||||
|
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
|
||||||
|
.fix_l1ss = false,
|
||||||
|
.credit_flow = true,
|
||||||
|
.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,
|
||||||
|
.hal_params = &ath11k_hw_hal_params_qca6390,
|
||||||
|
.supports_dynamic_smps_6ghz = false,
|
||||||
|
.alloc_cacheable_memory = false,
|
||||||
|
.wakeup_mhi = true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "wcn6855 hw2.1",
|
||||||
|
.hw_rev = ATH11K_HW_WCN6855_HW21,
|
||||||
|
.fw = {
|
||||||
|
.dir = "WCN6855/hw2.1",
|
||||||
|
.board_size = 256 * 1024,
|
||||||
|
.cal_offset = 128 * 1024,
|
||||||
|
},
|
||||||
|
.max_radios = 3,
|
||||||
|
.bdf_addr = 0x4B0C0000,
|
||||||
|
.hw_ops = &wcn6855_ops,
|
||||||
|
.ring_mask = &ath11k_hw_ring_mask_qca6390,
|
||||||
|
.internal_sleep_clock = true,
|
||||||
|
.regs = &wcn6855_regs,
|
||||||
|
.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,
|
||||||
|
.host_ce_config = ath11k_host_ce_config_qca6390,
|
||||||
|
.ce_count = 9,
|
||||||
|
.target_ce_config = ath11k_target_ce_config_wlan_qca6390,
|
||||||
|
.target_ce_count = 9,
|
||||||
|
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
|
||||||
|
.svc_to_ce_map_len = 14,
|
||||||
|
.single_pdev_only = true,
|
||||||
|
.rxdma1_enable = false,
|
||||||
|
.num_rxmda_per_pdev = 2,
|
||||||
|
.rx_mac_buf_ring = true,
|
||||||
|
.vdev_start_delay = true,
|
||||||
|
.htt_peer_map_v2 = false,
|
||||||
|
|
||||||
|
.spectral = {
|
||||||
|
.fft_sz = 0,
|
||||||
|
.fft_pad_sz = 0,
|
||||||
|
.summary_pad_sz = 0,
|
||||||
|
.fft_hdr_len = 0,
|
||||||
|
.max_fft_bins = 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||||
|
BIT(NL80211_IFTYPE_AP),
|
||||||
|
.supports_monitor = false,
|
||||||
|
.supports_shadow_regs = true,
|
||||||
|
.idle_ps = true,
|
||||||
|
.supports_sta_ps = true,
|
||||||
|
.cold_boot_calib = false,
|
||||||
|
.fw_mem_mode = 0,
|
||||||
|
.num_vdevs = 16 + 1,
|
||||||
|
.num_peers = 512,
|
||||||
.supports_suspend = true,
|
.supports_suspend = true,
|
||||||
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
|
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
|
||||||
.fix_l1ss = false,
|
.fix_l1ss = false,
|
||||||
@ -1009,7 +1085,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
|
|||||||
ath11k_dp_free(ab);
|
ath11k_dp_free(ab);
|
||||||
ath11k_hal_srng_deinit(ab);
|
ath11k_hal_srng_deinit(ab);
|
||||||
|
|
||||||
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
|
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;
|
||||||
|
|
||||||
ret = ath11k_hal_srng_init(ab);
|
ret = ath11k_hal_srng_init(ab);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1043,6 +1119,7 @@ void ath11k_core_halt(struct ath11k *ar)
|
|||||||
ath11k_mac_peer_cleanup_all(ar);
|
ath11k_mac_peer_cleanup_all(ar);
|
||||||
cancel_delayed_work_sync(&ar->scan.timeout);
|
cancel_delayed_work_sync(&ar->scan.timeout);
|
||||||
cancel_work_sync(&ar->regd_update_work);
|
cancel_work_sync(&ar->regd_update_work);
|
||||||
|
cancel_work_sync(&ab->update_11d_work);
|
||||||
|
|
||||||
rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
|
rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
@ -1050,6 +1127,34 @@ void ath11k_core_halt(struct ath11k *ar)
|
|||||||
idr_init(&ar->txmgmt_idr);
|
idr_init(&ar->txmgmt_idr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ath11k_update_11d(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work);
|
||||||
|
struct ath11k *ar;
|
||||||
|
struct ath11k_pdev *pdev;
|
||||||
|
struct wmi_set_current_country_params set_current_param = {};
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
spin_lock_bh(&ab->base_lock);
|
||||||
|
memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2);
|
||||||
|
spin_unlock_bh(&ab->base_lock);
|
||||||
|
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n",
|
||||||
|
set_current_param.alpha2[0],
|
||||||
|
set_current_param.alpha2[1]);
|
||||||
|
|
||||||
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
pdev = &ab->pdevs[i];
|
||||||
|
ar = pdev->ar;
|
||||||
|
|
||||||
|
ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param);
|
||||||
|
if (ret)
|
||||||
|
ath11k_warn(ar->ab,
|
||||||
|
"pdev id %d failed set current country code: %d\n",
|
||||||
|
i, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ath11k_core_restart(struct work_struct *work)
|
static void ath11k_core_restart(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work);
|
struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work);
|
||||||
@ -1083,6 +1188,7 @@ static void ath11k_core_restart(struct work_struct *work)
|
|||||||
idr_for_each(&ar->txmgmt_idr,
|
idr_for_each(&ar->txmgmt_idr,
|
||||||
ath11k_mac_tx_mgmt_pending_free, ar);
|
ath11k_mac_tx_mgmt_pending_free, ar);
|
||||||
idr_destroy(&ar->txmgmt_idr);
|
idr_destroy(&ar->txmgmt_idr);
|
||||||
|
wake_up(&ar->txmgmt_empty_waitq);
|
||||||
}
|
}
|
||||||
|
|
||||||
wake_up(&ab->wmi_ab.tx_credits_wq);
|
wake_up(&ab->wmi_ab.tx_credits_wq);
|
||||||
@ -1219,12 +1325,14 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
|
|||||||
|
|
||||||
mutex_init(&ab->core_lock);
|
mutex_init(&ab->core_lock);
|
||||||
spin_lock_init(&ab->base_lock);
|
spin_lock_init(&ab->base_lock);
|
||||||
|
mutex_init(&ab->vdev_id_11d_lock);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ab->peers);
|
INIT_LIST_HEAD(&ab->peers);
|
||||||
init_waitqueue_head(&ab->peer_mapping_wq);
|
init_waitqueue_head(&ab->peer_mapping_wq);
|
||||||
init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
|
init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
|
||||||
init_waitqueue_head(&ab->qmi.cold_boot_waitq);
|
init_waitqueue_head(&ab->qmi.cold_boot_waitq);
|
||||||
INIT_WORK(&ab->restart_work, ath11k_core_restart);
|
INIT_WORK(&ab->restart_work, ath11k_core_restart);
|
||||||
|
INIT_WORK(&ab->update_11d_work, ath11k_update_11d);
|
||||||
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
|
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
|
||||||
init_completion(&ab->htc_suspend);
|
init_completion(&ab->htc_suspend);
|
||||||
init_completion(&ab->wow.wakeup_completed);
|
init_completion(&ab->wow.wakeup_completed);
|
||||||
|
@ -117,6 +117,7 @@ enum ath11k_hw_rev {
|
|||||||
ATH11K_HW_IPQ6018_HW10,
|
ATH11K_HW_IPQ6018_HW10,
|
||||||
ATH11K_HW_QCN9074_HW10,
|
ATH11K_HW_QCN9074_HW10,
|
||||||
ATH11K_HW_WCN6855_HW20,
|
ATH11K_HW_WCN6855_HW20,
|
||||||
|
ATH11K_HW_WCN6855_HW21,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ath11k_firmware_mode {
|
enum ath11k_firmware_mode {
|
||||||
@ -199,6 +200,9 @@ enum ath11k_dev_flags {
|
|||||||
ATH11K_FLAG_REGISTERED,
|
ATH11K_FLAG_REGISTERED,
|
||||||
ATH11K_FLAG_QMI_FAIL,
|
ATH11K_FLAG_QMI_FAIL,
|
||||||
ATH11K_FLAG_HTC_SUSPEND_COMPLETE,
|
ATH11K_FLAG_HTC_SUSPEND_COMPLETE,
|
||||||
|
ATH11K_FLAG_CE_IRQ_ENABLED,
|
||||||
|
ATH11K_FLAG_EXT_IRQ_ENABLED,
|
||||||
|
ATH11K_FLAG_FIXED_MEM_RGN,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ath11k_monitor_flags {
|
enum ath11k_monitor_flags {
|
||||||
@ -547,6 +551,7 @@ struct ath11k {
|
|||||||
/* protects txmgmt_idr data */
|
/* protects txmgmt_idr data */
|
||||||
spinlock_t txmgmt_idr_lock;
|
spinlock_t txmgmt_idr_lock;
|
||||||
atomic_t num_pending_mgmt_tx;
|
atomic_t num_pending_mgmt_tx;
|
||||||
|
wait_queue_head_t txmgmt_empty_waitq;
|
||||||
|
|
||||||
/* cycle count is reported twice for each visited channel during scan.
|
/* cycle count is reported twice for each visited channel during scan.
|
||||||
* access protected by data_lock
|
* access protected by data_lock
|
||||||
@ -585,6 +590,11 @@ struct ath11k {
|
|||||||
#endif
|
#endif
|
||||||
bool dfs_block_radar_events;
|
bool dfs_block_radar_events;
|
||||||
struct ath11k_thermal thermal;
|
struct ath11k_thermal thermal;
|
||||||
|
u32 vdev_id_11d_scan;
|
||||||
|
struct completion finish_11d_scan;
|
||||||
|
struct completion finish_11d_ch_list;
|
||||||
|
bool pending_11d;
|
||||||
|
bool regdom_set_by_user;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath11k_band_cap {
|
struct ath11k_band_cap {
|
||||||
@ -711,6 +721,11 @@ struct ath11k_base {
|
|||||||
/* Protects data like peers */
|
/* Protects data like peers */
|
||||||
spinlock_t base_lock;
|
spinlock_t base_lock;
|
||||||
struct ath11k_pdev pdevs[MAX_RADIOS];
|
struct ath11k_pdev pdevs[MAX_RADIOS];
|
||||||
|
struct {
|
||||||
|
enum WMI_HOST_WLAN_BAND supported_bands;
|
||||||
|
u32 pdev_id;
|
||||||
|
} target_pdev_ids[MAX_RADIOS];
|
||||||
|
u8 target_pdev_count;
|
||||||
struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS];
|
struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS];
|
||||||
struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS];
|
struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS];
|
||||||
unsigned long long free_vdev_map;
|
unsigned long long free_vdev_map;
|
||||||
@ -754,6 +769,8 @@ struct ath11k_base {
|
|||||||
struct completion driver_recovery;
|
struct completion driver_recovery;
|
||||||
struct workqueue_struct *workqueue;
|
struct workqueue_struct *workqueue;
|
||||||
struct work_struct restart_work;
|
struct work_struct restart_work;
|
||||||
|
struct work_struct update_11d_work;
|
||||||
|
u8 new_alpha2[3];
|
||||||
struct {
|
struct {
|
||||||
/* protected by data_lock */
|
/* protected by data_lock */
|
||||||
u32 fw_crash_counter;
|
u32 fw_crash_counter;
|
||||||
@ -763,6 +780,8 @@ struct ath11k_base {
|
|||||||
struct ath11k_dbring_cap *db_caps;
|
struct ath11k_dbring_cap *db_caps;
|
||||||
u32 num_db_cap;
|
u32 num_db_cap;
|
||||||
|
|
||||||
|
/* To synchronize 11d scan vdev id */
|
||||||
|
struct mutex vdev_id_11d_lock;
|
||||||
struct timer_list mon_reap_timer;
|
struct timer_list mon_reap_timer;
|
||||||
|
|
||||||
struct completion htc_suspend;
|
struct completion htc_suspend;
|
||||||
|
@ -6,6 +6,35 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define ATH11K_DB_MAGIC_VALUE 0xdeadbeaf
|
||||||
|
|
||||||
|
int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size)
|
||||||
|
{
|
||||||
|
u32 *temp;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
size = size >> 2;
|
||||||
|
|
||||||
|
for (idx = 0, temp = buffer; idx < size; idx++, temp++) {
|
||||||
|
if (*temp == ATH11K_DB_MAGIC_VALUE)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath11k_dbring_fill_magic_value(struct ath11k *ar,
|
||||||
|
void *buffer, u32 size)
|
||||||
|
{
|
||||||
|
u32 *temp;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
size = size >> 2;
|
||||||
|
|
||||||
|
for (idx = 0, temp = buffer; idx < size; idx++, temp++)
|
||||||
|
*temp++ = ATH11K_DB_MAGIC_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
static int ath11k_dbring_bufs_replenish(struct ath11k *ar,
|
static int ath11k_dbring_bufs_replenish(struct ath11k *ar,
|
||||||
struct ath11k_dbring *ring,
|
struct ath11k_dbring *ring,
|
||||||
struct ath11k_dbring_element *buff)
|
struct ath11k_dbring_element *buff)
|
||||||
@ -26,6 +55,7 @@ static int ath11k_dbring_bufs_replenish(struct ath11k *ar,
|
|||||||
|
|
||||||
ptr_unaligned = buff->payload;
|
ptr_unaligned = buff->payload;
|
||||||
ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align);
|
ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align);
|
||||||
|
ath11k_dbring_fill_magic_value(ar, ptr_aligned, ring->buf_sz);
|
||||||
paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz,
|
paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
@ -76,4 +76,6 @@ int ath11k_dbring_get_cap(struct ath11k_base *ab,
|
|||||||
struct ath11k_dbring_cap *db_cap);
|
struct ath11k_dbring_cap *db_cap);
|
||||||
void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring);
|
void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring);
|
||||||
void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring);
|
void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring);
|
||||||
|
int ath11k_dbring_validate_buffer(struct ath11k *ar, void *data, u32 size);
|
||||||
|
|
||||||
#endif /* ATH11K_DBRING_H */
|
#endif /* ATH11K_DBRING_H */
|
||||||
|
@ -1051,6 +1051,7 @@ int ath11k_dp_alloc(struct ath11k_base *ab)
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&dp->reo_cmd_list);
|
INIT_LIST_HEAD(&dp->reo_cmd_list);
|
||||||
INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list);
|
INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list);
|
||||||
|
INIT_LIST_HEAD(&dp->dp_full_mon_mpdu_list);
|
||||||
spin_lock_init(&dp->reo_cmd_lock);
|
spin_lock_init(&dp->reo_cmd_lock);
|
||||||
|
|
||||||
dp->reo_cmd_cache_flush_count = 0;
|
dp->reo_cmd_cache_flush_count = 0;
|
||||||
|
@ -89,6 +89,19 @@ struct dp_tx_ring {
|
|||||||
int tx_status_tail;
|
int tx_status_tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dp_mon_status_buf_state {
|
||||||
|
/* PPDU id matches in dst ring and status ring */
|
||||||
|
DP_MON_STATUS_MATCH,
|
||||||
|
/* status ring dma is not done */
|
||||||
|
DP_MON_STATUS_NO_DMA,
|
||||||
|
/* status ring is lagging, reap status ring */
|
||||||
|
DP_MON_STATUS_LAG,
|
||||||
|
/* status ring is leading, reap dst ring and drop */
|
||||||
|
DP_MON_STATUS_LEAD,
|
||||||
|
/* replinish monitor status ring */
|
||||||
|
DP_MON_STATUS_REPLINISH,
|
||||||
|
};
|
||||||
|
|
||||||
struct ath11k_pdev_mon_stats {
|
struct ath11k_pdev_mon_stats {
|
||||||
u32 status_ppdu_state;
|
u32 status_ppdu_state;
|
||||||
u32 status_ppdu_start;
|
u32 status_ppdu_start;
|
||||||
@ -104,6 +117,12 @@ struct ath11k_pdev_mon_stats {
|
|||||||
u32 dup_mon_buf_cnt;
|
u32 dup_mon_buf_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dp_full_mon_mpdu {
|
||||||
|
struct list_head list;
|
||||||
|
struct sk_buff *head;
|
||||||
|
struct sk_buff *tail;
|
||||||
|
};
|
||||||
|
|
||||||
struct dp_link_desc_bank {
|
struct dp_link_desc_bank {
|
||||||
void *vaddr_unaligned;
|
void *vaddr_unaligned;
|
||||||
void *vaddr;
|
void *vaddr;
|
||||||
@ -135,7 +154,11 @@ struct ath11k_mon_data {
|
|||||||
u32 mon_last_buf_cookie;
|
u32 mon_last_buf_cookie;
|
||||||
u64 mon_last_linkdesc_paddr;
|
u64 mon_last_linkdesc_paddr;
|
||||||
u16 chan_noise_floor;
|
u16 chan_noise_floor;
|
||||||
|
bool hold_mon_dst_ring;
|
||||||
|
enum dp_mon_status_buf_state buf_state;
|
||||||
|
dma_addr_t mon_status_paddr;
|
||||||
|
struct dp_full_mon_mpdu *mon_mpdu;
|
||||||
|
struct hal_sw_mon_ring_entries sw_mon_entries;
|
||||||
struct ath11k_pdev_mon_stats rx_mon_stats;
|
struct ath11k_pdev_mon_stats rx_mon_stats;
|
||||||
/* lock for monitor data */
|
/* lock for monitor data */
|
||||||
spinlock_t mon_lock;
|
spinlock_t mon_lock;
|
||||||
@ -245,6 +268,7 @@ struct ath11k_dp {
|
|||||||
struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
|
struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
|
||||||
struct list_head reo_cmd_list;
|
struct list_head reo_cmd_list;
|
||||||
struct list_head reo_cmd_cache_flush_list;
|
struct list_head reo_cmd_cache_flush_list;
|
||||||
|
struct list_head dp_full_mon_mpdu_list;
|
||||||
u32 reo_cmd_cache_flush_count;
|
u32 reo_cmd_cache_flush_count;
|
||||||
/**
|
/**
|
||||||
* protects access to below fields,
|
* protects access to below fields,
|
||||||
@ -292,6 +316,7 @@ enum htt_h2t_msg_type {
|
|||||||
HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc,
|
HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc,
|
||||||
HTT_H2T_MSG_TYPE_EXT_STATS_CFG = 0x10,
|
HTT_H2T_MSG_TYPE_EXT_STATS_CFG = 0x10,
|
||||||
HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11,
|
HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11,
|
||||||
|
HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE = 0x17,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0)
|
#define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0)
|
||||||
@ -957,6 +982,33 @@ struct htt_rx_ring_tlv_filter {
|
|||||||
u32 pkt_filter_flags3; /* DATA */
|
u32 pkt_filter_flags3; /* DATA */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE GENMASK(7, 0)
|
||||||
|
#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID GENMASK(15, 8)
|
||||||
|
|
||||||
|
#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE BIT(0)
|
||||||
|
#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END BIT(1)
|
||||||
|
#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END BIT(2)
|
||||||
|
#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING GENMASK(10, 3)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration for full monitor mode destination ring select
|
||||||
|
* 0 - REO destination ring select
|
||||||
|
* 1 - FW destination ring select
|
||||||
|
* 2 - SW destination ring select
|
||||||
|
* 3 - Release destination ring select
|
||||||
|
*/
|
||||||
|
enum htt_rx_full_mon_release_ring {
|
||||||
|
HTT_RX_MON_RING_REO,
|
||||||
|
HTT_RX_MON_RING_FW,
|
||||||
|
HTT_RX_MON_RING_SW,
|
||||||
|
HTT_RX_MON_RING_RELEASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct htt_rx_full_monitor_mode_cfg_cmd {
|
||||||
|
u32 info0;
|
||||||
|
u32 cfg;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* HTT message target->host */
|
/* HTT message target->host */
|
||||||
|
|
||||||
enum htt_t2h_msg_type {
|
enum htt_t2h_msg_type {
|
||||||
|
@ -2942,6 +2942,43 @@ fail_desc_get:
|
|||||||
return req_entries - num_remain;
|
return req_entries - num_remain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP 32535
|
||||||
|
|
||||||
|
static void
|
||||||
|
ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon,
|
||||||
|
struct hal_tlv_hdr *tlv)
|
||||||
|
{
|
||||||
|
struct hal_rx_ppdu_start *ppdu_start;
|
||||||
|
u16 ppdu_id_diff, ppdu_id, tlv_len;
|
||||||
|
u8 *ptr;
|
||||||
|
|
||||||
|
/* PPDU id is part of second tlv, move ptr to second tlv */
|
||||||
|
tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl);
|
||||||
|
ptr = (u8 *)tlv;
|
||||||
|
ptr += sizeof(*tlv) + tlv_len;
|
||||||
|
tlv = (struct hal_tlv_hdr *)ptr;
|
||||||
|
|
||||||
|
if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_PPDU_START)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ptr += sizeof(*tlv);
|
||||||
|
ppdu_start = (struct hal_rx_ppdu_start *)ptr;
|
||||||
|
ppdu_id = FIELD_GET(HAL_RX_PPDU_START_INFO0_PPDU_ID,
|
||||||
|
__le32_to_cpu(ppdu_start->info0));
|
||||||
|
|
||||||
|
if (pmon->sw_mon_entries.ppdu_id < ppdu_id) {
|
||||||
|
pmon->buf_state = DP_MON_STATUS_LEAD;
|
||||||
|
ppdu_id_diff = ppdu_id - pmon->sw_mon_entries.ppdu_id;
|
||||||
|
if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP)
|
||||||
|
pmon->buf_state = DP_MON_STATUS_LAG;
|
||||||
|
} else if (pmon->sw_mon_entries.ppdu_id > ppdu_id) {
|
||||||
|
pmon->buf_state = DP_MON_STATUS_LAG;
|
||||||
|
ppdu_id_diff = pmon->sw_mon_entries.ppdu_id - ppdu_id;
|
||||||
|
if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP)
|
||||||
|
pmon->buf_state = DP_MON_STATUS_LEAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
||||||
int *budget, struct sk_buff_head *skb_list)
|
int *budget, struct sk_buff_head *skb_list)
|
||||||
{
|
{
|
||||||
@ -2949,6 +2986,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
|||||||
const struct ath11k_hw_hal_params *hal_params;
|
const struct ath11k_hw_hal_params *hal_params;
|
||||||
struct ath11k_pdev_dp *dp;
|
struct ath11k_pdev_dp *dp;
|
||||||
struct dp_rxdma_ring *rx_ring;
|
struct dp_rxdma_ring *rx_ring;
|
||||||
|
struct ath11k_mon_data *pmon;
|
||||||
struct hal_srng *srng;
|
struct hal_srng *srng;
|
||||||
void *rx_mon_status_desc;
|
void *rx_mon_status_desc;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
@ -2962,6 +3000,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
|||||||
|
|
||||||
ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar;
|
ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar;
|
||||||
dp = &ar->dp;
|
dp = &ar->dp;
|
||||||
|
pmon = &dp->mon_data;
|
||||||
srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id);
|
srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id);
|
||||||
rx_ring = &dp->rx_mon_status_refill_ring[srng_id];
|
rx_ring = &dp->rx_mon_status_refill_ring[srng_id];
|
||||||
|
|
||||||
@ -2974,8 +3013,10 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
|||||||
*budget -= 1;
|
*budget -= 1;
|
||||||
rx_mon_status_desc =
|
rx_mon_status_desc =
|
||||||
ath11k_hal_srng_src_peek(ab, srng);
|
ath11k_hal_srng_src_peek(ab, srng);
|
||||||
if (!rx_mon_status_desc)
|
if (!rx_mon_status_desc) {
|
||||||
|
pmon->buf_state = DP_MON_STATUS_REPLINISH;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr,
|
ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr,
|
||||||
&cookie, &rbm);
|
&cookie, &rbm);
|
||||||
@ -2988,6 +3029,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
|||||||
ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n",
|
ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n",
|
||||||
buf_id);
|
buf_id);
|
||||||
spin_unlock_bh(&rx_ring->idr_lock);
|
spin_unlock_bh(&rx_ring->idr_lock);
|
||||||
|
pmon->buf_state = DP_MON_STATUS_REPLINISH;
|
||||||
goto move_next;
|
goto move_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3007,10 +3049,18 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
|||||||
FIELD_GET(HAL_TLV_HDR_TAG,
|
FIELD_GET(HAL_TLV_HDR_TAG,
|
||||||
tlv->tl));
|
tlv->tl));
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
|
pmon->buf_state = DP_MON_STATUS_NO_DMA;
|
||||||
goto move_next;
|
goto move_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ab->hw_params.full_monitor_mode) {
|
||||||
|
ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv);
|
||||||
|
if (paddr == pmon->mon_status_paddr)
|
||||||
|
pmon->buf_state = DP_MON_STATUS_MATCH;
|
||||||
|
}
|
||||||
__skb_queue_tail(skb_list, skb);
|
__skb_queue_tail(skb_list, skb);
|
||||||
|
} else {
|
||||||
|
pmon->buf_state = DP_MON_STATUS_REPLINISH;
|
||||||
}
|
}
|
||||||
move_next:
|
move_next:
|
||||||
skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
|
skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
|
||||||
@ -3061,10 +3111,10 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
|
|||||||
if (!num_buffs_reaped)
|
if (!num_buffs_reaped)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
while ((skb = __skb_dequeue(&skb_list))) {
|
memset(&ppdu_info, 0, sizeof(ppdu_info));
|
||||||
memset(&ppdu_info, 0, sizeof(ppdu_info));
|
ppdu_info.peer_id = HAL_INVALID_PEERID;
|
||||||
ppdu_info.peer_id = HAL_INVALID_PEERID;
|
|
||||||
|
|
||||||
|
while ((skb = __skb_dequeue(&skb_list))) {
|
||||||
if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) {
|
if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) {
|
||||||
log_type = ATH11K_PKTLOG_TYPE_LITE_RX;
|
log_type = ATH11K_PKTLOG_TYPE_LITE_RX;
|
||||||
rx_buf_sz = DP_RX_BUFFER_SIZE_LITE;
|
rx_buf_sz = DP_RX_BUFFER_SIZE_LITE;
|
||||||
@ -3092,10 +3142,7 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
|
|||||||
ath11k_dbg(ab, ATH11K_DBG_DATA,
|
ath11k_dbg(ab, ATH11K_DBG_DATA,
|
||||||
"failed to find the peer with peer_id %d\n",
|
"failed to find the peer with peer_id %d\n",
|
||||||
ppdu_info.peer_id);
|
ppdu_info.peer_id);
|
||||||
spin_unlock_bh(&ab->base_lock);
|
goto next_skb;
|
||||||
rcu_read_unlock();
|
|
||||||
dev_kfree_skb_any(skb);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arsta = (struct ath11k_sta *)peer->sta->drv_priv;
|
arsta = (struct ath11k_sta *)peer->sta->drv_priv;
|
||||||
@ -3104,10 +3151,13 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
|
|||||||
if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr))
|
if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr))
|
||||||
trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz);
|
trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz);
|
||||||
|
|
||||||
|
next_skb:
|
||||||
spin_unlock_bh(&ab->base_lock);
|
spin_unlock_bh(&ab->base_lock);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
|
memset(&ppdu_info, 0, sizeof(ppdu_info));
|
||||||
|
ppdu_info.peer_id = HAL_INVALID_PEERID;
|
||||||
}
|
}
|
||||||
exit:
|
exit:
|
||||||
return num_buffs_reaped;
|
return num_buffs_reaped;
|
||||||
@ -5098,6 +5148,357 @@ static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar,
|
||||||
|
void *ring_entry, struct sk_buff **head_msdu,
|
||||||
|
struct sk_buff **tail_msdu,
|
||||||
|
struct hal_sw_mon_ring_entries *sw_mon_entries)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_dp *dp = &ar->dp;
|
||||||
|
struct ath11k_mon_data *pmon = &dp->mon_data;
|
||||||
|
struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring;
|
||||||
|
struct sk_buff *msdu = NULL, *last = NULL;
|
||||||
|
struct hal_sw_monitor_ring *sw_desc = ring_entry;
|
||||||
|
struct hal_rx_msdu_list msdu_list;
|
||||||
|
struct hal_rx_desc *rx_desc;
|
||||||
|
struct ath11k_skb_rxcb *rxcb;
|
||||||
|
void *rx_msdu_link_desc;
|
||||||
|
void *p_buf_addr_info, *p_last_buf_addr_info;
|
||||||
|
int buf_id, i = 0;
|
||||||
|
u32 rx_buf_size, rx_pkt_offset, l2_hdr_offset;
|
||||||
|
u32 rx_bufs_used = 0, msdu_cnt = 0;
|
||||||
|
u32 total_len = 0, frag_len = 0, sw_cookie;
|
||||||
|
u16 num_msdus = 0;
|
||||||
|
u8 rxdma_err, rbm;
|
||||||
|
bool is_frag, is_first_msdu;
|
||||||
|
bool drop_mpdu = false;
|
||||||
|
|
||||||
|
ath11k_hal_rx_sw_mon_ring_buf_paddr_get(ring_entry, sw_mon_entries);
|
||||||
|
|
||||||
|
sw_cookie = sw_mon_entries->mon_dst_sw_cookie;
|
||||||
|
sw_mon_entries->end_of_ppdu = false;
|
||||||
|
sw_mon_entries->drop_ppdu = false;
|
||||||
|
p_last_buf_addr_info = sw_mon_entries->dst_buf_addr_info;
|
||||||
|
msdu_cnt = sw_mon_entries->msdu_cnt;
|
||||||
|
|
||||||
|
sw_mon_entries->end_of_ppdu =
|
||||||
|
FIELD_GET(HAL_SW_MON_RING_INFO0_END_OF_PPDU, sw_desc->info0);
|
||||||
|
if (sw_mon_entries->end_of_ppdu)
|
||||||
|
return rx_bufs_used;
|
||||||
|
|
||||||
|
if (FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON,
|
||||||
|
sw_desc->info0) ==
|
||||||
|
HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
|
||||||
|
rxdma_err =
|
||||||
|
FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE,
|
||||||
|
sw_desc->info0);
|
||||||
|
if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR ||
|
||||||
|
rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR ||
|
||||||
|
rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) {
|
||||||
|
pmon->rx_mon_stats.dest_mpdu_drop++;
|
||||||
|
drop_mpdu = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_frag = false;
|
||||||
|
is_first_msdu = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
rx_msdu_link_desc =
|
||||||
|
(u8 *)pmon->link_desc_banks[sw_cookie].vaddr +
|
||||||
|
(sw_mon_entries->mon_dst_paddr -
|
||||||
|
pmon->link_desc_banks[sw_cookie].paddr);
|
||||||
|
|
||||||
|
ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list,
|
||||||
|
&num_msdus);
|
||||||
|
|
||||||
|
for (i = 0; i < num_msdus; i++) {
|
||||||
|
buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
|
||||||
|
msdu_list.sw_cookie[i]);
|
||||||
|
|
||||||
|
spin_lock_bh(&rx_ring->idr_lock);
|
||||||
|
msdu = idr_find(&rx_ring->bufs_idr, buf_id);
|
||||||
|
if (!msdu) {
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
|
||||||
|
"full mon msdu_pop: invalid buf_id %d\n",
|
||||||
|
buf_id);
|
||||||
|
spin_unlock_bh(&rx_ring->idr_lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idr_remove(&rx_ring->bufs_idr, buf_id);
|
||||||
|
spin_unlock_bh(&rx_ring->idr_lock);
|
||||||
|
|
||||||
|
rxcb = ATH11K_SKB_RXCB(msdu);
|
||||||
|
if (!rxcb->unmapped) {
|
||||||
|
dma_unmap_single(ar->ab->dev, rxcb->paddr,
|
||||||
|
msdu->len +
|
||||||
|
skb_tailroom(msdu),
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
rxcb->unmapped = 1;
|
||||||
|
}
|
||||||
|
if (drop_mpdu) {
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
|
||||||
|
"full mon: i %d drop msdu %p *ppdu_id %x\n",
|
||||||
|
i, msdu, sw_mon_entries->ppdu_id);
|
||||||
|
dev_kfree_skb_any(msdu);
|
||||||
|
msdu_cnt--;
|
||||||
|
goto next_msdu;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_desc = (struct hal_rx_desc *)msdu->data;
|
||||||
|
|
||||||
|
rx_pkt_offset = sizeof(struct hal_rx_desc);
|
||||||
|
l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc);
|
||||||
|
|
||||||
|
if (is_first_msdu) {
|
||||||
|
if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) {
|
||||||
|
drop_mpdu = true;
|
||||||
|
dev_kfree_skb_any(msdu);
|
||||||
|
msdu = NULL;
|
||||||
|
goto next_msdu;
|
||||||
|
}
|
||||||
|
is_first_msdu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i],
|
||||||
|
&is_frag, &total_len,
|
||||||
|
&frag_len, &msdu_cnt);
|
||||||
|
|
||||||
|
rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len;
|
||||||
|
|
||||||
|
ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size);
|
||||||
|
|
||||||
|
if (!(*head_msdu))
|
||||||
|
*head_msdu = msdu;
|
||||||
|
else if (last)
|
||||||
|
last->next = msdu;
|
||||||
|
|
||||||
|
last = msdu;
|
||||||
|
next_msdu:
|
||||||
|
rx_bufs_used++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc,
|
||||||
|
&sw_mon_entries->mon_dst_paddr,
|
||||||
|
&sw_mon_entries->mon_dst_sw_cookie,
|
||||||
|
&rbm,
|
||||||
|
&p_buf_addr_info);
|
||||||
|
|
||||||
|
if (ath11k_dp_rx_monitor_link_desc_return(ar,
|
||||||
|
p_last_buf_addr_info,
|
||||||
|
dp->mac_id))
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
|
||||||
|
"full mon: dp_rx_monitor_link_desc_return failed\n");
|
||||||
|
|
||||||
|
p_last_buf_addr_info = p_buf_addr_info;
|
||||||
|
|
||||||
|
} while (sw_mon_entries->mon_dst_paddr && msdu_cnt);
|
||||||
|
|
||||||
|
if (last)
|
||||||
|
last->next = NULL;
|
||||||
|
|
||||||
|
*tail_msdu = msdu;
|
||||||
|
|
||||||
|
return rx_bufs_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath11k_dp_rx_full_mon_prepare_mpdu(struct ath11k_dp *dp,
|
||||||
|
struct dp_full_mon_mpdu *mon_mpdu,
|
||||||
|
struct sk_buff *head,
|
||||||
|
struct sk_buff *tail)
|
||||||
|
{
|
||||||
|
mon_mpdu = kzalloc(sizeof(*mon_mpdu), GFP_ATOMIC);
|
||||||
|
if (!mon_mpdu)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
list_add_tail(&mon_mpdu->list, &dp->dp_full_mon_mpdu_list);
|
||||||
|
mon_mpdu->head = head;
|
||||||
|
mon_mpdu->tail = tail;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath11k_dp_rx_full_mon_drop_ppdu(struct ath11k_dp *dp,
|
||||||
|
struct dp_full_mon_mpdu *mon_mpdu)
|
||||||
|
{
|
||||||
|
struct dp_full_mon_mpdu *tmp;
|
||||||
|
struct sk_buff *tmp_msdu, *skb_next;
|
||||||
|
|
||||||
|
if (list_empty(&dp->dp_full_mon_mpdu_list))
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) {
|
||||||
|
list_del(&mon_mpdu->list);
|
||||||
|
|
||||||
|
tmp_msdu = mon_mpdu->head;
|
||||||
|
while (tmp_msdu) {
|
||||||
|
skb_next = tmp_msdu->next;
|
||||||
|
dev_kfree_skb_any(tmp_msdu);
|
||||||
|
tmp_msdu = skb_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(mon_mpdu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath11k_dp_rx_full_mon_deliver_ppdu(struct ath11k *ar,
|
||||||
|
int mac_id,
|
||||||
|
struct ath11k_mon_data *pmon,
|
||||||
|
struct napi_struct *napi)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_mon_stats *rx_mon_stats;
|
||||||
|
struct dp_full_mon_mpdu *tmp;
|
||||||
|
struct dp_full_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
|
||||||
|
struct sk_buff *head_msdu, *tail_msdu;
|
||||||
|
struct ath11k_base *ab = ar->ab;
|
||||||
|
struct ath11k_dp *dp = &ab->dp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rx_mon_stats = &pmon->rx_mon_stats;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) {
|
||||||
|
list_del(&mon_mpdu->list);
|
||||||
|
head_msdu = mon_mpdu->head;
|
||||||
|
tail_msdu = mon_mpdu->tail;
|
||||||
|
if (head_msdu && tail_msdu) {
|
||||||
|
ret = ath11k_dp_rx_mon_deliver(ar, mac_id, head_msdu,
|
||||||
|
tail_msdu, napi);
|
||||||
|
rx_mon_stats->dest_mpdu_done++;
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_DATA, "full mon: deliver ppdu\n");
|
||||||
|
}
|
||||||
|
kfree(mon_mpdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ath11k_dp_rx_process_full_mon_status_ring(struct ath11k_base *ab, int mac_id,
|
||||||
|
struct napi_struct *napi, int budget)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = ab->pdevs[mac_id].ar;
|
||||||
|
struct ath11k_pdev_dp *dp = &ar->dp;
|
||||||
|
struct ath11k_mon_data *pmon = &dp->mon_data;
|
||||||
|
struct hal_sw_mon_ring_entries *sw_mon_entries;
|
||||||
|
int quota = 0, work = 0, count;
|
||||||
|
|
||||||
|
sw_mon_entries = &pmon->sw_mon_entries;
|
||||||
|
|
||||||
|
while (pmon->hold_mon_dst_ring) {
|
||||||
|
quota = ath11k_dp_rx_process_mon_status(ab, mac_id,
|
||||||
|
napi, 1);
|
||||||
|
if (pmon->buf_state == DP_MON_STATUS_MATCH) {
|
||||||
|
count = sw_mon_entries->status_buf_count;
|
||||||
|
if (count > 1) {
|
||||||
|
quota += ath11k_dp_rx_process_mon_status(ab, mac_id,
|
||||||
|
napi, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
ath11k_dp_rx_full_mon_deliver_ppdu(ar, dp->mac_id,
|
||||||
|
pmon, napi);
|
||||||
|
pmon->hold_mon_dst_ring = false;
|
||||||
|
} else if (!pmon->mon_status_paddr ||
|
||||||
|
pmon->buf_state == DP_MON_STATUS_LEAD) {
|
||||||
|
sw_mon_entries->drop_ppdu = true;
|
||||||
|
pmon->hold_mon_dst_ring = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quota)
|
||||||
|
break;
|
||||||
|
|
||||||
|
work += quota;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sw_mon_entries->drop_ppdu)
|
||||||
|
ath11k_dp_rx_full_mon_drop_ppdu(&ab->dp, pmon->mon_mpdu);
|
||||||
|
|
||||||
|
return work;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id,
|
||||||
|
struct napi_struct *napi, int budget)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = ab->pdevs[mac_id].ar;
|
||||||
|
struct ath11k_pdev_dp *dp = &ar->dp;
|
||||||
|
struct ath11k_mon_data *pmon = &dp->mon_data;
|
||||||
|
struct hal_sw_mon_ring_entries *sw_mon_entries;
|
||||||
|
struct ath11k_pdev_mon_stats *rx_mon_stats;
|
||||||
|
struct sk_buff *head_msdu, *tail_msdu;
|
||||||
|
void *mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id];
|
||||||
|
void *ring_entry;
|
||||||
|
u32 rx_bufs_used = 0, mpdu_rx_bufs_used;
|
||||||
|
int quota = 0, ret;
|
||||||
|
bool break_dst_ring = false;
|
||||||
|
|
||||||
|
spin_lock_bh(&pmon->mon_lock);
|
||||||
|
|
||||||
|
sw_mon_entries = &pmon->sw_mon_entries;
|
||||||
|
rx_mon_stats = &pmon->rx_mon_stats;
|
||||||
|
|
||||||
|
if (pmon->hold_mon_dst_ring) {
|
||||||
|
spin_unlock_bh(&pmon->mon_lock);
|
||||||
|
goto reap_status_ring;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng);
|
||||||
|
while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) {
|
||||||
|
head_msdu = NULL;
|
||||||
|
tail_msdu = NULL;
|
||||||
|
|
||||||
|
mpdu_rx_bufs_used = ath11k_dp_rx_full_mon_mpdu_pop(ar, ring_entry,
|
||||||
|
&head_msdu,
|
||||||
|
&tail_msdu,
|
||||||
|
sw_mon_entries);
|
||||||
|
rx_bufs_used += mpdu_rx_bufs_used;
|
||||||
|
|
||||||
|
if (!sw_mon_entries->end_of_ppdu) {
|
||||||
|
if (head_msdu) {
|
||||||
|
ret = ath11k_dp_rx_full_mon_prepare_mpdu(&ab->dp,
|
||||||
|
pmon->mon_mpdu,
|
||||||
|
head_msdu,
|
||||||
|
tail_msdu);
|
||||||
|
if (ret)
|
||||||
|
break_dst_ring = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto next_entry;
|
||||||
|
} else {
|
||||||
|
if (!sw_mon_entries->ppdu_id &&
|
||||||
|
!sw_mon_entries->mon_status_paddr) {
|
||||||
|
break_dst_ring = true;
|
||||||
|
goto next_entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_mon_stats->dest_ppdu_done++;
|
||||||
|
pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
|
||||||
|
pmon->buf_state = DP_MON_STATUS_LAG;
|
||||||
|
pmon->mon_status_paddr = sw_mon_entries->mon_status_paddr;
|
||||||
|
pmon->hold_mon_dst_ring = true;
|
||||||
|
next_entry:
|
||||||
|
ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab,
|
||||||
|
mon_dst_srng);
|
||||||
|
if (break_dst_ring)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath11k_hal_srng_access_end(ar->ab, mon_dst_srng);
|
||||||
|
spin_unlock_bh(&pmon->mon_lock);
|
||||||
|
|
||||||
|
if (rx_bufs_used) {
|
||||||
|
ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id,
|
||||||
|
&dp->rxdma_mon_buf_ring,
|
||||||
|
rx_bufs_used,
|
||||||
|
HAL_RX_BUF_RBM_SW3_BM);
|
||||||
|
}
|
||||||
|
|
||||||
|
reap_status_ring:
|
||||||
|
quota = ath11k_dp_rx_process_full_mon_status_ring(ab, mac_id,
|
||||||
|
napi, budget);
|
||||||
|
|
||||||
|
return quota;
|
||||||
|
}
|
||||||
|
|
||||||
static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id,
|
static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id,
|
||||||
struct napi_struct *napi, int budget)
|
struct napi_struct *napi, int budget)
|
||||||
{
|
{
|
||||||
@ -5120,10 +5521,14 @@ int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id,
|
|||||||
struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id);
|
struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags))
|
if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) &&
|
||||||
|
ab->hw_params.full_monitor_mode)
|
||||||
|
ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget);
|
||||||
|
else if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags))
|
||||||
ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget);
|
ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget);
|
||||||
else
|
else
|
||||||
ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget);
|
ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "debugfs_sta.h"
|
#include "debugfs_sta.h"
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "peer.h"
|
#include "peer.h"
|
||||||
|
#include "mac.h"
|
||||||
|
|
||||||
static enum hal_tcl_encap_type
|
static enum hal_tcl_encap_type
|
||||||
ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
|
ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
|
||||||
@ -985,6 +986,7 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type,
|
|||||||
struct ath11k_dp *dp = &ab->dp;
|
struct ath11k_dp *dp = &ab->dp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct htt_ext_stats_cfg_cmd *cmd;
|
struct htt_ext_stats_cfg_cmd *cmd;
|
||||||
|
u32 pdev_id;
|
||||||
int len = sizeof(*cmd);
|
int len = sizeof(*cmd);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -998,7 +1000,12 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type,
|
|||||||
memset(cmd, 0, sizeof(*cmd));
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG;
|
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG;
|
||||||
|
|
||||||
cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id;
|
if (ab->hw_params.single_pdev_only)
|
||||||
|
pdev_id = ath11k_mac_get_target_pdev_id(ar);
|
||||||
|
else
|
||||||
|
pdev_id = ar->pdev->pdev_id;
|
||||||
|
|
||||||
|
cmd->hdr.pdev_mask = 1 << pdev_id;
|
||||||
|
|
||||||
cmd->hdr.stats_type = type;
|
cmd->hdr.stats_type = type;
|
||||||
cmd->cfg_param0 = cfg_params->cfg0;
|
cmd->cfg_param0 = cfg_params->cfg0;
|
||||||
@ -1026,6 +1033,15 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset)
|
|||||||
struct htt_rx_ring_tlv_filter tlv_filter = {0};
|
struct htt_rx_ring_tlv_filter tlv_filter = {0};
|
||||||
int ret = 0, ring_id = 0, i;
|
int ret = 0, ring_id = 0, i;
|
||||||
|
|
||||||
|
if (ab->hw_params.full_monitor_mode) {
|
||||||
|
ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab,
|
||||||
|
dp->mac_id, !reset);
|
||||||
|
if (ret < 0) {
|
||||||
|
ath11k_err(ab, "failed to setup full monitor %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
|
ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
|
||||||
|
|
||||||
if (!reset) {
|
if (!reset) {
|
||||||
@ -1091,3 +1107,42 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id,
|
||||||
|
bool config)
|
||||||
|
{
|
||||||
|
struct htt_rx_full_monitor_mode_cfg_cmd *cmd;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret, len = sizeof(*cmd);
|
||||||
|
|
||||||
|
skb = ath11k_htc_alloc_skb(ab, len);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
skb_put(skb, len);
|
||||||
|
cmd = (struct htt_rx_full_monitor_mode_cfg_cmd *)skb->data;
|
||||||
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
|
cmd->info0 = FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE,
|
||||||
|
HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE);
|
||||||
|
|
||||||
|
cmd->info0 |= FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID, mac_id);
|
||||||
|
|
||||||
|
cmd->cfg = HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE |
|
||||||
|
FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING,
|
||||||
|
HTT_RX_MON_RING_SW);
|
||||||
|
if (config) {
|
||||||
|
cmd->cfg |= HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END |
|
||||||
|
HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);
|
||||||
|
if (ret)
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -37,4 +37,6 @@ int ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id,
|
|||||||
int rx_buf_size,
|
int rx_buf_size,
|
||||||
struct htt_rx_ring_tlv_filter *tlv_filter);
|
struct htt_rx_ring_tlv_filter *tlv_filter);
|
||||||
|
|
||||||
|
int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id,
|
||||||
|
bool config);
|
||||||
#endif
|
#endif
|
||||||
|
@ -974,6 +974,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
|
|||||||
srng->msi_data = params->msi_data;
|
srng->msi_data = params->msi_data;
|
||||||
srng->initialized = 1;
|
srng->initialized = 1;
|
||||||
spin_lock_init(&srng->lock);
|
spin_lock_init(&srng->lock);
|
||||||
|
lockdep_set_class(&srng->lock, hal->srng_key + ring_id);
|
||||||
|
|
||||||
for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) {
|
for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) {
|
||||||
srng->hwreg_base[i] = srng_config->reg_start[i] +
|
srng->hwreg_base[i] = srng_config->reg_start[i] +
|
||||||
@ -1260,6 +1261,24 @@ static int ath11k_hal_srng_create_config(struct ath11k_base *ab)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ath11k_hal_register_srng_key(struct ath11k_base *ab)
|
||||||
|
{
|
||||||
|
struct ath11k_hal *hal = &ab->hal;
|
||||||
|
u32 ring_id;
|
||||||
|
|
||||||
|
for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++)
|
||||||
|
lockdep_register_key(hal->srng_key + ring_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath11k_hal_unregister_srng_key(struct ath11k_base *ab)
|
||||||
|
{
|
||||||
|
struct ath11k_hal *hal = &ab->hal;
|
||||||
|
u32 ring_id;
|
||||||
|
|
||||||
|
for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++)
|
||||||
|
lockdep_unregister_key(hal->srng_key + ring_id);
|
||||||
|
}
|
||||||
|
|
||||||
int ath11k_hal_srng_init(struct ath11k_base *ab)
|
int ath11k_hal_srng_init(struct ath11k_base *ab)
|
||||||
{
|
{
|
||||||
struct ath11k_hal *hal = &ab->hal;
|
struct ath11k_hal *hal = &ab->hal;
|
||||||
@ -1279,6 +1298,8 @@ int ath11k_hal_srng_init(struct ath11k_base *ab)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_cont_rdp;
|
goto err_free_cont_rdp;
|
||||||
|
|
||||||
|
ath11k_hal_register_srng_key(ab);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_free_cont_rdp:
|
err_free_cont_rdp:
|
||||||
@ -1293,6 +1314,7 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab)
|
|||||||
{
|
{
|
||||||
struct ath11k_hal *hal = &ab->hal;
|
struct ath11k_hal *hal = &ab->hal;
|
||||||
|
|
||||||
|
ath11k_hal_unregister_srng_key(ab);
|
||||||
ath11k_hal_free_cont_rdp(ab);
|
ath11k_hal_free_cont_rdp(ab);
|
||||||
ath11k_hal_free_cont_wrp(ab);
|
ath11k_hal_free_cont_wrp(ab);
|
||||||
kfree(hal->srng_config);
|
kfree(hal->srng_config);
|
||||||
|
@ -902,6 +902,8 @@ struct ath11k_hal {
|
|||||||
/* shadow register configuration */
|
/* shadow register configuration */
|
||||||
u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS];
|
u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS];
|
||||||
int num_shadow_reg_configured;
|
int num_shadow_reg_configured;
|
||||||
|
|
||||||
|
struct lock_class_key srng_key[HAL_SRNG_RING_ID_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 ath11k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid);
|
u32 ath11k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid);
|
||||||
|
@ -858,6 +858,25 @@ struct hal_reo_entrance_ring {
|
|||||||
* this ring has looped around the ring.
|
* this ring has looped around the ring.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON GENMASK(1, 0)
|
||||||
|
#define HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE GENMASK(6, 2)
|
||||||
|
#define HAL_SW_MON_RING_INFO0_MPDU_FRAG_NUMBER GENMASK(10, 7)
|
||||||
|
#define HAL_SW_MON_RING_INFO0_FRAMELESS_BAR BIT(11)
|
||||||
|
#define HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT GENMASK(15, 12)
|
||||||
|
#define HAL_SW_MON_RING_INFO0_END_OF_PPDU BIT(16)
|
||||||
|
|
||||||
|
#define HAL_SW_MON_RING_INFO1_PHY_PPDU_ID GENMASK(15, 0)
|
||||||
|
#define HAL_SW_MON_RING_INFO1_RING_ID GENMASK(27, 20)
|
||||||
|
#define HAL_SW_MON_RING_INFO1_LOOPING_COUNT GENMASK(31, 28)
|
||||||
|
|
||||||
|
struct hal_sw_monitor_ring {
|
||||||
|
struct ath11k_buffer_addr buf_addr_info;
|
||||||
|
struct rx_mpdu_desc rx_mpdu_info;
|
||||||
|
struct ath11k_buffer_addr status_buf_addr_info;
|
||||||
|
u32 info0;
|
||||||
|
u32 info1;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define HAL_REO_CMD_HDR_INFO0_CMD_NUMBER GENMASK(15, 0)
|
#define HAL_REO_CMD_HDR_INFO0_CMD_NUMBER GENMASK(15, 0)
|
||||||
#define HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED BIT(16)
|
#define HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED BIT(16)
|
||||||
|
|
||||||
|
@ -29,8 +29,7 @@ static int ath11k_hal_reo_cmd_queue_stats(struct hal_tlv_hdr *tlv,
|
|||||||
FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
|
FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
|
||||||
|
|
||||||
desc = (struct hal_reo_get_queue_stats *)tlv->value;
|
desc = (struct hal_reo_get_queue_stats *)tlv->value;
|
||||||
memset(&desc->queue_addr_lo, 0,
|
memset_startat(desc, 0, queue_addr_lo);
|
||||||
(sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr)));
|
|
||||||
|
|
||||||
desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
|
desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
|
||||||
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
|
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
|
||||||
@ -62,8 +61,7 @@ static int ath11k_hal_reo_cmd_flush_cache(struct ath11k_hal *hal, struct hal_tlv
|
|||||||
FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
|
FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
|
||||||
|
|
||||||
desc = (struct hal_reo_flush_cache *)tlv->value;
|
desc = (struct hal_reo_flush_cache *)tlv->value;
|
||||||
memset(&desc->cache_addr_lo, 0,
|
memset_startat(desc, 0, cache_addr_lo);
|
||||||
(sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr)));
|
|
||||||
|
|
||||||
desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
|
desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
|
||||||
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
|
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
|
||||||
@ -101,8 +99,7 @@ static int ath11k_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,
|
|||||||
FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
|
FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
|
||||||
|
|
||||||
desc = (struct hal_reo_update_rx_queue *)tlv->value;
|
desc = (struct hal_reo_update_rx_queue *)tlv->value;
|
||||||
memset(&desc->queue_addr_lo, 0,
|
memset_startat(desc, 0, queue_addr_lo);
|
||||||
(sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr)));
|
|
||||||
|
|
||||||
desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
|
desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
|
||||||
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
|
if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
|
||||||
@ -764,15 +761,17 @@ void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size,
|
|||||||
* size changes and also send WMI message to FW to change the REO
|
* size changes and also send WMI message to FW to change the REO
|
||||||
* queue descriptor in Rx peer entry as part of dp_rx_tid_update.
|
* queue descriptor in Rx peer entry as part of dp_rx_tid_update.
|
||||||
*/
|
*/
|
||||||
memset(ext_desc, 0, 3 * sizeof(*ext_desc));
|
memset(ext_desc, 0, sizeof(*ext_desc));
|
||||||
ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
|
ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
|
||||||
HAL_DESC_REO_QUEUE_EXT_DESC,
|
HAL_DESC_REO_QUEUE_EXT_DESC,
|
||||||
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1);
|
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1);
|
||||||
ext_desc++;
|
ext_desc++;
|
||||||
|
memset(ext_desc, 0, sizeof(*ext_desc));
|
||||||
ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
|
ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
|
||||||
HAL_DESC_REO_QUEUE_EXT_DESC,
|
HAL_DESC_REO_QUEUE_EXT_DESC,
|
||||||
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2);
|
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2);
|
||||||
ext_desc++;
|
ext_desc++;
|
||||||
|
memset(ext_desc, 0, sizeof(*ext_desc));
|
||||||
ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
|
ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
|
||||||
HAL_DESC_REO_QUEUE_EXT_DESC,
|
HAL_DESC_REO_QUEUE_EXT_DESC,
|
||||||
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3);
|
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3);
|
||||||
@ -1186,3 +1185,47 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr,
|
|||||||
|
|
||||||
*pp_buf_addr = (void *)buf_addr_info;
|
*pp_buf_addr = (void *)buf_addr_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc,
|
||||||
|
struct hal_sw_mon_ring_entries *sw_mon_entries)
|
||||||
|
{
|
||||||
|
struct hal_sw_monitor_ring *sw_mon_ring = rx_desc;
|
||||||
|
struct ath11k_buffer_addr *buf_addr_info;
|
||||||
|
struct ath11k_buffer_addr *status_buf_addr_info;
|
||||||
|
struct rx_mpdu_desc *rx_mpdu_desc_info_details;
|
||||||
|
|
||||||
|
rx_mpdu_desc_info_details = &sw_mon_ring->rx_mpdu_info;
|
||||||
|
|
||||||
|
sw_mon_entries->msdu_cnt = FIELD_GET(RX_MPDU_DESC_INFO0_MSDU_COUNT,
|
||||||
|
rx_mpdu_desc_info_details->info0);
|
||||||
|
|
||||||
|
buf_addr_info = &sw_mon_ring->buf_addr_info;
|
||||||
|
status_buf_addr_info = &sw_mon_ring->status_buf_addr_info;
|
||||||
|
|
||||||
|
sw_mon_entries->mon_dst_paddr = (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR,
|
||||||
|
buf_addr_info->info1)) << 32) |
|
||||||
|
FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
|
||||||
|
buf_addr_info->info0);
|
||||||
|
|
||||||
|
sw_mon_entries->mon_status_paddr =
|
||||||
|
(((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR,
|
||||||
|
status_buf_addr_info->info1)) << 32) |
|
||||||
|
FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
|
||||||
|
status_buf_addr_info->info0);
|
||||||
|
|
||||||
|
sw_mon_entries->mon_dst_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
|
||||||
|
buf_addr_info->info1);
|
||||||
|
|
||||||
|
sw_mon_entries->mon_status_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
|
||||||
|
status_buf_addr_info->info1);
|
||||||
|
|
||||||
|
sw_mon_entries->status_buf_count = FIELD_GET(HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT,
|
||||||
|
sw_mon_ring->info0);
|
||||||
|
|
||||||
|
sw_mon_entries->dst_buf_addr_info = buf_addr_info;
|
||||||
|
sw_mon_entries->status_buf_addr_info = status_buf_addr_info;
|
||||||
|
|
||||||
|
sw_mon_entries->ppdu_id =
|
||||||
|
FIELD_GET(HAL_SW_MON_RING_INFO1_PHY_PPDU_ID, sw_mon_ring->info1);
|
||||||
|
}
|
||||||
|
@ -77,6 +77,20 @@ enum hal_rx_mon_status {
|
|||||||
HAL_RX_MON_STATUS_BUF_DONE,
|
HAL_RX_MON_STATUS_BUF_DONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hal_sw_mon_ring_entries {
|
||||||
|
dma_addr_t mon_dst_paddr;
|
||||||
|
dma_addr_t mon_status_paddr;
|
||||||
|
u32 mon_dst_sw_cookie;
|
||||||
|
u32 mon_status_sw_cookie;
|
||||||
|
void *dst_buf_addr_info;
|
||||||
|
void *status_buf_addr_info;
|
||||||
|
u16 ppdu_id;
|
||||||
|
u8 status_buf_count;
|
||||||
|
u8 msdu_cnt;
|
||||||
|
bool end_of_ppdu;
|
||||||
|
bool drop_ppdu;
|
||||||
|
};
|
||||||
|
|
||||||
struct hal_rx_mon_ppdu_info {
|
struct hal_rx_mon_ppdu_info {
|
||||||
u32 ppdu_id;
|
u32 ppdu_id;
|
||||||
u32 ppdu_ts;
|
u32 ppdu_ts;
|
||||||
@ -331,6 +345,9 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc,
|
|||||||
dma_addr_t *paddr, u32 *sw_cookie,
|
dma_addr_t *paddr, u32 *sw_cookie,
|
||||||
void **pp_buf_addr_info, u8 *rbm,
|
void **pp_buf_addr_info, u8 *rbm,
|
||||||
u32 *msdu_cnt);
|
u32 *msdu_cnt);
|
||||||
|
void
|
||||||
|
ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc,
|
||||||
|
struct hal_sw_mon_ring_entries *sw_mon_ent);
|
||||||
enum hal_rx_mon_status
|
enum hal_rx_mon_status
|
||||||
ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab,
|
ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab,
|
||||||
struct hal_rx_mon_ppdu_info *ppdu_info,
|
struct hal_rx_mon_ppdu_info *ppdu_info,
|
||||||
|
@ -150,18 +150,18 @@ static void ath11k_hw_ipq8074_reo_setup(struct ath11k_base *ab)
|
|||||||
static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab,
|
static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab,
|
||||||
struct target_resource_config *config)
|
struct target_resource_config *config)
|
||||||
{
|
{
|
||||||
config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS;
|
config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab);
|
||||||
|
|
||||||
if (ab->num_radios == 2) {
|
if (ab->num_radios == 2) {
|
||||||
config->num_peers = TARGET_NUM_PEERS(DBS);
|
config->num_peers = TARGET_NUM_PEERS(ab, DBS);
|
||||||
config->num_tids = TARGET_NUM_TIDS(DBS);
|
config->num_tids = TARGET_NUM_TIDS(ab, DBS);
|
||||||
} else if (ab->num_radios == 3) {
|
} else if (ab->num_radios == 3) {
|
||||||
config->num_peers = TARGET_NUM_PEERS(DBS_SBS);
|
config->num_peers = TARGET_NUM_PEERS(ab, DBS_SBS);
|
||||||
config->num_tids = TARGET_NUM_TIDS(DBS_SBS);
|
config->num_tids = TARGET_NUM_TIDS(ab, DBS_SBS);
|
||||||
} else {
|
} else {
|
||||||
/* Control should not reach here */
|
/* Control should not reach here */
|
||||||
config->num_peers = TARGET_NUM_PEERS(SINGLE);
|
config->num_peers = TARGET_NUM_PEERS(ab, SINGLE);
|
||||||
config->num_tids = TARGET_NUM_TIDS(SINGLE);
|
config->num_tids = TARGET_NUM_TIDS(ab, SINGLE);
|
||||||
}
|
}
|
||||||
config->num_offload_peers = TARGET_NUM_OFFLD_PEERS;
|
config->num_offload_peers = TARGET_NUM_OFFLD_PEERS;
|
||||||
config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
|
config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
|
||||||
|
@ -12,26 +12,26 @@
|
|||||||
/* Target configuration defines */
|
/* Target configuration defines */
|
||||||
|
|
||||||
/* Num VDEVS per radio */
|
/* Num VDEVS per radio */
|
||||||
#define TARGET_NUM_VDEVS (16 + 1)
|
#define TARGET_NUM_VDEVS(ab) (ab->hw_params.num_vdevs)
|
||||||
|
|
||||||
#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS)
|
#define TARGET_NUM_PEERS_PDEV(ab) (ab->hw_params.num_peers + TARGET_NUM_VDEVS(ab))
|
||||||
|
|
||||||
/* Num of peers for Single Radio mode */
|
/* Num of peers for Single Radio mode */
|
||||||
#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV)
|
#define TARGET_NUM_PEERS_SINGLE(ab) (TARGET_NUM_PEERS_PDEV(ab))
|
||||||
|
|
||||||
/* Num of peers for DBS */
|
/* Num of peers for DBS */
|
||||||
#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV)
|
#define TARGET_NUM_PEERS_DBS(ab) (2 * TARGET_NUM_PEERS_PDEV(ab))
|
||||||
|
|
||||||
/* Num of peers for DBS_SBS */
|
/* Num of peers for DBS_SBS */
|
||||||
#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV)
|
#define TARGET_NUM_PEERS_DBS_SBS(ab) (3 * TARGET_NUM_PEERS_PDEV(ab))
|
||||||
|
|
||||||
/* Max num of stations (per radio) */
|
/* Max num of stations (per radio) */
|
||||||
#define TARGET_NUM_STATIONS 512
|
#define TARGET_NUM_STATIONS(ab) (ab->hw_params.num_peers)
|
||||||
|
|
||||||
#define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x
|
#define TARGET_NUM_PEERS(ab, x) TARGET_NUM_PEERS_##x(ab)
|
||||||
#define TARGET_NUM_PEER_KEYS 2
|
#define TARGET_NUM_PEER_KEYS 2
|
||||||
#define TARGET_NUM_TIDS(x) (2 * TARGET_NUM_PEERS(x) + \
|
#define TARGET_NUM_TIDS(ab, x) (2 * TARGET_NUM_PEERS(ab, x) + \
|
||||||
4 * TARGET_NUM_VDEVS + 8)
|
4 * TARGET_NUM_VDEVS(ab) + 8)
|
||||||
|
|
||||||
#define TARGET_AST_SKID_LIMIT 16
|
#define TARGET_AST_SKID_LIMIT 16
|
||||||
#define TARGET_NUM_OFFLD_PEERS 4
|
#define TARGET_NUM_OFFLD_PEERS 4
|
||||||
@ -168,10 +168,14 @@ struct ath11k_hw_params {
|
|||||||
|
|
||||||
u16 interface_modes;
|
u16 interface_modes;
|
||||||
bool supports_monitor;
|
bool supports_monitor;
|
||||||
|
bool full_monitor_mode;
|
||||||
bool supports_shadow_regs;
|
bool supports_shadow_regs;
|
||||||
bool idle_ps;
|
bool idle_ps;
|
||||||
bool supports_sta_ps;
|
bool supports_sta_ps;
|
||||||
bool cold_boot_calib;
|
bool cold_boot_calib;
|
||||||
|
int fw_mem_mode;
|
||||||
|
u32 num_vdevs;
|
||||||
|
u32 num_peers;
|
||||||
bool supports_suspend;
|
bool supports_suspend;
|
||||||
u32 hal_desc_sz;
|
u32 hal_desc_sz;
|
||||||
bool fix_l1ss;
|
bool fix_l1ss;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
@ -553,6 +554,67 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab)
|
||||||
|
{
|
||||||
|
struct ath11k *ar;
|
||||||
|
struct ath11k_pdev *pdev;
|
||||||
|
struct ath11k_vif *arvif;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
pdev = &ab->pdevs[i];
|
||||||
|
ar = pdev->ar;
|
||||||
|
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||||
|
if (arvif->is_up)
|
||||||
|
return arvif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ath11k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BAND band2)
|
||||||
|
{
|
||||||
|
return (((band1 == NL80211_BAND_2GHZ) && (band2 & WMI_HOST_WLAN_2G_CAP)) ||
|
||||||
|
(((band1 == NL80211_BAND_5GHZ) || (band1 == NL80211_BAND_6GHZ)) &&
|
||||||
|
(band2 & WMI_HOST_WLAN_5G_CAP)));
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = arvif->ar;
|
||||||
|
struct ath11k_base *ab = ar->ab;
|
||||||
|
struct ieee80211_vif *vif = arvif->vif;
|
||||||
|
struct cfg80211_chan_def def;
|
||||||
|
enum nl80211_band band;
|
||||||
|
u8 pdev_id = ab->target_pdev_ids[0].pdev_id;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
|
||||||
|
return pdev_id;
|
||||||
|
|
||||||
|
band = def.chan->band;
|
||||||
|
|
||||||
|
for (i = 0; i < ab->target_pdev_count; i++) {
|
||||||
|
if (ath11k_mac_band_match(band, ab->target_pdev_ids[i].supported_bands))
|
||||||
|
return ab->target_pdev_ids[i].pdev_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdev_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar)
|
||||||
|
{
|
||||||
|
struct ath11k_vif *arvif;
|
||||||
|
|
||||||
|
arvif = ath11k_mac_get_vif_up(ar->ab);
|
||||||
|
|
||||||
|
if (arvif)
|
||||||
|
return ath11k_mac_get_target_pdev_id_from_vif(arvif);
|
||||||
|
else
|
||||||
|
return ar->ab->target_pdev_ids[0].pdev_id;
|
||||||
|
}
|
||||||
|
|
||||||
static void ath11k_pdev_caps_update(struct ath11k *ar)
|
static void ath11k_pdev_caps_update(struct ath11k *ar)
|
||||||
{
|
{
|
||||||
struct ath11k_base *ab = ar->ab;
|
struct ath11k_base *ab = ar->ab;
|
||||||
@ -1920,7 +1982,6 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
|
|||||||
struct ath11k_vif *arvif = (void *)vif->drv_priv;
|
struct ath11k_vif *arvif = (void *)vif->drv_priv;
|
||||||
struct cfg80211_chan_def def;
|
struct cfg80211_chan_def def;
|
||||||
const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
|
const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
|
||||||
u8 ampdu_factor;
|
|
||||||
enum nl80211_band band;
|
enum nl80211_band band;
|
||||||
u16 *he_mcs_mask;
|
u16 *he_mcs_mask;
|
||||||
u8 max_nss, he_mcs;
|
u8 max_nss, he_mcs;
|
||||||
@ -1928,6 +1989,9 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
|
|||||||
int i, he_nss, nss_idx;
|
int i, he_nss, nss_idx;
|
||||||
bool user_rate_valid = true;
|
bool user_rate_valid = true;
|
||||||
u32 rx_nss, tx_nss, nss_160;
|
u32 rx_nss, tx_nss, nss_160;
|
||||||
|
u8 ampdu_factor, rx_mcs_80, rx_mcs_160;
|
||||||
|
u16 mcs_160_map, mcs_80_map;
|
||||||
|
bool support_160;
|
||||||
|
|
||||||
if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
|
if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
|
||||||
return;
|
return;
|
||||||
@ -1942,6 +2006,39 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
arg->he_flag = true;
|
arg->he_flag = true;
|
||||||
|
support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] &
|
||||||
|
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G);
|
||||||
|
|
||||||
|
/* Supported HE-MCS and NSS Set of peer he_cap is intersection with self he_cp */
|
||||||
|
mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
|
||||||
|
mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
|
||||||
|
|
||||||
|
if (support_160) {
|
||||||
|
for (i = 7; i >= 0; i--) {
|
||||||
|
u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3;
|
||||||
|
|
||||||
|
if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
|
||||||
|
rx_mcs_160 = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 7; i >= 0; i--) {
|
||||||
|
u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3;
|
||||||
|
|
||||||
|
if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
|
||||||
|
rx_mcs_80 = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (support_160)
|
||||||
|
max_nss = min(rx_mcs_80, rx_mcs_160);
|
||||||
|
else
|
||||||
|
max_nss = rx_mcs_80;
|
||||||
|
|
||||||
|
arg->peer_nss = min(sta->rx_nss, max_nss);
|
||||||
|
|
||||||
memcpy_and_pad(&arg->peer_he_cap_macinfo,
|
memcpy_and_pad(&arg->peer_he_cap_macinfo,
|
||||||
sizeof(arg->peer_he_cap_macinfo),
|
sizeof(arg->peer_he_cap_macinfo),
|
||||||
@ -2584,6 +2681,15 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
|
|||||||
if (ret)
|
if (ret)
|
||||||
ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
|
ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
|
||||||
arvif->vdev_id, ret);
|
arvif->vdev_id, ret);
|
||||||
|
|
||||||
|
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
|
||||||
|
WMI_VDEV_PARAM_DTIM_POLICY,
|
||||||
|
WMI_DTIM_POLICY_STICK);
|
||||||
|
if (ret)
|
||||||
|
ath11k_warn(ar->ab, "failed to set vdev %d dtim policy: %d\n",
|
||||||
|
arvif->vdev_id, ret);
|
||||||
|
|
||||||
|
ath11k_mac_11d_scan_stop_all(ar->ab);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath11k_bss_disassoc(struct ieee80211_hw *hw,
|
static void ath11k_bss_disassoc(struct ieee80211_hw *hw,
|
||||||
@ -3313,6 +3419,7 @@ static int ath11k_start_scan(struct ath11k *ar,
|
|||||||
struct scan_req_params *arg)
|
struct scan_req_params *arg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned long timeout = 1 * HZ;
|
||||||
|
|
||||||
lockdep_assert_held(&ar->conf_mutex);
|
lockdep_assert_held(&ar->conf_mutex);
|
||||||
|
|
||||||
@ -3323,7 +3430,14 @@ static int ath11k_start_scan(struct ath11k *ar,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ);
|
if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) {
|
||||||
|
timeout = 5 * HZ;
|
||||||
|
|
||||||
|
if (ar->supports_6ghz)
|
||||||
|
timeout += 5 * HZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wait_for_completion_timeout(&ar->scan.started, timeout);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = ath11k_scan_stop(ar);
|
ret = ath11k_scan_stop(ar);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -3380,15 +3494,38 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
/* Currently the pending_11d=true only happened 1 time while
|
||||||
|
* wlan interface up in ath11k_mac_11d_scan_start(), it is called by
|
||||||
|
* ath11k_mac_op_add_interface(), after wlan interface up,
|
||||||
|
* pending_11d=false always.
|
||||||
|
* If remove below wait, it always happened scan fail and lead connect
|
||||||
|
* fail while wlan interface up, because it has a 11d scan which is running
|
||||||
|
* in firmware, and lead this scan failed.
|
||||||
|
*/
|
||||||
|
if (ar->pending_11d) {
|
||||||
|
long time_left;
|
||||||
|
unsigned long timeout = 5 * HZ;
|
||||||
|
|
||||||
|
if (ar->supports_6ghz)
|
||||||
|
timeout += 5 * HZ;
|
||||||
|
|
||||||
|
time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout);
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
|
||||||
|
"mac wait 11d channel list time left %ld\n", time_left);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&arg, 0, sizeof(arg));
|
memset(&arg, 0, sizeof(arg));
|
||||||
ath11k_wmi_start_scan_init(ar, &arg);
|
ath11k_wmi_start_scan_init(ar, &arg);
|
||||||
arg.vdev_id = arvif->vdev_id;
|
arg.vdev_id = arvif->vdev_id;
|
||||||
arg.scan_id = ATH11K_SCAN_ID;
|
arg.scan_id = ATH11K_SCAN_ID;
|
||||||
|
|
||||||
if (req->ie_len) {
|
if (req->ie_len) {
|
||||||
|
arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL);
|
||||||
|
if (!arg.extraie.ptr) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
arg.extraie.len = req->ie_len;
|
arg.extraie.len = req->ie_len;
|
||||||
arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL);
|
|
||||||
memcpy(arg.extraie.ptr, req->ie, req->ie_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->n_ssids) {
|
if (req->n_ssids) {
|
||||||
@ -3404,10 +3541,24 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
if (req->n_channels) {
|
if (req->n_channels) {
|
||||||
arg.num_chan = req->n_channels;
|
arg.num_chan = req->n_channels;
|
||||||
|
arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list),
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!arg.chan_list) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < arg.num_chan; i++)
|
for (i = 0; i < arg.num_chan; i++)
|
||||||
arg.chan_list[i] = req->channels[i]->center_freq;
|
arg.chan_list[i] = req->channels[i]->center_freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
|
||||||
|
arg.scan_f_add_spoofed_mac_in_probe = 1;
|
||||||
|
ether_addr_copy(arg.mac_addr.addr, req->mac_addr);
|
||||||
|
ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask);
|
||||||
|
}
|
||||||
|
|
||||||
ret = ath11k_start_scan(ar, &arg);
|
ret = ath11k_start_scan(ar, &arg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
|
ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
|
||||||
@ -3422,6 +3573,8 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
|
|||||||
ATH11K_MAC_SCAN_TIMEOUT_MSECS));
|
ATH11K_MAC_SCAN_TIMEOUT_MSECS));
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
kfree(arg.chan_list);
|
||||||
|
|
||||||
if (req->ie_len)
|
if (req->ie_len)
|
||||||
kfree(arg.extraie.ptr);
|
kfree(arg.extraie.ptr);
|
||||||
|
|
||||||
@ -3597,7 +3750,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||||||
/* flush the fragments cache during key (re)install to
|
/* flush the fragments cache during key (re)install to
|
||||||
* ensure all frags in the new frag list belong to the same key.
|
* ensure all frags in the new frag list belong to the same key.
|
||||||
*/
|
*/
|
||||||
if (peer && cmd == SET_KEY)
|
if (peer && sta && cmd == SET_KEY)
|
||||||
ath11k_peer_frags_flush(ar, peer);
|
ath11k_peer_frags_flush(ar, peer);
|
||||||
spin_unlock_bh(&ab->base_lock);
|
spin_unlock_bh(&ab->base_lock);
|
||||||
|
|
||||||
@ -5128,23 +5281,47 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
|
static void ath11k_mgmt_over_wmi_tx_drop(struct ath11k *ar, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct sk_buff *msdu = skb;
|
int num_mgmt;
|
||||||
|
|
||||||
|
ieee80211_free_txskb(ar->hw, skb);
|
||||||
|
|
||||||
|
num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);
|
||||||
|
|
||||||
|
if (num_mgmt < 0)
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
|
||||||
|
if (!num_mgmt)
|
||||||
|
wake_up(&ar->txmgmt_empty_waitq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
|
||||||
|
{
|
||||||
|
struct sk_buff *msdu;
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
struct ath11k *ar = ctx;
|
|
||||||
struct ath11k_base *ab = ar->ab;
|
|
||||||
|
|
||||||
spin_lock_bh(&ar->txmgmt_idr_lock);
|
spin_lock_bh(&ar->txmgmt_idr_lock);
|
||||||
idr_remove(&ar->txmgmt_idr, buf_id);
|
msdu = idr_remove(&ar->txmgmt_idr, buf_id);
|
||||||
spin_unlock_bh(&ar->txmgmt_idr_lock);
|
spin_unlock_bh(&ar->txmgmt_idr_lock);
|
||||||
dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
|
|
||||||
|
if (!msdu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dma_unmap_single(ar->ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
|
|
||||||
info = IEEE80211_SKB_CB(msdu);
|
info = IEEE80211_SKB_CB(msdu);
|
||||||
memset(&info->status, 0, sizeof(info->status));
|
memset(&info->status, 0, sizeof(info->status));
|
||||||
|
|
||||||
ieee80211_free_txskb(ar->hw, msdu);
|
ath11k_mgmt_over_wmi_tx_drop(ar, msdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
|
||||||
|
{
|
||||||
|
struct ath11k *ar = ctx;
|
||||||
|
|
||||||
|
ath11k_mac_tx_mgmt_free(ar, buf_id);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5153,17 +5330,10 @@ static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
|
|||||||
{
|
{
|
||||||
struct ieee80211_vif *vif = ctx;
|
struct ieee80211_vif *vif = ctx;
|
||||||
struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
|
struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
|
||||||
struct sk_buff *msdu = skb;
|
|
||||||
struct ath11k *ar = skb_cb->ar;
|
struct ath11k *ar = skb_cb->ar;
|
||||||
struct ath11k_base *ab = ar->ab;
|
|
||||||
|
|
||||||
if (skb_cb->vif == vif) {
|
if (skb_cb->vif == vif)
|
||||||
spin_lock_bh(&ar->txmgmt_idr_lock);
|
ath11k_mac_tx_mgmt_free(ar, buf_id);
|
||||||
idr_remove(&ar->txmgmt_idr, buf_id);
|
|
||||||
spin_unlock_bh(&ar->txmgmt_idr_lock);
|
|
||||||
dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len,
|
|
||||||
DMA_TO_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5178,10 +5348,16 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
|
|||||||
int buf_id;
|
int buf_id;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ATH11K_SKB_CB(skb)->ar = ar;
|
||||||
|
|
||||||
spin_lock_bh(&ar->txmgmt_idr_lock);
|
spin_lock_bh(&ar->txmgmt_idr_lock);
|
||||||
buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0,
|
buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0,
|
||||||
ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC);
|
ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC);
|
||||||
spin_unlock_bh(&ar->txmgmt_idr_lock);
|
spin_unlock_bh(&ar->txmgmt_idr_lock);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
|
||||||
|
"mac tx mgmt frame, buf id %d\n", buf_id);
|
||||||
|
|
||||||
if (buf_id < 0)
|
if (buf_id < 0)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
@ -5228,7 +5404,7 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
|
|||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL)
|
while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL)
|
||||||
ieee80211_free_txskb(ar->hw, skb);
|
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
||||||
@ -5243,29 +5419,29 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
|||||||
skb_cb = ATH11K_SKB_CB(skb);
|
skb_cb = ATH11K_SKB_CB(skb);
|
||||||
if (!skb_cb->vif) {
|
if (!skb_cb->vif) {
|
||||||
ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
|
ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
|
||||||
ieee80211_free_txskb(ar->hw, skb);
|
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
arvif = ath11k_vif_to_arvif(skb_cb->vif);
|
arvif = ath11k_vif_to_arvif(skb_cb->vif);
|
||||||
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
|
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
|
||||||
arvif->is_started) {
|
arvif->is_started) {
|
||||||
atomic_inc(&ar->num_pending_mgmt_tx);
|
|
||||||
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
|
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0)
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
|
|
||||||
ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n",
|
ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n",
|
||||||
arvif->vdev_id, ret);
|
arvif->vdev_id, ret);
|
||||||
ieee80211_free_txskb(ar->hw, skb);
|
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
|
||||||
|
} else {
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
|
||||||
|
"mac tx mgmt frame, vdev_id %d\n",
|
||||||
|
arvif->vdev_id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ath11k_warn(ar->ab,
|
ath11k_warn(ar->ab,
|
||||||
"dropping mgmt frame for vdev %d, is_started %d\n",
|
"dropping mgmt frame for vdev %d, is_started %d\n",
|
||||||
arvif->vdev_id,
|
arvif->vdev_id,
|
||||||
arvif->is_started);
|
arvif->is_started);
|
||||||
ieee80211_free_txskb(ar->hw, skb);
|
ath11k_mgmt_over_wmi_tx_drop(ar, skb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5296,6 +5472,7 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
skb_queue_tail(q, skb);
|
skb_queue_tail(q, skb);
|
||||||
|
atomic_inc(&ar->num_pending_mgmt_tx);
|
||||||
ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
|
ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -5426,6 +5603,14 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) {
|
||||||
|
ret = ath11k_wmi_scan_prob_req_oui(ar, ar->mac_addr);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_err(ab, "failed to set prob req oui: %i\n", ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
|
ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
|
||||||
0, pdev->pdev_id);
|
0, pdev->pdev_id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -5524,6 +5709,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
|
|||||||
|
|
||||||
cancel_delayed_work_sync(&ar->scan.timeout);
|
cancel_delayed_work_sync(&ar->scan.timeout);
|
||||||
cancel_work_sync(&ar->regd_update_work);
|
cancel_work_sync(&ar->regd_update_work);
|
||||||
|
cancel_work_sync(&ar->ab->update_11d_work);
|
||||||
|
|
||||||
spin_lock_bh(&ar->data_lock);
|
spin_lock_bh(&ar->data_lock);
|
||||||
list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
|
list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
|
||||||
@ -5677,6 +5863,122 @@ static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ath11k_mac_vif_ap_active_any(struct ath11k_base *ab)
|
||||||
|
{
|
||||||
|
struct ath11k *ar;
|
||||||
|
struct ath11k_pdev *pdev;
|
||||||
|
struct ath11k_vif *arvif;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
pdev = &ab->pdevs[i];
|
||||||
|
ar = pdev->ar;
|
||||||
|
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||||
|
if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait)
|
||||||
|
{
|
||||||
|
struct wmi_11d_scan_start_params param;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&ar->ab->vdev_id_11d_lock);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n",
|
||||||
|
ar->vdev_id_11d_scan);
|
||||||
|
|
||||||
|
if (ar->regdom_set_by_user)
|
||||||
|
goto fin;
|
||||||
|
|
||||||
|
if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID)
|
||||||
|
goto fin;
|
||||||
|
|
||||||
|
if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
|
||||||
|
goto fin;
|
||||||
|
|
||||||
|
if (ath11k_mac_vif_ap_active_any(ar->ab))
|
||||||
|
goto fin;
|
||||||
|
|
||||||
|
param.vdev_id = vdev_id;
|
||||||
|
param.start_interval_msec = 0;
|
||||||
|
param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL;
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n");
|
||||||
|
|
||||||
|
if (wait)
|
||||||
|
reinit_completion(&ar->finish_11d_scan);
|
||||||
|
|
||||||
|
ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n",
|
||||||
|
vdev_id, ret);
|
||||||
|
} else {
|
||||||
|
ar->vdev_id_11d_scan = vdev_id;
|
||||||
|
if (wait) {
|
||||||
|
ar->pending_11d = true;
|
||||||
|
ret = wait_for_completion_timeout(&ar->finish_11d_scan,
|
||||||
|
5 * HZ);
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
|
||||||
|
"mac 11d scan left time %d\n", ret);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ar->pending_11d = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fin:
|
||||||
|
mutex_unlock(&ar->ab->vdev_id_11d_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath11k_mac_11d_scan_stop(struct ath11k *ar)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u32 vdev_id;
|
||||||
|
|
||||||
|
if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n");
|
||||||
|
|
||||||
|
mutex_lock(&ar->ab->vdev_id_11d_lock);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n",
|
||||||
|
ar->vdev_id_11d_scan);
|
||||||
|
|
||||||
|
if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) {
|
||||||
|
vdev_id = ar->vdev_id_11d_scan;
|
||||||
|
|
||||||
|
ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id);
|
||||||
|
if (ret)
|
||||||
|
ath11k_warn(ar->ab,
|
||||||
|
"failed to stopt 11d scan vdev %d ret: %d\n",
|
||||||
|
vdev_id, ret);
|
||||||
|
else
|
||||||
|
ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID;
|
||||||
|
}
|
||||||
|
mutex_unlock(&ar->ab->vdev_id_11d_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab)
|
||||||
|
{
|
||||||
|
struct ath11k *ar;
|
||||||
|
struct ath11k_pdev *pdev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n");
|
||||||
|
|
||||||
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
|
pdev = &ab->pdevs[i];
|
||||||
|
ar = pdev->ar;
|
||||||
|
|
||||||
|
ath11k_mac_11d_scan_stop(ar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif)
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
@ -5702,9 +6004,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
|
if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) {
|
||||||
ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n",
|
ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n",
|
||||||
ar->num_created_vdevs, TARGET_NUM_VDEVS);
|
ar->num_created_vdevs, TARGET_NUM_VDEVS(ab));
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -5810,6 +6112,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
|||||||
arvif->vdev_id, ret);
|
arvif->vdev_id, ret);
|
||||||
goto err_peer_del;
|
goto err_peer_del;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ath11k_mac_11d_scan_stop_all(ar->ab);
|
||||||
break;
|
break;
|
||||||
case WMI_VDEV_TYPE_STA:
|
case WMI_VDEV_TYPE_STA:
|
||||||
param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
|
param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
|
||||||
@ -5849,6 +6153,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
|||||||
arvif->vdev_id, ret);
|
arvif->vdev_id, ret);
|
||||||
goto err_peer_del;
|
goto err_peer_del;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case WMI_VDEV_TYPE_MONITOR:
|
case WMI_VDEV_TYPE_MONITOR:
|
||||||
set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
|
set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
|
||||||
@ -5950,6 +6257,9 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
|
|||||||
ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
|
ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
|
||||||
arvif->vdev_id);
|
arvif->vdev_id);
|
||||||
|
|
||||||
|
if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
|
||||||
|
ath11k_mac_11d_scan_stop(ar);
|
||||||
|
|
||||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||||
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
|
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -6363,37 +6673,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
|
|||||||
|
|
||||||
lockdep_assert_held(&ar->conf_mutex);
|
lockdep_assert_held(&ar->conf_mutex);
|
||||||
|
|
||||||
for (i = 0; i < n_vifs; i++) {
|
/* Associated channel resources of all relevant vdevs
|
||||||
arvif = (void *)vifs[i].vif->drv_priv;
|
|
||||||
|
|
||||||
if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR)
|
|
||||||
monitor_vif = true;
|
|
||||||
|
|
||||||
ath11k_dbg(ab, ATH11K_DBG_MAC,
|
|
||||||
"mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n",
|
|
||||||
arvif->vdev_id,
|
|
||||||
vifs[i].old_ctx->def.chan->center_freq,
|
|
||||||
vifs[i].new_ctx->def.chan->center_freq,
|
|
||||||
vifs[i].old_ctx->def.width,
|
|
||||||
vifs[i].new_ctx->def.width);
|
|
||||||
|
|
||||||
if (WARN_ON(!arvif->is_started))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (WARN_ON(!arvif->is_up))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
|
|
||||||
if (ret) {
|
|
||||||
ath11k_warn(ab, "failed to down vdev %d: %d\n",
|
|
||||||
arvif->vdev_id, ret);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ar->num_started_vdevs--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All relevant vdevs are downed and associated channel resources
|
|
||||||
* should be available for the channel switch now.
|
* should be available for the channel switch now.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -6698,6 +6978,9 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||||||
ret);
|
ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
|
||||||
|
ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false);
|
||||||
|
|
||||||
mutex_unlock(&ar->conf_mutex);
|
mutex_unlock(&ar->conf_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6784,6 +7067,17 @@ static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v
|
|||||||
ATH11K_FLUSH_TIMEOUT);
|
ATH11K_FLUSH_TIMEOUT);
|
||||||
if (time_left == 0)
|
if (time_left == 0)
|
||||||
ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
|
ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
|
||||||
|
|
||||||
|
time_left = wait_event_timeout(ar->txmgmt_empty_waitq,
|
||||||
|
(atomic_read(&ar->num_pending_mgmt_tx) == 0),
|
||||||
|
ATH11K_FLUSH_TIMEOUT);
|
||||||
|
if (time_left == 0)
|
||||||
|
ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n",
|
||||||
|
time_left);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
|
||||||
|
"mac mgmt tx flush mgmt pending %d\n",
|
||||||
|
atomic_read(&ar->num_pending_mgmt_tx));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -7849,6 +8143,9 @@ static int __ath11k_mac_register(struct ath11k *ar)
|
|||||||
|
|
||||||
ar->hw->wiphy->interface_modes = ab->hw_params.interface_modes;
|
ar->hw->wiphy->interface_modes = ab->hw_params.interface_modes;
|
||||||
|
|
||||||
|
if (ab->hw_params.single_pdev_only && ar->supports_6ghz)
|
||||||
|
ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS);
|
||||||
|
|
||||||
ieee80211_hw_set(ar->hw, SIGNAL_DBM);
|
ieee80211_hw_set(ar->hw, SIGNAL_DBM);
|
||||||
ieee80211_hw_set(ar->hw, SUPPORTS_PS);
|
ieee80211_hw_set(ar->hw, SUPPORTS_PS);
|
||||||
ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
|
ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
|
||||||
@ -7905,11 +8202,16 @@ static int __ath11k_mac_register(struct ath11k *ar)
|
|||||||
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;
|
NL80211_FEATURE_AP_SCAN;
|
||||||
|
|
||||||
ar->max_num_stations = TARGET_NUM_STATIONS;
|
ar->max_num_stations = TARGET_NUM_STATIONS(ab);
|
||||||
ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
|
ar->max_num_peers = TARGET_NUM_PEERS_PDEV(ab);
|
||||||
|
|
||||||
ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
|
ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
|
||||||
|
|
||||||
|
if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) {
|
||||||
|
ar->hw->wiphy->features |=
|
||||||
|
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
ar->hw->queues = ATH11K_HW_MAX_QUEUES;
|
ar->hw->queues = ATH11K_HW_MAX_QUEUES;
|
||||||
ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN;
|
ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN;
|
||||||
ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;
|
ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;
|
||||||
@ -8004,7 +8306,7 @@ int ath11k_mac_register(struct ath11k_base *ab)
|
|||||||
|
|
||||||
/* Initialize channel counters frequency value in hertz */
|
/* Initialize channel counters frequency value in hertz */
|
||||||
ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ;
|
ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ;
|
||||||
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
|
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;
|
||||||
|
|
||||||
for (i = 0; i < ab->num_radios; i++) {
|
for (i = 0; i < ab->num_radios; i++) {
|
||||||
pdev = &ab->pdevs[i];
|
pdev = &ab->pdevs[i];
|
||||||
@ -8022,6 +8324,8 @@ int ath11k_mac_register(struct ath11k_base *ab)
|
|||||||
ret = __ath11k_mac_register(ar);
|
ret = __ath11k_mac_register(ar);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_cleanup;
|
goto err_cleanup;
|
||||||
|
|
||||||
|
init_waitqueue_head(&ar->txmgmt_empty_waitq);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -8099,6 +8403,9 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
|
|||||||
|
|
||||||
ar->monitor_vdev_id = -1;
|
ar->monitor_vdev_id = -1;
|
||||||
clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
|
clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
|
||||||
|
ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID;
|
||||||
|
init_completion(&ar->finish_11d_scan);
|
||||||
|
init_completion(&ar->finish_11d_ch_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -127,6 +127,13 @@ struct ath11k_generic_iter {
|
|||||||
|
|
||||||
extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default;
|
extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default;
|
||||||
|
|
||||||
|
#define ATH11K_SCAN_11D_INTERVAL 600000
|
||||||
|
#define ATH11K_11D_INVALID_VDEV_ID 0xFFFF
|
||||||
|
|
||||||
|
void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait);
|
||||||
|
void ath11k_mac_11d_scan_stop(struct ath11k *ar);
|
||||||
|
void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab);
|
||||||
|
|
||||||
void ath11k_mac_destroy(struct ath11k_base *ab);
|
void ath11k_mac_destroy(struct ath11k_base *ab);
|
||||||
void ath11k_mac_unregister(struct ath11k_base *ab);
|
void ath11k_mac_unregister(struct ath11k_base *ab);
|
||||||
int ath11k_mac_register(struct ath11k_base *ab);
|
int ath11k_mac_register(struct ath11k_base *ab);
|
||||||
@ -144,6 +151,10 @@ void ath11k_mac_scan_finish(struct ath11k *ar);
|
|||||||
struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id);
|
struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id);
|
||||||
struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab,
|
struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab,
|
||||||
u32 vdev_id);
|
u32 vdev_id);
|
||||||
|
u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar);
|
||||||
|
u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif);
|
||||||
|
struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab);
|
||||||
|
|
||||||
struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id);
|
struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id);
|
||||||
struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id);
|
struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id);
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -248,6 +251,7 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
|
|||||||
u32 user_base_data, base_vector;
|
u32 user_base_data, base_vector;
|
||||||
int ret, num_vectors, i;
|
int ret, num_vectors, i;
|
||||||
int *irq;
|
int *irq;
|
||||||
|
unsigned int msi_data;
|
||||||
|
|
||||||
ret = ath11k_pci_get_user_msi_assignment(ab_pci,
|
ret = ath11k_pci_get_user_msi_assignment(ab_pci,
|
||||||
"MHI", &num_vectors,
|
"MHI", &num_vectors,
|
||||||
@ -262,9 +266,15 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
|
|||||||
if (!irq)
|
if (!irq)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < num_vectors; i++)
|
for (i = 0; i < num_vectors; i++) {
|
||||||
|
msi_data = base_vector;
|
||||||
|
|
||||||
|
if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
msi_data += i;
|
||||||
|
|
||||||
irq[i] = ath11k_pci_get_msi_irq(ab->dev,
|
irq[i] = ath11k_pci_get_msi_irq(ab->dev,
|
||||||
base_vector + i);
|
msi_data);
|
||||||
|
}
|
||||||
|
|
||||||
ab_pci->mhi_ctrl->irq = irq;
|
ab_pci->mhi_ctrl->irq = irq;
|
||||||
ab_pci->mhi_ctrl->nr_irqs = num_vectors;
|
ab_pci->mhi_ctrl->nr_irqs = num_vectors;
|
||||||
@ -311,6 +321,26 @@ static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,
|
|||||||
writel(val, addr);
|
writel(val, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl)
|
||||||
|
{
|
||||||
|
struct device_node *np;
|
||||||
|
struct resource res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
np = of_find_node_by_type(NULL, "memory");
|
||||||
|
if (!np)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
ret = of_address_to_resource(np, 0, &res);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mhi_ctrl->iova_start = res.start + 0x1000000;
|
||||||
|
mhi_ctrl->iova_stop = res.end;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ath11k_mhi_register(struct ath11k_pci *ab_pci)
|
int ath11k_mhi_register(struct ath11k_pci *ab_pci)
|
||||||
{
|
{
|
||||||
struct ath11k_base *ab = ab_pci->ab;
|
struct ath11k_base *ab = ab_pci->ab;
|
||||||
@ -339,8 +369,18 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
mhi_ctrl->iova_start = 0;
|
if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
mhi_ctrl->iova_stop = 0xffffffff;
|
mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
|
||||||
|
|
||||||
|
if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
|
||||||
|
ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
mhi_ctrl->iova_start = 0;
|
||||||
|
mhi_ctrl->iova_stop = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
mhi_ctrl->sbl_size = SZ_512K;
|
mhi_ctrl->sbl_size = SZ_512K;
|
||||||
mhi_ctrl->seg_len = SZ_512K;
|
mhi_ctrl->seg_len = SZ_512K;
|
||||||
mhi_ctrl->fbc_download = true;
|
mhi_ctrl->fbc_download = true;
|
||||||
@ -356,6 +396,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
|
|||||||
break;
|
break;
|
||||||
case ATH11K_HW_QCA6390_HW20:
|
case ATH11K_HW_QCA6390_HW20:
|
||||||
case ATH11K_HW_WCN6855_HW20:
|
case ATH11K_HW_WCN6855_HW20:
|
||||||
|
case ATH11K_HW_WCN6855_HW21:
|
||||||
ath11k_mhi_config = &ath11k_mhi_config_qca6390;
|
ath11k_mhi_config = &ath11k_mhi_config_qca6390;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
@ -16,7 +17,8 @@
|
|||||||
#define ATH11K_PCI_BAR_NUM 0
|
#define ATH11K_PCI_BAR_NUM 0
|
||||||
#define ATH11K_PCI_DMA_MASK 32
|
#define ATH11K_PCI_DMA_MASK 32
|
||||||
|
|
||||||
#define ATH11K_PCI_IRQ_CE0_OFFSET 3
|
#define ATH11K_PCI_IRQ_CE0_OFFSET 3
|
||||||
|
#define ATH11K_PCI_IRQ_DP_OFFSET 14
|
||||||
|
|
||||||
#define WINDOW_ENABLE_BIT 0x40000000
|
#define WINDOW_ENABLE_BIT 0x40000000
|
||||||
#define WINDOW_REG_ADDRESS 0x310c
|
#define WINDOW_REG_ADDRESS 0x310c
|
||||||
@ -25,7 +27,7 @@
|
|||||||
#define WINDOW_RANGE_MASK GENMASK(18, 0)
|
#define WINDOW_RANGE_MASK GENMASK(18, 0)
|
||||||
|
|
||||||
#define TCSR_SOC_HW_VERSION 0x0224
|
#define TCSR_SOC_HW_VERSION 0x0224
|
||||||
#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8)
|
#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8)
|
||||||
#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0)
|
#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0)
|
||||||
|
|
||||||
/* BAR0 + 4k is always accessible, and no
|
/* BAR0 + 4k is always accessible, and no
|
||||||
@ -76,6 +78,17 @@ static const struct ath11k_msi_config ath11k_msi_config[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct ath11k_msi_config msi_config_one_msi = {
|
||||||
|
.total_vectors = 1,
|
||||||
|
.total_users = 4,
|
||||||
|
.users = (struct ath11k_msi_user[]) {
|
||||||
|
{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
|
||||||
|
{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
|
||||||
|
{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
|
||||||
|
{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
|
static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
|
||||||
"bhi",
|
"bhi",
|
||||||
"mhi-er0",
|
"mhi-er0",
|
||||||
@ -485,11 +498,11 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam
|
|||||||
for (idx = 0; idx < msi_config->total_users; idx++) {
|
for (idx = 0; idx < msi_config->total_users; idx++) {
|
||||||
if (strcmp(user_name, msi_config->users[idx].name) == 0) {
|
if (strcmp(user_name, msi_config->users[idx].name) == 0) {
|
||||||
*num_vectors = msi_config->users[idx].num_vectors;
|
*num_vectors = msi_config->users[idx].num_vectors;
|
||||||
*user_base_data = msi_config->users[idx].base_vector
|
*base_vector = msi_config->users[idx].base_vector;
|
||||||
+ ab_pci->msi_ep_base_data;
|
*user_base_data = *base_vector + ab_pci->msi_ep_base_data;
|
||||||
*base_vector = msi_config->users[idx].base_vector;
|
|
||||||
|
|
||||||
ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
|
ath11k_dbg(ab, ATH11K_DBG_PCI,
|
||||||
|
"Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
|
||||||
user_name, *num_vectors, *user_base_data,
|
user_name, *num_vectors, *user_base_data,
|
||||||
*base_vector);
|
*base_vector);
|
||||||
|
|
||||||
@ -560,16 +573,30 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab)
|
|||||||
|
|
||||||
static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
|
static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
|
||||||
{
|
{
|
||||||
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||||
u32 irq_idx;
|
u32 irq_idx;
|
||||||
|
|
||||||
|
/* In case of one MSI vector, we handle irq enable/disable in a
|
||||||
|
* uniform way since we only have one irq
|
||||||
|
*/
|
||||||
|
if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
return;
|
||||||
|
|
||||||
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
|
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
|
||||||
enable_irq(ab->irq_num[irq_idx]);
|
enable_irq(ab->irq_num[irq_idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
|
static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
|
||||||
{
|
{
|
||||||
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||||
u32 irq_idx;
|
u32 irq_idx;
|
||||||
|
|
||||||
|
/* In case of one MSI vector, we handle irq enable/disable in a
|
||||||
|
* uniform way since we only have one irq
|
||||||
|
*/
|
||||||
|
if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
return;
|
||||||
|
|
||||||
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
|
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
|
||||||
disable_irq_nosync(ab->irq_num[irq_idx]);
|
disable_irq_nosync(ab->irq_num[irq_idx]);
|
||||||
}
|
}
|
||||||
@ -578,6 +605,8 @@ static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
|
||||||
|
|
||||||
for (i = 0; i < ab->hw_params.ce_count; i++) {
|
for (i = 0; i < ab->hw_params.ce_count; i++) {
|
||||||
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
||||||
continue;
|
continue;
|
||||||
@ -602,20 +631,27 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
|
|||||||
static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
|
static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
|
||||||
{
|
{
|
||||||
struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
|
struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
|
||||||
|
int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
|
||||||
|
|
||||||
ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
|
ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
|
||||||
|
|
||||||
ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
|
enable_irq(ce_pipe->ab->irq_num[irq_idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
|
static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
|
||||||
{
|
{
|
||||||
struct ath11k_ce_pipe *ce_pipe = arg;
|
struct ath11k_ce_pipe *ce_pipe = arg;
|
||||||
|
struct ath11k_base *ab = ce_pipe->ab;
|
||||||
|
int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
|
||||||
|
|
||||||
|
if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
/* last interrupt received for this CE */
|
/* last interrupt received for this CE */
|
||||||
ce_pipe->timestamp = jiffies;
|
ce_pipe->timestamp = jiffies;
|
||||||
|
|
||||||
ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
|
disable_irq_nosync(ab->irq_num[irq_idx]);
|
||||||
|
|
||||||
tasklet_schedule(&ce_pipe->intr_tq);
|
tasklet_schedule(&ce_pipe->intr_tq);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@ -623,8 +659,15 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
|
|||||||
|
|
||||||
static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
|
static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
|
||||||
{
|
{
|
||||||
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* In case of one MSI vector, we handle irq enable/disable
|
||||||
|
* in a uniform way since we only have one irq
|
||||||
|
*/
|
||||||
|
if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < irq_grp->num_irq; i++)
|
for (i = 0; i < irq_grp->num_irq; i++)
|
||||||
disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
|
disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
|
||||||
}
|
}
|
||||||
@ -633,6 +676,8 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
|
||||||
|
|
||||||
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
||||||
struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
|
struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
|
||||||
|
|
||||||
@ -645,8 +690,15 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
|
|||||||
|
|
||||||
static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
|
static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
|
||||||
{
|
{
|
||||||
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* In case of one MSI vector, we handle irq enable/disable in a
|
||||||
|
* uniform way since we only have one irq
|
||||||
|
*/
|
||||||
|
if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < irq_grp->num_irq; i++)
|
for (i = 0; i < irq_grp->num_irq; i++)
|
||||||
enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
|
enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
|
||||||
}
|
}
|
||||||
@ -655,6 +707,8 @@ static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
|
||||||
|
|
||||||
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
||||||
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
|
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
|
||||||
|
|
||||||
@ -690,11 +744,13 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
|
|||||||
napi);
|
napi);
|
||||||
struct ath11k_base *ab = irq_grp->ab;
|
struct ath11k_base *ab = irq_grp->ab;
|
||||||
int work_done;
|
int work_done;
|
||||||
|
int i;
|
||||||
|
|
||||||
work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
|
work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
|
||||||
if (work_done < budget) {
|
if (work_done < budget) {
|
||||||
napi_complete_done(napi, work_done);
|
napi_complete_done(napi, work_done);
|
||||||
ath11k_pci_ext_grp_enable(irq_grp);
|
for (i = 0; i < irq_grp->num_irq; i++)
|
||||||
|
enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (work_done > budget)
|
if (work_done > budget)
|
||||||
@ -706,13 +762,19 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
|
|||||||
static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
|
static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
|
||||||
{
|
{
|
||||||
struct ath11k_ext_irq_grp *irq_grp = arg;
|
struct ath11k_ext_irq_grp *irq_grp = arg;
|
||||||
|
struct ath11k_base *ab = irq_grp->ab;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
|
ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
|
||||||
|
|
||||||
/* last interrupt received for this group */
|
/* last interrupt received for this group */
|
||||||
irq_grp->timestamp = jiffies;
|
irq_grp->timestamp = jiffies;
|
||||||
|
|
||||||
ath11k_pci_ext_grp_disable(irq_grp);
|
for (i = 0; i < irq_grp->num_irq; i++)
|
||||||
|
disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
|
||||||
|
|
||||||
napi_schedule(&irq_grp->napi);
|
napi_schedule(&irq_grp->napi);
|
||||||
|
|
||||||
@ -721,10 +783,10 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
|
|||||||
|
|
||||||
static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
|
static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
|
||||||
{
|
{
|
||||||
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||||
int i, j, ret, num_vectors = 0;
|
int i, j, ret, num_vectors = 0;
|
||||||
u32 user_base_data = 0, base_vector = 0, base_idx;
|
u32 user_base_data = 0, base_vector = 0;
|
||||||
|
|
||||||
base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
|
|
||||||
ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
|
ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
|
||||||
&num_vectors,
|
&num_vectors,
|
||||||
&user_base_data,
|
&user_base_data,
|
||||||
@ -754,7 +816,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
irq_grp->num_irq = num_irq;
|
irq_grp->num_irq = num_irq;
|
||||||
irq_grp->irqs[0] = base_idx + i;
|
irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
|
||||||
|
|
||||||
for (j = 0; j < irq_grp->num_irq; j++) {
|
for (j = 0; j < irq_grp->num_irq; j++) {
|
||||||
int irq_idx = irq_grp->irqs[j];
|
int irq_idx = irq_grp->irqs[j];
|
||||||
@ -768,23 +830,32 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
|
|||||||
|
|
||||||
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
|
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
|
||||||
ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
|
ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
|
||||||
IRQF_SHARED,
|
ab_pci->irq_flags,
|
||||||
"DP_EXT_IRQ", irq_grp);
|
"DP_EXT_IRQ", irq_grp);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_err(ab, "failed request irq %d: %d\n",
|
ath11k_err(ab, "failed request irq %d: %d\n",
|
||||||
vector, ret);
|
vector, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_irq_nosync(ab->irq_num[irq_idx]);
|
|
||||||
}
|
}
|
||||||
|
ath11k_pci_ext_grp_disable(irq_grp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,
|
||||||
|
const struct cpumask *m)
|
||||||
|
{
|
||||||
|
if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return irq_set_affinity_hint(ab_pci->pdev->irq, m);
|
||||||
|
}
|
||||||
|
|
||||||
static int ath11k_pci_config_irq(struct ath11k_base *ab)
|
static int ath11k_pci_config_irq(struct ath11k_base *ab)
|
||||||
{
|
{
|
||||||
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||||
struct ath11k_ce_pipe *ce_pipe;
|
struct ath11k_ce_pipe *ce_pipe;
|
||||||
u32 msi_data_start;
|
u32 msi_data_start;
|
||||||
u32 msi_data_count, msi_data_idx;
|
u32 msi_data_count, msi_data_idx;
|
||||||
@ -798,6 +869,12 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0));
|
||||||
|
if (ret) {
|
||||||
|
ath11k_err(ab, "failed to set irq affinity %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Configure CE irqs */
|
/* Configure CE irqs */
|
||||||
for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
|
for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
|
||||||
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
||||||
@ -812,12 +889,12 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
|
|||||||
tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
|
tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
|
||||||
|
|
||||||
ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
|
ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
|
||||||
IRQF_SHARED, irq_name[irq_idx],
|
ab_pci->irq_flags, irq_name[irq_idx],
|
||||||
ce_pipe);
|
ce_pipe);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_err(ab, "failed to request irq %d: %d\n",
|
ath11k_err(ab, "failed to request irq %d: %d\n",
|
||||||
irq_idx, ret);
|
irq_idx, ret);
|
||||||
return ret;
|
goto err_irq_affinity_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
ab->irq_num[irq_idx] = irq;
|
ab->irq_num[irq_idx] = irq;
|
||||||
@ -828,9 +905,13 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
|
|||||||
|
|
||||||
ret = ath11k_pci_ext_irq_config(ab);
|
ret = ath11k_pci_ext_irq_config(ab);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_irq_affinity_cleanup;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_irq_affinity_cleanup:
|
||||||
|
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
|
static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
|
||||||
@ -852,6 +933,8 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
|
||||||
|
|
||||||
for (i = 0; i < ab->hw_params.ce_count; i++) {
|
for (i = 0; i < ab->hw_params.ce_count; i++) {
|
||||||
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
||||||
continue;
|
continue;
|
||||||
@ -896,15 +979,25 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
|
|||||||
msi_config->total_vectors,
|
msi_config->total_vectors,
|
||||||
msi_config->total_vectors,
|
msi_config->total_vectors,
|
||||||
PCI_IRQ_MSI);
|
PCI_IRQ_MSI);
|
||||||
if (num_vectors != msi_config->total_vectors) {
|
if (num_vectors == msi_config->total_vectors) {
|
||||||
ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
|
set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
|
||||||
msi_config->total_vectors, num_vectors);
|
ab_pci->irq_flags = IRQF_SHARED;
|
||||||
|
} else {
|
||||||
if (num_vectors >= 0)
|
num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
|
||||||
return -EINVAL;
|
1,
|
||||||
else
|
1,
|
||||||
return num_vectors;
|
PCI_IRQ_MSI);
|
||||||
|
if (num_vectors < 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto reset_msi_config;
|
||||||
|
}
|
||||||
|
clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
|
||||||
|
ab_pci->msi_config = &msi_config_one_msi;
|
||||||
|
ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
|
||||||
}
|
}
|
||||||
|
ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
|
||||||
|
|
||||||
ath11k_pci_msi_disable(ab_pci);
|
ath11k_pci_msi_disable(ab_pci);
|
||||||
|
|
||||||
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
|
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
|
||||||
@ -925,6 +1018,7 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
|
|||||||
free_msi_vector:
|
free_msi_vector:
|
||||||
pci_free_irq_vectors(ab_pci->pdev);
|
pci_free_irq_vectors(ab_pci->pdev);
|
||||||
|
|
||||||
|
reset_msi_config:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -933,6 +1027,25 @@ static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
|
|||||||
pci_free_irq_vectors(ab_pci->pdev);
|
pci_free_irq_vectors(ab_pci->pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
|
||||||
|
{
|
||||||
|
struct msi_desc *msi_desc;
|
||||||
|
|
||||||
|
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
|
||||||
|
if (!msi_desc) {
|
||||||
|
ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
|
||||||
|
pci_free_irq_vectors(ab_pci->pdev);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ab_pci->msi_ep_base_data = msi_desc->msg.data;
|
||||||
|
|
||||||
|
ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
|
||||||
|
ab_pci->msi_ep_base_data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
|
static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct ath11k_base *ab = ab_pci->ab;
|
struct ath11k_base *ab = ab_pci->ab;
|
||||||
@ -1130,7 +1243,13 @@ static int ath11k_pci_start(struct ath11k_base *ab)
|
|||||||
|
|
||||||
set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
|
set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
|
||||||
|
|
||||||
ath11k_pci_aspm_restore(ab_pci);
|
/* TODO: for now don't restore ASPM in case of single MSI
|
||||||
|
* vector as MHI register reading in M2 causes system hang.
|
||||||
|
*/
|
||||||
|
if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
|
||||||
|
ath11k_pci_aspm_restore(ab_pci);
|
||||||
|
else
|
||||||
|
ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
|
||||||
|
|
||||||
ath11k_pci_ce_irqs_enable(ab);
|
ath11k_pci_ce_irqs_enable(ab);
|
||||||
ath11k_ce_rx_post_buf(ab);
|
ath11k_ce_rx_post_buf(ab);
|
||||||
@ -1229,7 +1348,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
|
|||||||
{
|
{
|
||||||
struct ath11k_base *ab;
|
struct ath11k_base *ab;
|
||||||
struct ath11k_pci *ab_pci;
|
struct ath11k_pci *ab_pci;
|
||||||
u32 soc_hw_version_major, soc_hw_version_minor;
|
u32 soc_hw_version_major, soc_hw_version_minor, addr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
|
ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
|
||||||
@ -1249,6 +1368,14 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
|
|||||||
pci_set_drvdata(pdev, ab);
|
pci_set_drvdata(pdev, ab);
|
||||||
spin_lock_init(&ab_pci->window_lock);
|
spin_lock_init(&ab_pci->window_lock);
|
||||||
|
|
||||||
|
/* Set fixed_mem_region to true for platforms support reserved memory
|
||||||
|
* from DT. If memory is reserved from DT for FW, ath11k driver need not
|
||||||
|
* allocate memory.
|
||||||
|
*/
|
||||||
|
ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr);
|
||||||
|
if (!ret)
|
||||||
|
set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags);
|
||||||
|
|
||||||
ret = ath11k_pci_claim(ab_pci, pdev);
|
ret = ath11k_pci_claim(ab_pci, pdev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_err(ab, "failed to claim device: %d\n", ret);
|
ath11k_err(ab, "failed to claim device: %d\n", ret);
|
||||||
@ -1291,9 +1418,21 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
|
|||||||
&soc_hw_version_minor);
|
&soc_hw_version_minor);
|
||||||
switch (soc_hw_version_major) {
|
switch (soc_hw_version_major) {
|
||||||
case 2:
|
case 2:
|
||||||
ab->hw_rev = ATH11K_HW_WCN6855_HW20;
|
switch (soc_hw_version_minor) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x01:
|
||||||
|
ab->hw_rev = ATH11K_HW_WCN6855_HW20;
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
case 0x11:
|
||||||
|
ab->hw_rev = ATH11K_HW_WCN6855_HW21;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto unsupported_wcn6855_soc;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
unsupported_wcn6855_soc:
|
||||||
dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
|
dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
|
||||||
soc_hw_version_major, soc_hw_version_minor);
|
soc_hw_version_major, soc_hw_version_minor);
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
@ -1342,6 +1481,17 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
|
|||||||
goto err_ce_free;
|
goto err_ce_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* kernel may allocate a dummy vector before request_irq and
|
||||||
|
* then allocate a real vector when request_irq is called.
|
||||||
|
* So get msi_data here again to avoid spurious interrupt
|
||||||
|
* as msi_data will configured to srngs.
|
||||||
|
*/
|
||||||
|
ret = ath11k_pci_config_msi_data(ab_pci);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_err(ab, "failed to config msi_data: %d\n", ret);
|
||||||
|
goto err_free_irq;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ath11k_core_init(ab);
|
ret = ath11k_core_init(ab);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_err(ab, "failed to init core: %d\n", ret);
|
ath11k_err(ab, "failed to init core: %d\n", ret);
|
||||||
@ -1378,6 +1528,8 @@ static void ath11k_pci_remove(struct pci_dev *pdev)
|
|||||||
struct ath11k_base *ab = pci_get_drvdata(pdev);
|
struct ath11k_base *ab = pci_get_drvdata(pdev);
|
||||||
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||||
|
|
||||||
|
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
|
||||||
|
|
||||||
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
|
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
|
||||||
ath11k_pci_power_down(ab);
|
ath11k_pci_power_down(ab);
|
||||||
ath11k_debugfs_soc_destroy(ab);
|
ath11k_debugfs_soc_destroy(ab);
|
||||||
|
@ -68,6 +68,7 @@ enum ath11k_pci_flags {
|
|||||||
ATH11K_PCI_FLAG_INIT_DONE,
|
ATH11K_PCI_FLAG_INIT_DONE,
|
||||||
ATH11K_PCI_FLAG_IS_MSI_64,
|
ATH11K_PCI_FLAG_IS_MSI_64,
|
||||||
ATH11K_PCI_ASPM_RESTORE,
|
ATH11K_PCI_ASPM_RESTORE,
|
||||||
|
ATH11K_PCI_FLAG_MULTI_MSI_VECTORS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath11k_pci {
|
struct ath11k_pci {
|
||||||
@ -87,6 +88,8 @@ struct ath11k_pci {
|
|||||||
/* enum ath11k_pci_flags */
|
/* enum ath11k_pci_flags */
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u16 link_ctl;
|
u16 link_ctl;
|
||||||
|
|
||||||
|
unsigned long irq_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab)
|
static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab)
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
|
|
||||||
#define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02
|
#define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02
|
||||||
@ -1751,7 +1753,9 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
|
|||||||
* failure to FW and FW will then request mulitple blocks of small
|
* failure to FW and FW will then request mulitple blocks of small
|
||||||
* chunk size memory.
|
* chunk size memory.
|
||||||
*/
|
*/
|
||||||
if (!ab->bus_params.fixed_mem_region && ab->qmi.target_mem_delayed) {
|
if (!(ab->bus_params.fixed_mem_region ||
|
||||||
|
test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) &&
|
||||||
|
ab->qmi.target_mem_delayed) {
|
||||||
delayed = true;
|
delayed = true;
|
||||||
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n",
|
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n",
|
||||||
ab->qmi.mem_seg_count);
|
ab->qmi.mem_seg_count);
|
||||||
@ -1818,10 +1822,12 @@ static void ath11k_qmi_free_target_mem_chunk(struct ath11k_base *ab)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (ab->bus_params.fixed_mem_region)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
for (i = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||||
|
if ((ab->bus_params.fixed_mem_region ||
|
||||||
|
test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) &&
|
||||||
|
ab->qmi.target_mem[i].iaddr)
|
||||||
|
iounmap(ab->qmi.target_mem[i].iaddr);
|
||||||
|
|
||||||
if (!ab->qmi.target_mem[i].vaddr)
|
if (!ab->qmi.target_mem[i].vaddr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1869,10 +1875,44 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
|
|||||||
|
|
||||||
static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
||||||
{
|
{
|
||||||
int i, idx;
|
struct device *dev = ab->dev;
|
||||||
|
struct device_node *hremote_node = NULL;
|
||||||
|
struct resource res;
|
||||||
|
u32 host_ddr_sz;
|
||||||
|
int i, idx, ret;
|
||||||
|
|
||||||
for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) {
|
for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||||
switch (ab->qmi.target_mem[i].type) {
|
switch (ab->qmi.target_mem[i].type) {
|
||||||
|
case HOST_DDR_REGION_TYPE:
|
||||||
|
hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||||
|
if (!hremote_node) {
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_QMI,
|
||||||
|
"qmi fail to get hremote_node\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = of_address_to_resource(hremote_node, 0, &res);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_QMI,
|
||||||
|
"qmi fail to get reg from hremote\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.end - res.start + 1 < ab->qmi.target_mem[i].size) {
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_QMI,
|
||||||
|
"qmi fail to assign memory of sz\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ab->qmi.target_mem[idx].paddr = res.start;
|
||||||
|
ab->qmi.target_mem[idx].iaddr =
|
||||||
|
ioremap(ab->qmi.target_mem[idx].paddr,
|
||||||
|
ab->qmi.target_mem[i].size);
|
||||||
|
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||||
|
host_ddr_sz = ab->qmi.target_mem[i].size;
|
||||||
|
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||||
|
idx++;
|
||||||
|
break;
|
||||||
case BDF_MEM_REGION_TYPE:
|
case BDF_MEM_REGION_TYPE:
|
||||||
ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr;
|
ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr;
|
||||||
ab->qmi.target_mem[idx].vaddr = NULL;
|
ab->qmi.target_mem[idx].vaddr = NULL;
|
||||||
@ -1887,10 +1927,16 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) {
|
if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) {
|
||||||
ab->qmi.target_mem[idx].paddr =
|
if (hremote_node) {
|
||||||
ATH11K_QMI_CALDB_ADDRESS;
|
ab->qmi.target_mem[idx].paddr =
|
||||||
ab->qmi.target_mem[idx].vaddr =
|
res.start + host_ddr_sz;
|
||||||
(void *)ATH11K_QMI_CALDB_ADDRESS;
|
ab->qmi.target_mem[idx].iaddr =
|
||||||
|
ioremap(ab->qmi.target_mem[idx].paddr,
|
||||||
|
ab->qmi.target_mem[i].size);
|
||||||
|
} else {
|
||||||
|
ab->qmi.target_mem[idx].paddr =
|
||||||
|
ATH11K_QMI_CALDB_ADDRESS;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ab->qmi.target_mem[idx].paddr = 0;
|
ab->qmi.target_mem[idx].paddr = 0;
|
||||||
ab->qmi.target_mem[idx].vaddr = NULL;
|
ab->qmi.target_mem[idx].vaddr = NULL;
|
||||||
@ -2621,7 +2667,8 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
|
|||||||
msg->mem_seg[i].type, msg->mem_seg[i].size);
|
msg->mem_seg[i].type, msg->mem_seg[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ab->bus_params.fixed_mem_region) {
|
if (ab->bus_params.fixed_mem_region ||
|
||||||
|
test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
|
||||||
ret = ath11k_qmi_assign_target_mem_chunk(ab);
|
ret = ath11k_qmi_assign_target_mem_chunk(ab);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_warn(ab, "failed to assign qmi target memory: %d\n",
|
ath11k_warn(ab, "failed to assign qmi target memory: %d\n",
|
||||||
@ -2830,7 +2877,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
|
|||||||
memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk));
|
memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk));
|
||||||
ab->qmi.ab = ab;
|
ab->qmi.ab = ab;
|
||||||
|
|
||||||
ab->qmi.target_mem_mode = ATH11K_QMI_TARGET_MEM_MODE_DEFAULT;
|
ab->qmi.target_mem_mode = ab->hw_params.fw_mem_mode;
|
||||||
ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX,
|
ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX,
|
||||||
&ath11k_qmi_ops, ath11k_qmi_msg_handlers);
|
&ath11k_qmi_ops, ath11k_qmi_msg_handlers);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -34,14 +34,13 @@
|
|||||||
|
|
||||||
#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
|
#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
|
||||||
#define ATH11K_FIRMWARE_MODE_OFF 4
|
#define ATH11K_FIRMWARE_MODE_OFF 4
|
||||||
#define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0
|
|
||||||
#define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ)
|
#define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ)
|
||||||
|
|
||||||
struct ath11k_base;
|
struct ath11k_base;
|
||||||
|
|
||||||
enum ath11k_qmi_file_type {
|
enum ath11k_qmi_file_type {
|
||||||
ATH11K_QMI_FILE_TYPE_BDF_GOLDEN,
|
ATH11K_QMI_FILE_TYPE_BDF_GOLDEN,
|
||||||
ATH11K_QMI_FILE_TYPE_CALDATA,
|
ATH11K_QMI_FILE_TYPE_CALDATA = 2,
|
||||||
ATH11K_QMI_FILE_TYPE_EEPROM,
|
ATH11K_QMI_FILE_TYPE_EEPROM,
|
||||||
ATH11K_QMI_MAX_FILE_TYPE,
|
ATH11K_QMI_MAX_FILE_TYPE,
|
||||||
};
|
};
|
||||||
@ -95,6 +94,7 @@ struct target_mem_chunk {
|
|||||||
u32 type;
|
u32 type;
|
||||||
dma_addr_t paddr;
|
dma_addr_t paddr;
|
||||||
u32 *vaddr;
|
u32 *vaddr;
|
||||||
|
void __iomem *iaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct target_info {
|
struct target_info {
|
||||||
|
@ -86,6 +86,9 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
|
|||||||
if (ret)
|
if (ret)
|
||||||
ath11k_warn(ar->ab,
|
ath11k_warn(ar->ab,
|
||||||
"INIT Country code set to fw failed : %d\n", ret);
|
"INIT Country code set to fw failed : %d\n", ret);
|
||||||
|
|
||||||
|
ath11k_mac_11d_scan_stop(ar);
|
||||||
|
ar->regdom_set_by_user = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ath11k_reg_update_chan_list(struct ath11k *ar)
|
int ath11k_reg_update_chan_list(struct ath11k *ar)
|
||||||
@ -179,6 +182,11 @@ int ath11k_reg_update_chan_list(struct ath11k *ar)
|
|||||||
ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params);
|
ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params);
|
||||||
kfree(params);
|
kfree(params);
|
||||||
|
|
||||||
|
if (ar->pending_11d) {
|
||||||
|
complete(&ar->finish_11d_ch_list);
|
||||||
|
ar->pending_11d = false;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,8 +252,15 @@ int ath11k_regd_update(struct ath11k *ar)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ar->pending_11d)
|
||||||
|
complete(&ar->finish_11d_scan);
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
wiphy_lock(ar->hw->wiphy);
|
wiphy_lock(ar->hw->wiphy);
|
||||||
|
|
||||||
|
if (ar->pending_11d)
|
||||||
|
reinit_completion(&ar->finish_11d_ch_list);
|
||||||
|
|
||||||
ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy);
|
ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy);
|
||||||
wiphy_unlock(ar->hw->wiphy);
|
wiphy_unlock(ar->hw->wiphy);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
@ -581,6 +581,7 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
|
|||||||
u16 length, freq;
|
u16 length, freq;
|
||||||
u8 chan_width_mhz, bin_sz;
|
u8 chan_width_mhz, bin_sz;
|
||||||
int ret;
|
int ret;
|
||||||
|
u32 check_length;
|
||||||
|
|
||||||
lockdep_assert_held(&ar->spectral.lock);
|
lockdep_assert_held(&ar->spectral.lock);
|
||||||
|
|
||||||
@ -614,6 +615,13 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz);
|
||||||
|
ret = ath11k_dbring_validate_buffer(ar, data, check_length);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab, "found magic value in fft data, dropping\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ath11k_spectral_pull_search(ar, data, &search);
|
ret = ath11k_spectral_pull_search(ar, data, &search);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_warn(ab, "failed to pull search report %d\n", ret);
|
ath11k_warn(ab, "failed to pull search report %d\n", ret);
|
||||||
@ -747,6 +755,12 @@ static int ath11k_spectral_process_data(struct ath11k *ar,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = ath11k_dbring_validate_buffer(ar, data, tlv_len);
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
summary = (struct spectral_summary_fft_report *)tlv;
|
summary = (struct spectral_summary_fft_report *)tlv;
|
||||||
ath11k_spectral_pull_summary(ar, ¶m->meta,
|
ath11k_spectral_pull_summary(ar, ¶m->meta,
|
||||||
summary, &summ_rpt);
|
summary, &summ_rpt);
|
||||||
|
@ -130,6 +130,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
|
|||||||
.min_len = sizeof(struct wmi_vdev_delete_resp_event) },
|
.min_len = sizeof(struct wmi_vdev_delete_resp_event) },
|
||||||
[WMI_TAG_OBSS_COLOR_COLLISION_EVT] = {
|
[WMI_TAG_OBSS_COLOR_COLLISION_EVT] = {
|
||||||
.min_len = sizeof(struct wmi_obss_color_collision_event) },
|
.min_len = sizeof(struct wmi_obss_color_collision_event) },
|
||||||
|
[WMI_TAG_11D_NEW_COUNTRY_EVENT] = {
|
||||||
|
.min_len = sizeof(struct wmi_11d_new_cc_ev) },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PRIMAP(_hw_mode_) \
|
#define PRIMAP(_hw_mode_) \
|
||||||
@ -337,6 +339,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
|
|||||||
struct ath11k_pdev *pdev)
|
struct ath11k_pdev *pdev)
|
||||||
{
|
{
|
||||||
struct wmi_mac_phy_capabilities *mac_phy_caps;
|
struct wmi_mac_phy_capabilities *mac_phy_caps;
|
||||||
|
struct ath11k_base *ab = wmi_handle->wmi_ab->ab;
|
||||||
struct ath11k_band_cap *cap_band;
|
struct ath11k_band_cap *cap_band;
|
||||||
struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
|
struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
|
||||||
u32 phy_map;
|
u32 phy_map;
|
||||||
@ -368,6 +371,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
|
|||||||
pdev->pdev_id = mac_phy_caps->pdev_id;
|
pdev->pdev_id = mac_phy_caps->pdev_id;
|
||||||
pdev_cap->supported_bands |= mac_phy_caps->supported_bands;
|
pdev_cap->supported_bands |= mac_phy_caps->supported_bands;
|
||||||
pdev_cap->ampdu_density = mac_phy_caps->ampdu_density;
|
pdev_cap->ampdu_density = mac_phy_caps->ampdu_density;
|
||||||
|
ab->target_pdev_ids[ab->target_pdev_count].supported_bands =
|
||||||
|
mac_phy_caps->supported_bands;
|
||||||
|
ab->target_pdev_ids[ab->target_pdev_count].pdev_id = mac_phy_caps->pdev_id;
|
||||||
|
ab->target_pdev_count++;
|
||||||
|
|
||||||
/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
|
/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
|
||||||
* band to band for a single radio, need to see how this should be
|
* band to band for a single radio, need to see how this should be
|
||||||
@ -2106,7 +2113,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|
|||||||
void *ptr;
|
void *ptr;
|
||||||
int i, ret, len;
|
int i, ret, len;
|
||||||
u32 *tmp_ptr;
|
u32 *tmp_ptr;
|
||||||
u8 extraie_len_with_pad = 0;
|
u16 extraie_len_with_pad = 0;
|
||||||
struct hint_short_ssid *s_ssid = NULL;
|
struct hint_short_ssid *s_ssid = NULL;
|
||||||
struct hint_bssid *hint_bssid = NULL;
|
struct hint_bssid *hint_bssid = NULL;
|
||||||
|
|
||||||
@ -2125,7 +2132,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|
|||||||
len += sizeof(*bssid) * params->num_bssid;
|
len += sizeof(*bssid) * params->num_bssid;
|
||||||
|
|
||||||
len += TLV_HDR_SIZE;
|
len += TLV_HDR_SIZE;
|
||||||
if (params->extraie.len)
|
if (params->extraie.len && params->extraie.len <= 0xFFFF)
|
||||||
extraie_len_with_pad =
|
extraie_len_with_pad =
|
||||||
roundup(params->extraie.len, sizeof(u32));
|
roundup(params->extraie.len, sizeof(u32));
|
||||||
len += extraie_len_with_pad;
|
len += extraie_len_with_pad;
|
||||||
@ -2174,6 +2181,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|
|||||||
cmd->num_ssids = params->num_ssids;
|
cmd->num_ssids = params->num_ssids;
|
||||||
cmd->ie_len = params->extraie.len;
|
cmd->ie_len = params->extraie.len;
|
||||||
cmd->n_probes = params->n_probes;
|
cmd->n_probes = params->n_probes;
|
||||||
|
ether_addr_copy(cmd->mac_addr.addr, params->mac_addr.addr);
|
||||||
|
ether_addr_copy(cmd->mac_mask.addr, params->mac_mask.addr);
|
||||||
|
|
||||||
ptr += sizeof(*cmd);
|
ptr += sizeof(*cmd);
|
||||||
|
|
||||||
@ -2232,7 +2241,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|
|||||||
FIELD_PREP(WMI_TLV_LEN, len);
|
FIELD_PREP(WMI_TLV_LEN, len);
|
||||||
ptr += TLV_HDR_SIZE;
|
ptr += TLV_HDR_SIZE;
|
||||||
|
|
||||||
if (params->extraie.len)
|
if (extraie_len_with_pad)
|
||||||
memcpy(ptr, params->extraie.ptr,
|
memcpy(ptr, params->extraie.ptr,
|
||||||
params->extraie.len);
|
params->extraie.len);
|
||||||
|
|
||||||
@ -2793,6 +2802,42 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar,
|
||||||
|
struct wmi_set_current_country_params *param)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
struct wmi_set_current_country_cmd *cmd;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = (struct wmi_set_current_country_cmd *)skb->data;
|
||||||
|
cmd->tlv_header =
|
||||||
|
FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) |
|
||||||
|
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||||
|
|
||||||
|
cmd->pdev_id = ar->pdev->pdev_id;
|
||||||
|
memcpy(&cmd->new_alpha2, ¶m->alpha2, 3);
|
||||||
|
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
||||||
|
"set current country pdev id %d alpha2 %c%c\n",
|
||||||
|
ar->pdev->pdev_id,
|
||||||
|
param->alpha2[0],
|
||||||
|
param->alpha2[1]);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab,
|
||||||
|
"failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret);
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
|
ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
|
||||||
struct thermal_mitigation_params *param)
|
struct thermal_mitigation_params *param)
|
||||||
@ -2857,6 +2902,75 @@ ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar,
|
||||||
|
struct wmi_11d_scan_start_params *param)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
struct wmi_11d_scan_start_cmd *cmd;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = (struct wmi_11d_scan_start_cmd *)skb->data;
|
||||||
|
cmd->tlv_header =
|
||||||
|
FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_START_CMD) |
|
||||||
|
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||||
|
|
||||||
|
cmd->vdev_id = param->vdev_id;
|
||||||
|
cmd->scan_period_msec = param->scan_period_msec;
|
||||||
|
cmd->start_interval_msec = param->start_interval_msec;
|
||||||
|
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
||||||
|
"send 11d scan start vdev id %d period %d ms internal %d ms\n",
|
||||||
|
cmd->vdev_id,
|
||||||
|
cmd->scan_period_msec,
|
||||||
|
cmd->start_interval_msec);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab,
|
||||||
|
"failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret);
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id)
|
||||||
|
{
|
||||||
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
|
struct wmi_11d_scan_stop_cmd *cmd;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = (struct wmi_11d_scan_stop_cmd *)skb->data;
|
||||||
|
cmd->tlv_header =
|
||||||
|
FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_STOP_CMD) |
|
||||||
|
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||||
|
|
||||||
|
cmd->vdev_id = vdev_id;
|
||||||
|
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
||||||
|
"send 11d scan stop vdev id %d\n",
|
||||||
|
cmd->vdev_id);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
ath11k_warn(ar->ab,
|
||||||
|
"failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret);
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter)
|
int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter)
|
||||||
{
|
{
|
||||||
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
||||||
@ -3506,7 +3620,7 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk
|
|||||||
case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE:
|
case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ath11k_warn(ab, "received unknown obss color collision detetction event\n");
|
ath11k_warn(ab, "received unknown obss color collision detection event\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
@ -4230,6 +4344,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc,
|
|||||||
svc_rdy_ext->param.num_phy = svc_rdy_ext->soc_hal_reg_caps->num_phy;
|
svc_rdy_ext->param.num_phy = svc_rdy_ext->soc_hal_reg_caps->num_phy;
|
||||||
|
|
||||||
soc->num_radios = 0;
|
soc->num_radios = 0;
|
||||||
|
soc->target_pdev_count = 0;
|
||||||
phy_id_map = svc_rdy_ext->pref_hw_mode_caps.phy_id_map;
|
phy_id_map = svc_rdy_ext->pref_hw_mode_caps.phy_id_map;
|
||||||
|
|
||||||
while (phy_id_map && soc->num_radios < MAX_RADIOS) {
|
while (phy_id_map && soc->num_radios < MAX_RADIOS) {
|
||||||
@ -4867,6 +4982,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
|
|||||||
struct sk_buff *msdu;
|
struct sk_buff *msdu;
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
struct ath11k_skb_cb *skb_cb;
|
struct ath11k_skb_cb *skb_cb;
|
||||||
|
int num_mgmt;
|
||||||
|
|
||||||
spin_lock_bh(&ar->txmgmt_idr_lock);
|
spin_lock_bh(&ar->txmgmt_idr_lock);
|
||||||
msdu = idr_find(&ar->txmgmt_idr, desc_id);
|
msdu = idr_find(&ar->txmgmt_idr, desc_id);
|
||||||
@ -4890,10 +5006,19 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
|
|||||||
|
|
||||||
ieee80211_tx_status_irqsafe(ar->hw, msdu);
|
ieee80211_tx_status_irqsafe(ar->hw, msdu);
|
||||||
|
|
||||||
|
num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);
|
||||||
|
|
||||||
/* WARN when we received this event without doing any mgmt tx */
|
/* WARN when we received this event without doing any mgmt tx */
|
||||||
if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0)
|
if (num_mgmt < 0)
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
||||||
|
"wmi mgmt tx comp pending %d desc id %d\n",
|
||||||
|
num_mgmt, desc_id);
|
||||||
|
|
||||||
|
if (!num_mgmt)
|
||||||
|
wake_up(&ar->txmgmt_empty_waitq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5896,6 +6021,41 @@ static void ath11k_wmi_op_ep_tx_credits(struct ath11k_base *ab)
|
|||||||
wake_up(&ab->wmi_ab.tx_credits_wq);
|
wake_up(&ab->wmi_ab.tx_credits_wq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
const struct wmi_11d_new_cc_ev *ev;
|
||||||
|
const void **tb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
|
||||||
|
if (IS_ERR(tb)) {
|
||||||
|
ret = PTR_ERR(tb);
|
||||||
|
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
|
||||||
|
if (!ev) {
|
||||||
|
kfree(tb);
|
||||||
|
ath11k_warn(ab, "failed to fetch 11d new cc ev");
|
||||||
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_bh(&ab->base_lock);
|
||||||
|
memcpy(&ab->new_alpha2, &ev->new_alpha2, 2);
|
||||||
|
spin_unlock_bh(&ab->base_lock);
|
||||||
|
|
||||||
|
ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n",
|
||||||
|
ab->new_alpha2[0],
|
||||||
|
ab->new_alpha2[1]);
|
||||||
|
|
||||||
|
kfree(tb);
|
||||||
|
|
||||||
|
queue_work(ab->workqueue, &ab->update_11d_work);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab,
|
static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
@ -5927,7 +6087,13 @@ static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab,
|
|||||||
|
|
||||||
static bool ath11k_reg_is_world_alpha(char *alpha)
|
static bool ath11k_reg_is_world_alpha(char *alpha)
|
||||||
{
|
{
|
||||||
return alpha[0] == '0' && alpha[1] == '0';
|
if (alpha[0] == '0' && alpha[1] == '0')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (alpha[0] == 'n' && alpha[1] == 'a')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb)
|
static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb)
|
||||||
@ -6020,7 +6186,7 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
|
|||||||
ar = ab->pdevs[pdev_idx].ar;
|
ar = ab->pdevs[pdev_idx].ar;
|
||||||
kfree(ab->new_regd[pdev_idx]);
|
kfree(ab->new_regd[pdev_idx]);
|
||||||
ab->new_regd[pdev_idx] = regd;
|
ab->new_regd[pdev_idx] = regd;
|
||||||
ieee80211_queue_work(ar->hw, &ar->regd_update_work);
|
queue_work(ab->workqueue, &ar->regd_update_work);
|
||||||
} else {
|
} else {
|
||||||
/* This regd would be applied during mac registration and is
|
/* This regd would be applied during mac registration and is
|
||||||
* held constant throughout for regd intersection purpose
|
* held constant throughout for regd intersection purpose
|
||||||
@ -7285,6 +7451,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
|
|||||||
case WMI_WOW_WAKEUP_HOST_EVENTID:
|
case WMI_WOW_WAKEUP_HOST_EVENTID:
|
||||||
ath11k_wmi_event_wow_wakeup_host(ab, skb);
|
ath11k_wmi_event_wow_wakeup_host(ab, skb);
|
||||||
break;
|
break;
|
||||||
|
case WMI_11D_NEW_COUNTRY_EVENTID:
|
||||||
|
ath11k_reg_11d_new_cc_event(ab, skb);
|
||||||
|
break;
|
||||||
/* TODO: Add remaining events */
|
/* TODO: Add remaining events */
|
||||||
default:
|
default:
|
||||||
ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
|
ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
|
||||||
@ -7543,3 +7712,31 @@ int ath11k_wmi_wow_enable(struct ath11k *ar)
|
|||||||
|
|
||||||
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID);
|
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar,
|
||||||
|
const u8 mac_addr[ETH_ALEN])
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
struct wmi_scan_prob_req_oui_cmd *cmd;
|
||||||
|
u32 prob_req_oui;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
prob_req_oui = (((u32)mac_addr[0]) << 16) |
|
||||||
|
(((u32)mac_addr[1]) << 8) | mac_addr[2];
|
||||||
|
|
||||||
|
len = sizeof(*cmd);
|
||||||
|
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = (struct wmi_scan_prob_req_oui_cmd *)skb->data;
|
||||||
|
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
|
||||||
|
WMI_TAG_SCAN_PROB_REQ_OUI_CMD) |
|
||||||
|
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
||||||
|
cmd->prob_req_oui = prob_req_oui;
|
||||||
|
|
||||||
|
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi scan prob req oui %d\n",
|
||||||
|
prob_req_oui);
|
||||||
|
|
||||||
|
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID);
|
||||||
|
}
|
||||||
|
@ -113,10 +113,10 @@ enum wmi_host_hw_mode_priority {
|
|||||||
WMI_HOST_HW_MODE_MAX_PRI
|
WMI_HOST_HW_MODE_MAX_PRI
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum WMI_HOST_WLAN_BAND {
|
||||||
WMI_HOST_WLAN_2G_CAP = 0x1,
|
WMI_HOST_WLAN_2G_CAP = 0x1,
|
||||||
WMI_HOST_WLAN_5G_CAP = 0x2,
|
WMI_HOST_WLAN_5G_CAP = 0x2,
|
||||||
WMI_HOST_WLAN_2G_5G_CAP = 0x3,
|
WMI_HOST_WLAN_2G_5G_CAP = WMI_HOST_WLAN_2G_CAP | WMI_HOST_WLAN_5G_CAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command.
|
/* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command.
|
||||||
@ -2169,6 +2169,13 @@ enum wmi_nss_ratio {
|
|||||||
WMI_NSS_RATIO_2_NSS = 0x3,
|
WMI_NSS_RATIO_2_NSS = 0x3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum wmi_dtim_policy {
|
||||||
|
WMI_DTIM_POLICY_IGNORE = 1,
|
||||||
|
WMI_DTIM_POLICY_NORMAL = 2,
|
||||||
|
WMI_DTIM_POLICY_STICK = 3,
|
||||||
|
WMI_DTIM_POLICY_AUTO = 4,
|
||||||
|
};
|
||||||
|
|
||||||
struct wmi_host_pdev_band_to_mac {
|
struct wmi_host_pdev_band_to_mac {
|
||||||
u32 pdev_id;
|
u32 pdev_id;
|
||||||
u32 start_freq;
|
u32 start_freq;
|
||||||
@ -3082,7 +3089,6 @@ enum scan_dwelltime_adaptive_mode {
|
|||||||
|
|
||||||
#define WLAN_SCAN_MAX_NUM_SSID 10
|
#define WLAN_SCAN_MAX_NUM_SSID 10
|
||||||
#define WLAN_SCAN_MAX_NUM_BSSID 10
|
#define WLAN_SCAN_MAX_NUM_BSSID 10
|
||||||
#define WLAN_SCAN_MAX_NUM_CHANNELS 40
|
|
||||||
|
|
||||||
#define WLAN_SSID_MAX_LEN 32
|
#define WLAN_SSID_MAX_LEN 32
|
||||||
|
|
||||||
@ -3303,7 +3309,7 @@ struct scan_req_params {
|
|||||||
u32 num_bssid;
|
u32 num_bssid;
|
||||||
u32 num_ssids;
|
u32 num_ssids;
|
||||||
u32 n_probes;
|
u32 n_probes;
|
||||||
u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS];
|
u32 *chan_list;
|
||||||
u32 notify_scan_events;
|
u32 notify_scan_events;
|
||||||
struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID];
|
struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID];
|
||||||
struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID];
|
struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID];
|
||||||
@ -3314,6 +3320,8 @@ struct scan_req_params {
|
|||||||
u32 num_hint_bssid;
|
u32 num_hint_bssid;
|
||||||
struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID];
|
struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID];
|
||||||
struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID];
|
struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID];
|
||||||
|
struct wmi_mac_addr mac_addr;
|
||||||
|
struct wmi_mac_addr mac_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wmi_ssid_arg {
|
struct wmi_ssid_arg {
|
||||||
@ -3677,6 +3685,11 @@ struct wmi_scan_chan_list_cmd {
|
|||||||
u32 pdev_id;
|
u32 pdev_id;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_scan_prob_req_oui_cmd {
|
||||||
|
u32 tlv_header;
|
||||||
|
u32 prob_req_oui;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define WMI_MGMT_SEND_DOWNLD_LEN 64
|
#define WMI_MGMT_SEND_DOWNLD_LEN 64
|
||||||
|
|
||||||
#define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0)
|
#define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0)
|
||||||
@ -3770,6 +3783,16 @@ struct stats_request_params {
|
|||||||
u32 pdev_id;
|
u32 pdev_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wmi_set_current_country_params {
|
||||||
|
u8 alpha2[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wmi_set_current_country_cmd {
|
||||||
|
u32 tlv_header;
|
||||||
|
u32 pdev_id;
|
||||||
|
u32 new_alpha2;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
enum set_init_cc_type {
|
enum set_init_cc_type {
|
||||||
WMI_COUNTRY_INFO_TYPE_ALPHA,
|
WMI_COUNTRY_INFO_TYPE_ALPHA,
|
||||||
WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE,
|
WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE,
|
||||||
@ -3803,6 +3826,28 @@ struct wmi_init_country_cmd {
|
|||||||
} cc_info;
|
} cc_info;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_11d_scan_start_params {
|
||||||
|
u32 vdev_id;
|
||||||
|
u32 scan_period_msec;
|
||||||
|
u32 start_interval_msec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wmi_11d_scan_start_cmd {
|
||||||
|
u32 tlv_header;
|
||||||
|
u32 vdev_id;
|
||||||
|
u32 scan_period_msec;
|
||||||
|
u32 start_interval_msec;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_11d_scan_stop_cmd {
|
||||||
|
u32 tlv_header;
|
||||||
|
u32 vdev_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_11d_new_cc_ev {
|
||||||
|
u32 new_alpha2;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define THERMAL_LEVELS 1
|
#define THERMAL_LEVELS 1
|
||||||
struct tt_level_config {
|
struct tt_level_config {
|
||||||
u32 tmplwm;
|
u32 tmplwm;
|
||||||
@ -5433,9 +5478,16 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac,
|
|||||||
u32 tid, u32 initiator, u32 reason);
|
u32 tid, u32 initiator, u32 reason);
|
||||||
int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
|
int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
|
||||||
u32 vdev_id, u32 bcn_ctrl_op);
|
u32 vdev_id, u32 bcn_ctrl_op);
|
||||||
|
int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar,
|
||||||
|
struct wmi_set_current_country_params *param);
|
||||||
int
|
int
|
||||||
ath11k_wmi_send_init_country_cmd(struct ath11k *ar,
|
ath11k_wmi_send_init_country_cmd(struct ath11k *ar,
|
||||||
struct wmi_init_country_params init_cc_param);
|
struct wmi_init_country_params init_cc_param);
|
||||||
|
|
||||||
|
int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar,
|
||||||
|
struct wmi_11d_scan_start_params *param);
|
||||||
|
int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id);
|
||||||
|
|
||||||
int
|
int
|
||||||
ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
|
ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar,
|
||||||
struct thermal_mitigation_params *param);
|
struct thermal_mitigation_params *param);
|
||||||
@ -5492,5 +5544,6 @@ int ath11k_wmi_set_hw_mode(struct ath11k_base *ab,
|
|||||||
enum wmi_host_hw_mode_config_type mode);
|
enum wmi_host_hw_mode_config_type mode);
|
||||||
int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar);
|
int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar);
|
||||||
int ath11k_wmi_wow_enable(struct ath11k *ar);
|
int ath11k_wmi_wow_enable(struct ath11k *ar);
|
||||||
|
int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar,
|
||||||
|
const u8 mac_addr[ETH_ALEN]);
|
||||||
#endif
|
#endif
|
||||||
|
@ -153,12 +153,19 @@
|
|||||||
* implementations.
|
* implementations.
|
||||||
*/
|
*/
|
||||||
struct htc_frame_hdr {
|
struct htc_frame_hdr {
|
||||||
u8 eid;
|
struct_group_tagged(htc_frame_look_ahead, header,
|
||||||
u8 flags;
|
union {
|
||||||
|
struct {
|
||||||
|
u8 eid;
|
||||||
|
u8 flags;
|
||||||
|
|
||||||
/* length of data (including trailer) that follows the header */
|
/* length of data (including trailer) that follows the header */
|
||||||
__le16 payld_len;
|
__le16 payld_len;
|
||||||
|
|
||||||
|
};
|
||||||
|
u32 word;
|
||||||
|
};
|
||||||
|
);
|
||||||
/* end of 4-byte lookahead */
|
/* end of 4-byte lookahead */
|
||||||
|
|
||||||
u8 ctrl[2];
|
u8 ctrl[2];
|
||||||
|
@ -2260,19 +2260,16 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
|
|||||||
static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
|
static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
|
||||||
{
|
{
|
||||||
struct htc_packet *packet = NULL;
|
struct htc_packet *packet = NULL;
|
||||||
struct htc_frame_hdr *htc_hdr;
|
struct htc_frame_look_ahead look_ahead;
|
||||||
u32 look_ahead;
|
|
||||||
|
|
||||||
if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead,
|
if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead.word,
|
||||||
HTC_TARGET_RESPONSE_TIMEOUT))
|
HTC_TARGET_RESPONSE_TIMEOUT))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ath6kl_dbg(ATH6KL_DBG_HTC,
|
ath6kl_dbg(ATH6KL_DBG_HTC,
|
||||||
"htc rx wait ctrl look_ahead 0x%X\n", look_ahead);
|
"htc rx wait ctrl look_ahead 0x%X\n", look_ahead.word);
|
||||||
|
|
||||||
htc_hdr = (struct htc_frame_hdr *)&look_ahead;
|
if (look_ahead.eid != ENDPOINT_0)
|
||||||
|
|
||||||
if (htc_hdr->eid != ENDPOINT_0)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
packet = htc_get_control_buf(target, false);
|
packet = htc_get_control_buf(target, false);
|
||||||
@ -2281,8 +2278,8 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
packet->info.rx.rx_flags = 0;
|
packet->info.rx.rx_flags = 0;
|
||||||
packet->info.rx.exp_hdr = look_ahead;
|
packet->info.rx.exp_hdr = look_ahead.word;
|
||||||
packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH;
|
packet->act_len = le16_to_cpu(look_ahead.payld_len) + HTC_HDR_LENGTH;
|
||||||
|
|
||||||
if (packet->act_len > packet->buf_len)
|
if (packet->act_len > packet->buf_len)
|
||||||
goto fail_ctrl_rx;
|
goto fail_ctrl_rx;
|
||||||
|
@ -154,11 +154,52 @@ static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno)
|
|||||||
seqno << IEEE80211_SEQ_SEQ_SHIFT);
|
seqno << IEEE80211_SEQ_SEQ_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ath_merge_ratetbl(struct ieee80211_sta *sta, struct ath_buf *bf,
|
||||||
|
struct ieee80211_tx_info *tx_info)
|
||||||
|
{
|
||||||
|
struct ieee80211_sta_rates *ratetbl;
|
||||||
|
u8 i;
|
||||||
|
|
||||||
|
if (!sta)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ratetbl = rcu_dereference(sta->rates);
|
||||||
|
if (!ratetbl)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tx_info->control.rates[0].idx < 0 ||
|
||||||
|
tx_info->control.rates[0].count == 0)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
} else {
|
||||||
|
bf->rates[0] = tx_info->control.rates[0];
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||||
|
bf->rates[i].idx = ratetbl->rate[i].idx;
|
||||||
|
bf->rates[i].flags = ratetbl->rate[i].flags;
|
||||||
|
if (tx_info->control.use_rts)
|
||||||
|
bf->rates[i].count = ratetbl->rate[i].count_rts;
|
||||||
|
else if (tx_info->control.use_cts_prot)
|
||||||
|
bf->rates[i].count = ratetbl->rate[i].count_cts;
|
||||||
|
else
|
||||||
|
bf->rates[i].count = ratetbl->rate[i].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||||
struct ath_buf *bf)
|
struct ath_buf *bf)
|
||||||
{
|
{
|
||||||
ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
|
struct ieee80211_tx_info *tx_info;
|
||||||
ARRAY_SIZE(bf->rates));
|
|
||||||
|
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
|
||||||
|
|
||||||
|
if (!ath_merge_ratetbl(sta, bf, tx_info))
|
||||||
|
ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
|
||||||
|
ARRAY_SIZE(bf->rates));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
||||||
|
@ -307,8 +307,7 @@ static void carl9170_zap_queues(struct ar9170 *ar)
|
|||||||
for (i = 0; i < ar->hw->queues; i++)
|
for (i = 0; i < ar->hw->queues; i++)
|
||||||
ar->tx_stats[i].limit = CARL9170_NUM_TX_LIMIT_HARD;
|
ar->tx_stats[i].limit = CARL9170_NUM_TX_LIMIT_HARD;
|
||||||
|
|
||||||
for (i = 0; i < DIV_ROUND_UP(ar->fw.mem_blocks, BITS_PER_LONG); i++)
|
bitmap_zero(ar->mem_bitmap, ar->fw.mem_blocks);
|
||||||
ar->mem_bitmap[i] = 0;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
list_for_each_entry_rcu(cvif, &ar->vif_list, list) {
|
list_for_each_entry_rcu(cvif, &ar->vif_list, list) {
|
||||||
@ -1968,9 +1967,7 @@ int carl9170_register(struct ar9170 *ar)
|
|||||||
if (WARN_ON(ar->mem_bitmap))
|
if (WARN_ON(ar->mem_bitmap))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ar->mem_bitmap = kcalloc(roundup(ar->fw.mem_blocks, BITS_PER_LONG),
|
ar->mem_bitmap = bitmap_zalloc(ar->fw.mem_blocks, GFP_KERNEL);
|
||||||
sizeof(unsigned long),
|
|
||||||
GFP_KERNEL);
|
|
||||||
|
|
||||||
if (!ar->mem_bitmap)
|
if (!ar->mem_bitmap)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -2085,7 +2082,7 @@ void carl9170_free(struct ar9170 *ar)
|
|||||||
kfree_skb(ar->rx_failover);
|
kfree_skb(ar->rx_failover);
|
||||||
ar->rx_failover = NULL;
|
ar->rx_failover = NULL;
|
||||||
|
|
||||||
kfree(ar->mem_bitmap);
|
bitmap_free(ar->mem_bitmap);
|
||||||
ar->mem_bitmap = NULL;
|
ar->mem_bitmap = NULL;
|
||||||
|
|
||||||
kfree(ar->survey);
|
kfree(ar->survey);
|
||||||
|
@ -126,6 +126,7 @@ enum CountryCode {
|
|||||||
CTRY_KOREA_ROC = 410,
|
CTRY_KOREA_ROC = 410,
|
||||||
CTRY_KOREA_ROC2 = 411,
|
CTRY_KOREA_ROC2 = 411,
|
||||||
CTRY_KOREA_ROC3 = 412,
|
CTRY_KOREA_ROC3 = 412,
|
||||||
|
CTRY_KOREA_ROC4 = 413,
|
||||||
CTRY_KUWAIT = 414,
|
CTRY_KUWAIT = 414,
|
||||||
CTRY_LATVIA = 428,
|
CTRY_LATVIA = 428,
|
||||||
CTRY_LEBANON = 422,
|
CTRY_LEBANON = 422,
|
||||||
|
@ -76,6 +76,7 @@ enum EnumRd {
|
|||||||
APL7_FCCA = 0x5C,
|
APL7_FCCA = 0x5C,
|
||||||
APL8_WORLD = 0x5D,
|
APL8_WORLD = 0x5D,
|
||||||
APL9_WORLD = 0x5E,
|
APL9_WORLD = 0x5E,
|
||||||
|
APL10_WORLD = 0x5F,
|
||||||
|
|
||||||
WOR0_WORLD = 0x60,
|
WOR0_WORLD = 0x60,
|
||||||
WOR1_WORLD = 0x61,
|
WOR1_WORLD = 0x61,
|
||||||
@ -204,6 +205,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = {
|
|||||||
{APL6_WORLD, CTL_ETSI, CTL_ETSI},
|
{APL6_WORLD, CTL_ETSI, CTL_ETSI},
|
||||||
{APL8_WORLD, CTL_ETSI, CTL_ETSI},
|
{APL8_WORLD, CTL_ETSI, CTL_ETSI},
|
||||||
{APL9_WORLD, CTL_ETSI, CTL_ETSI},
|
{APL9_WORLD, CTL_ETSI, CTL_ETSI},
|
||||||
|
{APL10_WORLD, CTL_ETSI, CTL_ETSI},
|
||||||
|
|
||||||
{APL3_FCCA, CTL_FCC, CTL_FCC},
|
{APL3_FCCA, CTL_FCC, CTL_FCC},
|
||||||
{APL7_FCCA, CTL_FCC, CTL_FCC},
|
{APL7_FCCA, CTL_FCC, CTL_FCC},
|
||||||
@ -426,6 +428,7 @@ static struct country_code_to_enum_rd allCountries[] = {
|
|||||||
{CTRY_KOREA_ROC, APL9_WORLD, "KR"},
|
{CTRY_KOREA_ROC, APL9_WORLD, "KR"},
|
||||||
{CTRY_KOREA_ROC2, APL2_WORLD, "K2"},
|
{CTRY_KOREA_ROC2, APL2_WORLD, "K2"},
|
||||||
{CTRY_KOREA_ROC3, APL9_WORLD, "K3"},
|
{CTRY_KOREA_ROC3, APL9_WORLD, "K3"},
|
||||||
|
{CTRY_KOREA_ROC4, APL10_WORLD, "K4"},
|
||||||
{CTRY_KUWAIT, ETSI3_WORLD, "KW"},
|
{CTRY_KUWAIT, ETSI3_WORLD, "KW"},
|
||||||
{CTRY_LATVIA, ETSI1_WORLD, "LV"},
|
{CTRY_LATVIA, ETSI1_WORLD, "LV"},
|
||||||
{CTRY_LEBANON, NULL1_WORLD, "LB"},
|
{CTRY_LEBANON, NULL1_WORLD, "LB"},
|
||||||
|
@ -3459,9 +3459,6 @@ struct wcn36xx_hal_missed_beacon_ind_msg {
|
|||||||
|
|
||||||
/* Beacon Filtering data structures */
|
/* Beacon Filtering data structures */
|
||||||
|
|
||||||
/* The above structure would be followed by multiple of below mentioned
|
|
||||||
* structure
|
|
||||||
*/
|
|
||||||
struct beacon_filter_ie {
|
struct beacon_filter_ie {
|
||||||
u8 element_id;
|
u8 element_id;
|
||||||
u8 check_ie_presence;
|
u8 check_ie_presence;
|
||||||
@ -3469,7 +3466,27 @@ struct beacon_filter_ie {
|
|||||||
u8 value;
|
u8 value;
|
||||||
u8 bitmask;
|
u8 bitmask;
|
||||||
u8 ref;
|
u8 ref;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
|
#define WCN36XX_FILTER_CAPABILITY_MASK 0x73cf
|
||||||
|
#define WCN36XX_FILTER_IE_DS_CHANNEL_MASK 0x00
|
||||||
|
#define WCN36XX_FILTER_IE_ERP_FILTER_MASK 0xF8
|
||||||
|
#define WCN36XX_FILTER_IE_EDCA_FILTER_MASK 0xF0
|
||||||
|
#define WCN36XX_FILTER_IE_QOS_FILTER_MASK 0xF0
|
||||||
|
#define WCN36XX_FILTER_IE_CHANNEL_SWITCH_MASK 0x00
|
||||||
|
#define WCN36XX_FILTER_IE_HT_BYTE0_FILTER_MASK 0x00
|
||||||
|
#define WCN36XX_FILTER_IE_HT_BYTE1_FILTER_MASK 0xF8
|
||||||
|
#define WCN36XX_FILTER_IE_HT_BYTE2_FILTER_MASK 0xEB
|
||||||
|
#define WCN36XX_FILTER_IE_HT_BYTE5_FILTER_MASK 0xFD
|
||||||
|
#define WCN36XX_FILTER_IE_PWR_CONSTRAINT_MASK 0x00
|
||||||
|
#define WCN36XX_FILTER_IE_OPMODE_NOTIF_MASK 0x00
|
||||||
|
#define WCN36XX_FILTER_IE_VHTOP_CHWIDTH_MASK 0xFC
|
||||||
|
#define WCN36XX_FILTER_IE_RSN_MASK 0x00
|
||||||
|
#define WCN36XX_FILTER_IE_VENDOR_MASK 0x00
|
||||||
|
|
||||||
|
/* The above structure would be followed by multiple of below mentioned
|
||||||
|
* structure
|
||||||
|
*/
|
||||||
|
|
||||||
struct wcn36xx_hal_add_bcn_filter_req_msg {
|
struct wcn36xx_hal_add_bcn_filter_req_msg {
|
||||||
struct wcn36xx_hal_msg_header header;
|
struct wcn36xx_hal_msg_header header;
|
||||||
@ -3480,14 +3497,14 @@ struct wcn36xx_hal_add_bcn_filter_req_msg {
|
|||||||
u16 ie_num;
|
u16 ie_num;
|
||||||
u8 bss_index;
|
u8 bss_index;
|
||||||
u8 reserved;
|
u8 reserved;
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
struct wcn36xx_hal_rem_bcn_filter_req {
|
struct wcn36xx_hal_rem_bcn_filter_req {
|
||||||
struct wcn36xx_hal_msg_header header;
|
struct wcn36xx_hal_msg_header header;
|
||||||
|
|
||||||
u8 ie_Count;
|
u8 ie_Count;
|
||||||
u8 rem_ie_id[1];
|
u8 rem_ie_id[1];
|
||||||
};
|
} __packed;
|
||||||
|
|
||||||
#define WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD 0
|
#define WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD 0
|
||||||
#define WCN36XX_HAL_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1
|
#define WCN36XX_HAL_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1
|
||||||
|
@ -934,6 +934,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
|
|||||||
* place where AID is available.
|
* place where AID is available.
|
||||||
*/
|
*/
|
||||||
wcn36xx_smd_config_sta(wcn, vif, sta);
|
wcn36xx_smd_config_sta(wcn, vif, sta);
|
||||||
|
if (vif->type == NL80211_IFTYPE_STATION)
|
||||||
|
wcn36xx_smd_add_beacon_filter(wcn, vif);
|
||||||
wcn36xx_enable_keep_alive_null_packet(wcn, vif);
|
wcn36xx_enable_keep_alive_null_packet(wcn, vif);
|
||||||
} else {
|
} else {
|
||||||
wcn36xx_dbg(WCN36XX_DBG_MAC,
|
wcn36xx_dbg(WCN36XX_DBG_MAC,
|
||||||
@ -1220,7 +1222,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
u16 tid = params->tid;
|
u16 tid = params->tid;
|
||||||
u16 *ssn = ¶ms->ssn;
|
u16 *ssn = ¶ms->ssn;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u8 session;
|
int session;
|
||||||
|
|
||||||
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
|
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
|
||||||
action, tid);
|
action, tid);
|
||||||
@ -1232,9 +1234,11 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
sta_priv->tid = tid;
|
sta_priv->tid = tid;
|
||||||
session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
|
session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
|
||||||
get_sta_index(vif, sta_priv));
|
get_sta_index(vif, sta_priv));
|
||||||
|
if (session < 0) {
|
||||||
|
ret = session;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
wcn36xx_smd_add_ba(wcn, session);
|
wcn36xx_smd_add_ba(wcn, session);
|
||||||
wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid,
|
|
||||||
session);
|
|
||||||
break;
|
break;
|
||||||
case IEEE80211_AMPDU_RX_STOP:
|
case IEEE80211_AMPDU_RX_STOP:
|
||||||
wcn36xx_smd_del_ba(wcn, tid, 0, get_sta_index(vif, sta_priv));
|
wcn36xx_smd_del_ba(wcn, tid, 0, get_sta_index(vif, sta_priv));
|
||||||
@ -1244,6 +1248,18 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
|
sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
|
||||||
spin_unlock_bh(&sta_priv->ampdu_lock);
|
spin_unlock_bh(&sta_priv->ampdu_lock);
|
||||||
|
|
||||||
|
/* Replace the mac80211 ssn with the firmware one */
|
||||||
|
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu ssn = %u\n", *ssn);
|
||||||
|
wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, ssn);
|
||||||
|
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu fw-ssn = %u\n", *ssn);
|
||||||
|
|
||||||
|
/* Start BA session */
|
||||||
|
session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
|
||||||
|
get_sta_index(vif, sta_priv));
|
||||||
|
if (session < 0) {
|
||||||
|
ret = session;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
||||||
break;
|
break;
|
||||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||||
@ -1251,8 +1267,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
|
sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
|
||||||
spin_unlock_bh(&sta_priv->ampdu_lock);
|
spin_unlock_bh(&sta_priv->ampdu_lock);
|
||||||
|
|
||||||
wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
|
|
||||||
get_sta_index(vif, sta_priv));
|
|
||||||
break;
|
break;
|
||||||
case IEEE80211_AMPDU_TX_STOP_FLUSH:
|
case IEEE80211_AMPDU_TX_STOP_FLUSH:
|
||||||
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
|
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
|
||||||
@ -1268,6 +1282,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
wcn36xx_err("Unknown AMPDU action\n");
|
wcn36xx_err("Unknown AMPDU action\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
mutex_unlock(&wcn->conf_mutex);
|
mutex_unlock(&wcn->conf_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -944,7 +944,7 @@ int wcn36xx_smd_update_channel_list(struct wcn36xx *wcn, struct cfg80211_scan_re
|
|||||||
|
|
||||||
INIT_HAL_MSG((*msg_body), WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ);
|
INIT_HAL_MSG((*msg_body), WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ);
|
||||||
|
|
||||||
msg_body->num_channel = min_t(u8, req->n_channels, sizeof(msg_body->channels));
|
msg_body->num_channel = min_t(u8, req->n_channels, ARRAY_SIZE(msg_body->channels));
|
||||||
for (i = 0; i < msg_body->num_channel; i++) {
|
for (i = 0; i < msg_body->num_channel; i++) {
|
||||||
struct wcn36xx_hal_channel_param *param = &msg_body->channels[i];
|
struct wcn36xx_hal_channel_param *param = &msg_body->channels[i];
|
||||||
u32 min_power = WCN36XX_HAL_DEFAULT_MIN_POWER;
|
u32 min_power = WCN36XX_HAL_DEFAULT_MIN_POWER;
|
||||||
@ -2561,6 +2561,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
|
|||||||
&session_id);
|
&session_id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret);
|
wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret);
|
||||||
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2626,27 +2627,43 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len)
|
static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba_info)
|
||||||
{
|
{
|
||||||
|
struct wcn36xx_hal_trigger_ba_rsp_candidate *candidate;
|
||||||
struct wcn36xx_hal_trigger_ba_rsp_msg *rsp;
|
struct wcn36xx_hal_trigger_ba_rsp_msg *rsp;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (len < sizeof(*rsp))
|
if (len < sizeof(*rsp))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf;
|
rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf;
|
||||||
|
|
||||||
|
if (rsp->candidate_cnt < 1)
|
||||||
|
return rsp->status ? rsp->status : -EINVAL;
|
||||||
|
|
||||||
|
candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp));
|
||||||
|
|
||||||
|
for (i = 0; i < STACFG_MAX_TC; i++) {
|
||||||
|
ba_info[i] = candidate->ba_info[i];
|
||||||
|
}
|
||||||
|
|
||||||
return rsp->status;
|
return rsp->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id)
|
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn)
|
||||||
{
|
{
|
||||||
struct wcn36xx_hal_trigger_ba_req_msg msg_body;
|
struct wcn36xx_hal_trigger_ba_req_msg msg_body;
|
||||||
struct wcn36xx_hal_trigger_ba_req_candidate *candidate;
|
struct wcn36xx_hal_trigger_ba_req_candidate *candidate;
|
||||||
|
struct add_ba_info ba_info[STACFG_MAX_TC];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (tid >= STACFG_MAX_TC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&wcn->hal_mutex);
|
mutex_lock(&wcn->hal_mutex);
|
||||||
INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ);
|
INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ);
|
||||||
|
|
||||||
msg_body.session_id = session_id;
|
msg_body.session_id = 0; /* not really used */
|
||||||
msg_body.candidate_cnt = 1;
|
msg_body.candidate_cnt = 1;
|
||||||
msg_body.header.len += sizeof(*candidate);
|
msg_body.header.len += sizeof(*candidate);
|
||||||
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||||
@ -2661,13 +2678,17 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 sessio
|
|||||||
wcn36xx_err("Sending hal_trigger_ba failed\n");
|
wcn36xx_err("Sending hal_trigger_ba failed\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len);
|
ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len, ba_info);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
|
wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&wcn->hal_mutex);
|
mutex_unlock(&wcn->hal_mutex);
|
||||||
|
|
||||||
|
if (ssn)
|
||||||
|
*ssn = ba_info[tid].starting_seq_num;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3172,6 +3193,91 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BEACON_FILTER(eid, presence, offs, val, mask, ref_val) \
|
||||||
|
{ \
|
||||||
|
.element_id = eid, \
|
||||||
|
.check_ie_presence = presence, \
|
||||||
|
.offset = offs, \
|
||||||
|
.value = val, \
|
||||||
|
.bitmask = mask, \
|
||||||
|
.ref = ref_val, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct beacon_filter_ie bcn_filter_ies[] = {
|
||||||
|
BEACON_FILTER(WLAN_EID_DS_PARAMS, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_DS_CHANNEL_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_ERP_INFO, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_ERP_FILTER_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_EDCA_PARAM_SET, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_EDCA_FILTER_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_QOS_CAPA, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_QOS_FILTER_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_CHANNEL_SWITCH, 1, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_CHANNEL_SWITCH_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_HT_BYTE0_FILTER_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 2, 0,
|
||||||
|
WCN36XX_FILTER_IE_HT_BYTE2_FILTER_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 5, 0,
|
||||||
|
WCN36XX_FILTER_IE_HT_BYTE5_FILTER_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_PWR_CONSTRAINT, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_PWR_CONSTRAINT_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_OPMODE_NOTIF, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_OPMODE_NOTIF_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_VHT_OPERATION, 0, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_VHTOP_CHWIDTH_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_RSN, 1, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_RSN_MASK, 0),
|
||||||
|
BEACON_FILTER(WLAN_EID_VENDOR_SPECIFIC, 1, 0, 0,
|
||||||
|
WCN36XX_FILTER_IE_VENDOR_MASK, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
int wcn36xx_smd_add_beacon_filter(struct wcn36xx *wcn,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
|
{
|
||||||
|
struct wcn36xx_hal_add_bcn_filter_req_msg msg_body, *body;
|
||||||
|
struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
|
||||||
|
u8 *payload;
|
||||||
|
size_t payload_size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!get_feat_caps(wcn->fw_feat_caps, BCN_FILTER))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
mutex_lock(&wcn->hal_mutex);
|
||||||
|
INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BCN_FILTER_REQ);
|
||||||
|
|
||||||
|
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||||
|
|
||||||
|
body = (struct wcn36xx_hal_add_bcn_filter_req_msg *)wcn->hal_buf;
|
||||||
|
body->capability_info = vif->bss_conf.assoc_capability;
|
||||||
|
body->capability_mask = WCN36XX_FILTER_CAPABILITY_MASK;
|
||||||
|
body->beacon_interval = vif->bss_conf.beacon_int;
|
||||||
|
body->ie_num = ARRAY_SIZE(bcn_filter_ies);
|
||||||
|
body->bss_index = vif_priv->bss_index;
|
||||||
|
|
||||||
|
payload = ((u8 *)body) + body->header.len;
|
||||||
|
payload_size = sizeof(bcn_filter_ies);
|
||||||
|
memcpy(payload, &bcn_filter_ies, payload_size);
|
||||||
|
|
||||||
|
body->header.len += payload_size;
|
||||||
|
|
||||||
|
ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);
|
||||||
|
if (ret) {
|
||||||
|
wcn36xx_err("Sending add bcn_filter failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
|
||||||
|
if (ret) {
|
||||||
|
wcn36xx_err("add bcn filter response failed err=%d\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
mutex_unlock(&wcn->hal_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
|
int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
|
||||||
void *buf, int len, void *priv, u32 addr)
|
void *buf, int len, void *priv, u32 addr)
|
||||||
{
|
{
|
||||||
@ -3227,6 +3333,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
|
|||||||
case WCN36XX_HAL_ENTER_IMPS_RSP:
|
case WCN36XX_HAL_ENTER_IMPS_RSP:
|
||||||
case WCN36XX_HAL_EXIT_IMPS_RSP:
|
case WCN36XX_HAL_EXIT_IMPS_RSP:
|
||||||
case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP:
|
case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP:
|
||||||
|
case WCN36XX_HAL_ADD_BCN_FILTER_RSP:
|
||||||
memcpy(wcn->hal_buf, buf, len);
|
memcpy(wcn->hal_buf, buf, len);
|
||||||
wcn->hal_rsp_len = len;
|
wcn->hal_rsp_len = len;
|
||||||
complete(&wcn->hal_rsp_compl);
|
complete(&wcn->hal_rsp_compl);
|
||||||
|
@ -137,7 +137,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
|
|||||||
u8 sta_index);
|
u8 sta_index);
|
||||||
int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id);
|
int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id);
|
||||||
int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 direction, u8 sta_index);
|
int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 direction, u8 sta_index);
|
||||||
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id);
|
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn);
|
||||||
|
|
||||||
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
|
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
|
||||||
|
|
||||||
@ -167,4 +167,7 @@ int wcn36xx_smd_host_resume(struct wcn36xx *wcn);
|
|||||||
int wcn36xx_smd_enter_imps(struct wcn36xx *wcn);
|
int wcn36xx_smd_enter_imps(struct wcn36xx *wcn);
|
||||||
int wcn36xx_smd_exit_imps(struct wcn36xx *wcn);
|
int wcn36xx_smd_exit_imps(struct wcn36xx *wcn);
|
||||||
|
|
||||||
|
int wcn36xx_smd_add_beacon_filter(struct wcn36xx *wcn,
|
||||||
|
struct ieee80211_vif *vif);
|
||||||
|
|
||||||
#endif /* _SMD_H_ */
|
#endif /* _SMD_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user