mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-25 04:41:15 +07:00
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for v5.8. Major changes: ath11k * add 802.11 encapsulation offload on hardware support * add htt_peer_stats_reset debugfs file ath10k * sdio: decrease power consumption * sdio: add HTT TX bundle support to increase throughput * sdio: add rx bitrate reporting ath9k * improvements to AR9002 calibration logic carl9170 * remove buggy P2P_GO support
This commit is contained in:
commit
7f65f6118a
@ -96,6 +96,17 @@ Optional properties:
|
||||
- qcom,coexist-gpio-pin : gpio pin number information to support coex
|
||||
which will be used by wifi firmware.
|
||||
|
||||
* Subnodes
|
||||
The ath10k wifi node can contain one optional firmware subnode.
|
||||
Firmware subnode is needed when the platform does not have TustZone.
|
||||
The firmware subnode must have:
|
||||
|
||||
- iommus:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: A list of phandle and IOMMU specifier pairs.
|
||||
|
||||
|
||||
Example (to supply PCI based wifi block details):
|
||||
|
||||
In this example, the node is defined as child node of the PCI controller.
|
||||
@ -196,4 +207,7 @@ wifi@18000000 {
|
||||
memory-region = <&wifi_msa_mem>;
|
||||
iommus = <&apps_smmu 0x0040 0x1>;
|
||||
qcom,msa-fixed-perm;
|
||||
wifi-firmware {
|
||||
iommus = <&apps_iommu 0xc22 0x1>;
|
||||
};
|
||||
};
|
||||
|
@ -380,6 +380,7 @@ static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 l
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to write to the device\n");
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -419,7 +419,7 @@ struct ce_pipe_config {
|
||||
#define PIPEDIR_INOUT 3 /* bidirectional */
|
||||
|
||||
/* Establish a mapping between a service/direction and a pipe. */
|
||||
struct service_to_pipe {
|
||||
struct ce_service_to_pipe {
|
||||
__le32 service_id;
|
||||
__le32 pipedir;
|
||||
__le32 pipenum;
|
||||
|
@ -190,6 +190,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.uart_pin_workaround = true,
|
||||
.tx_stats_over_pktlog = false,
|
||||
.bmi_large_size_download = true,
|
||||
.supports_peer_stats_info = true,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_2_1_VERSION,
|
||||
@ -725,10 +726,10 @@ static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
|
||||
param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
|
||||
|
||||
/* Alternate credit size of 1544 as used by SDIO firmware is
|
||||
* not big enough for mac80211 / native wifi frames. disable it
|
||||
*/
|
||||
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
||||
if (mode == ATH10K_FIRMWARE_MODE_NORMAL)
|
||||
param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
||||
else
|
||||
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
|
||||
|
||||
if (mode == ATH10K_FIRMWARE_MODE_UTF)
|
||||
param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
|
||||
@ -2714,7 +2715,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_hif_swap_mailbox(ar);
|
||||
status = ath10k_hif_start_post(ar);
|
||||
if (status) {
|
||||
ath10k_err(ar, "failed to swap mailbox: %d\n", status);
|
||||
goto err_hif_stop;
|
||||
@ -3277,6 +3278,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
init_completion(&ar->thermal.wmi_sync);
|
||||
init_completion(&ar->bss_survey_done);
|
||||
init_completion(&ar->peer_delete_done);
|
||||
init_completion(&ar->peer_stats_info_complete);
|
||||
|
||||
INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
|
||||
|
||||
@ -3288,6 +3290,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
if (!ar->workqueue_aux)
|
||||
goto err_free_wq;
|
||||
|
||||
ar->workqueue_tx_complete =
|
||||
create_singlethread_workqueue("ath10k_tx_complete_wq");
|
||||
if (!ar->workqueue_tx_complete)
|
||||
goto err_free_aux_wq;
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
mutex_init(&ar->dump_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
@ -3315,7 +3322,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
|
||||
ret = ath10k_coredump_create(ar);
|
||||
if (ret)
|
||||
goto err_free_aux_wq;
|
||||
goto err_free_tx_complete;
|
||||
|
||||
ret = ath10k_debug_create(ar);
|
||||
if (ret)
|
||||
@ -3325,12 +3332,12 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
|
||||
err_free_coredump:
|
||||
ath10k_coredump_destroy(ar);
|
||||
|
||||
err_free_tx_complete:
|
||||
destroy_workqueue(ar->workqueue_tx_complete);
|
||||
err_free_aux_wq:
|
||||
destroy_workqueue(ar->workqueue_aux);
|
||||
err_free_wq:
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
err_free_mac:
|
||||
ath10k_mac_destroy(ar);
|
||||
|
||||
@ -3346,6 +3353,9 @@ void ath10k_core_destroy(struct ath10k *ar)
|
||||
flush_workqueue(ar->workqueue_aux);
|
||||
destroy_workqueue(ar->workqueue_aux);
|
||||
|
||||
flush_workqueue(ar->workqueue_tx_complete);
|
||||
destroy_workqueue(ar->workqueue_tx_complete);
|
||||
|
||||
ath10k_debug_destroy(ar);
|
||||
ath10k_coredump_destroy(ar);
|
||||
ath10k_htt_tx_destroy(&ar->htt);
|
||||
|
@ -149,6 +149,26 @@ static inline u32 host_interest_item_address(u32 item_offset)
|
||||
return QCA988X_HOST_INTEREST_ADDRESS + item_offset;
|
||||
}
|
||||
|
||||
enum ath10k_phy_mode {
|
||||
ATH10K_PHY_MODE_LEGACY = 0,
|
||||
ATH10K_PHY_MODE_HT = 1,
|
||||
ATH10K_PHY_MODE_VHT = 2,
|
||||
};
|
||||
|
||||
/* Data rate 100KBPS based on IE Index */
|
||||
struct ath10k_index_ht_data_rate_type {
|
||||
u8 beacon_rate_index;
|
||||
u16 supported_rate[4];
|
||||
};
|
||||
|
||||
/* Data rate 100KBPS based on IE Index */
|
||||
struct ath10k_index_vht_data_rate_type {
|
||||
u8 beacon_rate_index;
|
||||
u16 supported_VHT80_rate[2];
|
||||
u16 supported_VHT40_rate[2];
|
||||
u16 supported_VHT20_rate[2];
|
||||
};
|
||||
|
||||
struct ath10k_bmi {
|
||||
bool done_sent;
|
||||
};
|
||||
@ -500,8 +520,14 @@ struct ath10k_sta {
|
||||
u16 peer_id;
|
||||
struct rate_info txrate;
|
||||
struct ieee80211_tx_info tx_info;
|
||||
u32 tx_retries;
|
||||
u32 tx_failed;
|
||||
u32 last_tx_bitrate;
|
||||
|
||||
u32 rx_rate_code;
|
||||
u32 rx_bitrate_kbps;
|
||||
u32 tx_rate_code;
|
||||
u32 tx_bitrate_kbps;
|
||||
struct work_struct update_wk;
|
||||
u64 rx_duration;
|
||||
struct ath10k_htt_tx_stats *tx_stats;
|
||||
@ -949,6 +975,11 @@ struct ath10k {
|
||||
struct ieee80211_hw *hw;
|
||||
struct ieee80211_ops *ops;
|
||||
struct device *dev;
|
||||
struct msa_region {
|
||||
dma_addr_t paddr;
|
||||
u32 mem_size;
|
||||
void *vaddr;
|
||||
} msa;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
||||
enum ath10k_hw_rev hw_rev;
|
||||
@ -1087,11 +1118,12 @@ struct ath10k {
|
||||
int last_wmi_vdev_start_status;
|
||||
struct completion vdev_setup_done;
|
||||
struct completion vdev_delete_done;
|
||||
struct completion peer_stats_info_complete;
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
/* Auxiliary workqueue */
|
||||
struct workqueue_struct *workqueue_aux;
|
||||
|
||||
struct workqueue_struct *workqueue_tx_complete;
|
||||
/* prevents concurrent FW reconfiguration */
|
||||
struct mutex conf_mutex;
|
||||
|
||||
@ -1132,6 +1164,8 @@ struct ath10k {
|
||||
|
||||
struct work_struct register_work;
|
||||
struct work_struct restart_work;
|
||||
struct work_struct bundle_tx_work;
|
||||
struct work_struct tx_complete_work;
|
||||
|
||||
/* cycle count is reported twice for each visited channel during scan.
|
||||
* access protected by data_lock
|
||||
|
@ -349,7 +349,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
{
|
||||
unsigned long timeout, time_left;
|
||||
int ret;
|
||||
@ -778,7 +778,7 @@ static ssize_t ath10k_mem_value_read(struct file *file,
|
||||
|
||||
ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n",
|
||||
ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
|
||||
(u32)(*ppos), ret);
|
||||
goto exit;
|
||||
}
|
||||
|
@ -125,6 +125,9 @@ static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar)
|
||||
{
|
||||
return ar->debug.enable_extd_tx_stats;
|
||||
}
|
||||
|
||||
int ath10k_debug_fw_stats_request(struct ath10k *ar);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ath10k_debug_start(struct ath10k *ar)
|
||||
@ -192,6 +195,11 @@ static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
|
||||
|
||||
#define ath10k_debug_get_et_strings NULL
|
||||
|
@ -54,7 +54,7 @@ struct ath10k_hif_ops {
|
||||
*/
|
||||
void (*stop)(struct ath10k *ar);
|
||||
|
||||
int (*swap_mailbox)(struct ath10k *ar);
|
||||
int (*start_post)(struct ath10k *ar);
|
||||
|
||||
int (*get_htt_tx_complete)(struct ath10k *ar);
|
||||
|
||||
@ -139,10 +139,10 @@ static inline void ath10k_hif_stop(struct ath10k *ar)
|
||||
return ar->hif.ops->stop(ar);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_swap_mailbox(struct ath10k *ar)
|
||||
static inline int ath10k_hif_start_post(struct ath10k *ar)
|
||||
{
|
||||
if (ar->hif.ops->swap_mailbox)
|
||||
return ar->hif.ops->swap_mailbox(ar);
|
||||
if (ar->hif.ops->start_post)
|
||||
return ar->hif.ops->start_post(ar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -170,7 +170,8 @@ static inline void ath10k_hif_get_default_pipe(struct ath10k *ar,
|
||||
static inline void ath10k_hif_send_complete_check(struct ath10k *ar,
|
||||
u8 pipe_id, int force)
|
||||
{
|
||||
ar->hif.ops->send_complete_check(ar, pipe_id, force);
|
||||
if (ar->hif.ops->send_complete_check)
|
||||
ar->hif.ops->send_complete_check(ar, pipe_id, force);
|
||||
}
|
||||
|
||||
static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
|
||||
|
@ -51,10 +51,12 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k *ar = ep->htc->ar;
|
||||
struct ath10k_htc_hdr *hdr;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %pK\n", __func__,
|
||||
ep->eid, skb);
|
||||
|
||||
hdr = (struct ath10k_htc_hdr *)skb->data;
|
||||
ath10k_htc_restore_tx_skb(ep->htc, skb);
|
||||
|
||||
if (!ep->ep_ops.ep_tx_complete) {
|
||||
@ -63,6 +65,11 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdr->flags & ATH10K_HTC_FLAG_SEND_BUNDLE) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htc_notify_tx_completion);
|
||||
@ -78,7 +85,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
|
||||
hdr->eid = ep->eid;
|
||||
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
|
||||
hdr->flags = 0;
|
||||
if (ep->tx_credit_flow_enabled)
|
||||
if (ep->tx_credit_flow_enabled && !ep->bundle_tx)
|
||||
hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
|
||||
|
||||
spin_lock_bh(&ep->htc->tx_lock);
|
||||
@ -86,6 +93,63 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
|
||||
spin_unlock_bh(&ep->htc->tx_lock);
|
||||
}
|
||||
|
||||
static int ath10k_htc_consume_credit(struct ath10k_htc_ep *ep,
|
||||
unsigned int len,
|
||||
bool consume)
|
||||
{
|
||||
struct ath10k_htc *htc = ep->htc;
|
||||
struct ath10k *ar = htc->ar;
|
||||
enum ath10k_htc_ep_id eid = ep->eid;
|
||||
int credits, ret = 0;
|
||||
|
||||
if (!ep->tx_credit_flow_enabled)
|
||||
return 0;
|
||||
|
||||
credits = DIV_ROUND_UP(len, ep->tx_credit_size);
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
|
||||
if (ep->tx_credits < credits) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc insufficient credits ep %d required %d available %d consume %d\n",
|
||||
eid, credits, ep->tx_credits, consume);
|
||||
ret = -EAGAIN;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (consume) {
|
||||
ep->tx_credits -= credits;
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc ep %d consumed %d credits total %d\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_htc_release_credit(struct ath10k_htc_ep *ep, unsigned int len)
|
||||
{
|
||||
struct ath10k_htc *htc = ep->htc;
|
||||
struct ath10k *ar = htc->ar;
|
||||
enum ath10k_htc_ep_id eid = ep->eid;
|
||||
int credits;
|
||||
|
||||
if (!ep->tx_credit_flow_enabled)
|
||||
return;
|
||||
|
||||
credits = DIV_ROUND_UP(len, ep->tx_credit_size);
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
ep->tx_credits += credits;
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc ep %d reverted %d credits back total %d\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
|
||||
if (ep->ep_ops.ep_tx_credits)
|
||||
ep->ep_ops.ep_tx_credits(htc->ar);
|
||||
}
|
||||
|
||||
int ath10k_htc_send(struct ath10k_htc *htc,
|
||||
enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *skb)
|
||||
@ -95,8 +159,8 @@ int ath10k_htc_send(struct ath10k_htc *htc,
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
|
||||
struct ath10k_hif_sg_item sg_item;
|
||||
struct device *dev = htc->ar->dev;
|
||||
int credits = 0;
|
||||
int ret;
|
||||
unsigned int skb_len;
|
||||
|
||||
if (htc->ar->state == ATH10K_STATE_WEDGED)
|
||||
return -ECOMM;
|
||||
@ -108,23 +172,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,
|
||||
|
||||
skb_push(skb, sizeof(struct ath10k_htc_hdr));
|
||||
|
||||
if (ep->tx_credit_flow_enabled) {
|
||||
credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
if (ep->tx_credits < credits) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc insufficient credits ep %d required %d available %d\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
ret = -EAGAIN;
|
||||
goto err_pull;
|
||||
}
|
||||
ep->tx_credits -= credits;
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc ep %d consumed %d credits (total %d)\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
}
|
||||
skb_len = skb->len;
|
||||
ret = ath10k_htc_consume_credit(ep, skb_len, true);
|
||||
if (ret)
|
||||
goto err_pull;
|
||||
|
||||
ath10k_htc_prepare_tx_skb(ep, skb);
|
||||
|
||||
@ -155,17 +206,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
|
||||
if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
|
||||
dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
|
||||
err_credits:
|
||||
if (ep->tx_credit_flow_enabled) {
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
ep->tx_credits += credits;
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc ep %d reverted %d credits back (total %d)\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
|
||||
if (ep->ep_ops.ep_tx_credits)
|
||||
ep->ep_ops.ep_tx_credits(htc->ar);
|
||||
}
|
||||
ath10k_htc_release_credit(ep, skb_len);
|
||||
err_pull:
|
||||
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
|
||||
return ret;
|
||||
@ -581,6 +622,278 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
|
||||
return allocation;
|
||||
}
|
||||
|
||||
static int ath10k_htc_send_bundle(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *bundle_skb,
|
||||
struct sk_buff_head *tx_save_head)
|
||||
{
|
||||
struct ath10k_hif_sg_item sg_item;
|
||||
struct ath10k_htc *htc = ep->htc;
|
||||
struct ath10k *ar = htc->ar;
|
||||
struct sk_buff *skb;
|
||||
int ret, cn = 0;
|
||||
unsigned int skb_len;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle skb len %d\n", bundle_skb->len);
|
||||
skb_len = bundle_skb->len;
|
||||
ret = ath10k_htc_consume_credit(ep, skb_len, true);
|
||||
|
||||
if (!ret) {
|
||||
sg_item.transfer_id = ep->eid;
|
||||
sg_item.transfer_context = bundle_skb;
|
||||
sg_item.vaddr = bundle_skb->data;
|
||||
sg_item.len = bundle_skb->len;
|
||||
|
||||
ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1);
|
||||
if (ret)
|
||||
ath10k_htc_release_credit(ep, skb_len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_kfree_skb_any(bundle_skb);
|
||||
|
||||
for (cn = 0; (skb = skb_dequeue_tail(tx_save_head)); cn++) {
|
||||
if (ret) {
|
||||
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
|
||||
skb_queue_head(&ep->tx_req_head, skb);
|
||||
} else {
|
||||
skb_queue_tail(&ep->tx_complete_head, skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
queue_work(ar->workqueue_tx_complete, &ar->tx_complete_work);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"bundle tx status %d eid %d req count %d count %d len %d\n",
|
||||
ret, ep->eid, skb_queue_len(&ep->tx_req_head), cn, bundle_skb->len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_htc_send_one_skb(struct ath10k_htc_ep *ep, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htc *htc = ep->htc;
|
||||
struct ath10k *ar = htc->ar;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_htc_send(htc, ep->eid, skb);
|
||||
|
||||
if (ret)
|
||||
skb_queue_head(&ep->tx_req_head, skb);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "tx one status %d eid %d len %d pending count %d\n",
|
||||
ret, ep->eid, skb->len, skb_queue_len(&ep->tx_req_head));
|
||||
}
|
||||
|
||||
static int ath10k_htc_send_bundle_skbs(struct ath10k_htc_ep *ep)
|
||||
{
|
||||
struct ath10k_htc *htc = ep->htc;
|
||||
struct sk_buff *bundle_skb, *skb;
|
||||
struct sk_buff_head tx_save_head;
|
||||
struct ath10k_htc_hdr *hdr;
|
||||
u8 *bundle_buf;
|
||||
int ret = 0, credit_pad, credit_remainder, trans_len, bundles_left = 0;
|
||||
|
||||
if (htc->ar->state == ATH10K_STATE_WEDGED)
|
||||
return -ECOMM;
|
||||
|
||||
if (ep->tx_credit_flow_enabled &&
|
||||
ep->tx_credits < ATH10K_MIN_CREDIT_PER_HTC_TX_BUNDLE)
|
||||
return 0;
|
||||
|
||||
bundles_left = ATH10K_MAX_MSG_PER_HTC_TX_BUNDLE * ep->tx_credit_size;
|
||||
bundle_skb = dev_alloc_skb(bundles_left);
|
||||
|
||||
if (!bundle_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
bundle_buf = bundle_skb->data;
|
||||
skb_queue_head_init(&tx_save_head);
|
||||
|
||||
while (true) {
|
||||
skb = skb_dequeue(&ep->tx_req_head);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
credit_pad = 0;
|
||||
trans_len = skb->len + sizeof(*hdr);
|
||||
credit_remainder = trans_len % ep->tx_credit_size;
|
||||
|
||||
if (credit_remainder != 0) {
|
||||
credit_pad = ep->tx_credit_size - credit_remainder;
|
||||
trans_len += credit_pad;
|
||||
}
|
||||
|
||||
ret = ath10k_htc_consume_credit(ep,
|
||||
bundle_buf + trans_len - bundle_skb->data,
|
||||
false);
|
||||
if (ret) {
|
||||
skb_queue_head(&ep->tx_req_head, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bundles_left < trans_len) {
|
||||
bundle_skb->len = bundle_buf - bundle_skb->data;
|
||||
ret = ath10k_htc_send_bundle(ep, bundle_skb, &tx_save_head);
|
||||
|
||||
if (ret) {
|
||||
skb_queue_head(&ep->tx_req_head, skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (skb_queue_len(&ep->tx_req_head) == 0) {
|
||||
ath10k_htc_send_one_skb(ep, skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ep->tx_credit_flow_enabled &&
|
||||
ep->tx_credits < ATH10K_MIN_CREDIT_PER_HTC_TX_BUNDLE) {
|
||||
skb_queue_head(&ep->tx_req_head, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bundles_left =
|
||||
ATH10K_MAX_MSG_PER_HTC_TX_BUNDLE * ep->tx_credit_size;
|
||||
bundle_skb = dev_alloc_skb(bundles_left);
|
||||
|
||||
if (!bundle_skb) {
|
||||
skb_queue_head(&ep->tx_req_head, skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
bundle_buf = bundle_skb->data;
|
||||
skb_queue_head_init(&tx_save_head);
|
||||
}
|
||||
|
||||
skb_push(skb, sizeof(struct ath10k_htc_hdr));
|
||||
ath10k_htc_prepare_tx_skb(ep, skb);
|
||||
|
||||
memcpy(bundle_buf, skb->data, skb->len);
|
||||
hdr = (struct ath10k_htc_hdr *)bundle_buf;
|
||||
hdr->flags |= ATH10K_HTC_FLAG_SEND_BUNDLE;
|
||||
hdr->pad_len = __cpu_to_le16(credit_pad);
|
||||
bundle_buf += trans_len;
|
||||
bundles_left -= trans_len;
|
||||
skb_queue_tail(&tx_save_head, skb);
|
||||
}
|
||||
|
||||
if (bundle_buf != bundle_skb->data) {
|
||||
bundle_skb->len = bundle_buf - bundle_skb->data;
|
||||
ret = ath10k_htc_send_bundle(ep, bundle_skb, &tx_save_head);
|
||||
} else {
|
||||
dev_kfree_skb_any(bundle_skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_htc_bundle_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, bundle_tx_work);
|
||||
struct ath10k_htc_ep *ep;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
|
||||
ep = &ar->htc.endpoint[i];
|
||||
|
||||
if (!ep->bundle_tx)
|
||||
continue;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle tx work eid %d count %d\n",
|
||||
ep->eid, skb_queue_len(&ep->tx_req_head));
|
||||
|
||||
if (skb_queue_len(&ep->tx_req_head) >=
|
||||
ATH10K_MIN_MSG_PER_HTC_TX_BUNDLE) {
|
||||
ath10k_htc_send_bundle_skbs(ep);
|
||||
} else {
|
||||
skb = skb_dequeue(&ep->tx_req_head);
|
||||
|
||||
if (!skb)
|
||||
continue;
|
||||
ath10k_htc_send_one_skb(ep, skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_htc_tx_complete_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, tx_complete_work);
|
||||
struct ath10k_htc_ep *ep;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
|
||||
ep = &ar->htc.endpoint[i];
|
||||
eid = ep->eid;
|
||||
if (ep->bundle_tx && eid == ar->htt.eid) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle tx complete eid %d pending complete count%d\n",
|
||||
ep->eid, skb_queue_len(&ep->tx_complete_head));
|
||||
|
||||
while (true) {
|
||||
skb = skb_dequeue(&ep->tx_complete_head);
|
||||
if (!skb)
|
||||
break;
|
||||
ath10k_htc_notify_tx_completion(ep, skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ath10k_htc_send_hl(struct ath10k_htc *htc,
|
||||
enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
|
||||
struct ath10k *ar = htc->ar;
|
||||
|
||||
if (sizeof(struct ath10k_htc_hdr) + skb->len > ep->tx_credit_size) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "tx exceed max len %d\n", skb->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "htc send hl eid %d bundle %d tx count %d len %d\n",
|
||||
eid, ep->bundle_tx, skb_queue_len(&ep->tx_req_head), skb->len);
|
||||
|
||||
if (ep->bundle_tx) {
|
||||
skb_queue_tail(&ep->tx_req_head, skb);
|
||||
queue_work(ar->workqueue, &ar->bundle_tx_work);
|
||||
return 0;
|
||||
} else {
|
||||
return ath10k_htc_send(htc, eid, skb);
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep)
|
||||
{
|
||||
if (ep->htc->max_msgs_per_htc_bundle >= ATH10K_MIN_MSG_PER_HTC_TX_BUNDLE &&
|
||||
!ep->bundle_tx) {
|
||||
ep->bundle_tx = true;
|
||||
skb_queue_head_init(&ep->tx_req_head);
|
||||
skb_queue_head_init(&ep->tx_complete_head);
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_htc_stop_hl(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htc_ep *ep;
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&ar->bundle_tx_work);
|
||||
cancel_work_sync(&ar->tx_complete_work);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
|
||||
ep = &ar->htc.endpoint[i];
|
||||
|
||||
if (!ep->bundle_tx)
|
||||
continue;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "stop tx work eid %d count %d\n",
|
||||
ep->eid, skb_queue_len(&ep->tx_req_head));
|
||||
|
||||
skb_queue_purge(&ep->tx_req_head);
|
||||
}
|
||||
}
|
||||
|
||||
int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
{
|
||||
struct ath10k *ar = htc->ar;
|
||||
@ -649,14 +962,21 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
*/
|
||||
if (htc->control_resp_len >=
|
||||
sizeof(msg->hdr) + sizeof(msg->ready_ext)) {
|
||||
htc->alt_data_credit_size =
|
||||
__le16_to_cpu(msg->ready_ext.reserved) &
|
||||
ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK;
|
||||
htc->max_msgs_per_htc_bundle =
|
||||
min_t(u8, msg->ready_ext.max_msgs_per_htc_bundle,
|
||||
HTC_HOST_MAX_MSG_PER_RX_BUNDLE);
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"Extended ready message. RX bundle size: %d\n",
|
||||
htc->max_msgs_per_htc_bundle);
|
||||
"Extended ready message RX bundle size %d alt size %d\n",
|
||||
htc->max_msgs_per_htc_bundle,
|
||||
htc->alt_data_credit_size);
|
||||
}
|
||||
|
||||
INIT_WORK(&ar->bundle_tx_work, ath10k_htc_bundle_tx_work);
|
||||
INIT_WORK(&ar->tx_complete_work, ath10k_htc_tx_complete_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -801,6 +1121,11 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
ep->max_tx_queue_depth = conn_req->max_send_queue_depth;
|
||||
ep->max_ep_message_len = __le16_to_cpu(resp_msg->max_msg_size);
|
||||
ep->tx_credits = tx_alloc;
|
||||
ep->tx_credit_size = htc->target_credit_size;
|
||||
|
||||
if (conn_req->service_id == ATH10K_HTC_SVC_ID_HTT_DATA_MSG &&
|
||||
htc->alt_data_credit_size != 0)
|
||||
ep->tx_credit_size = htc->alt_data_credit_size;
|
||||
|
||||
/* copy all the callbacks */
|
||||
ep->ep_ops = conn_req->ep_ops;
|
||||
|
@ -83,8 +83,14 @@ struct ath10k_htc_hdr {
|
||||
u8 seq_no; /* for tx */
|
||||
u8 control_byte1;
|
||||
} __packed;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
union {
|
||||
__le16 pad_len;
|
||||
struct {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum ath10k_ath10k_htc_msg_id {
|
||||
@ -113,6 +119,8 @@ enum ath10k_htc_conn_flags {
|
||||
#define ATH10K_HTC_CONN_FLAGS_RECV_ALLOC_LSB 8
|
||||
};
|
||||
|
||||
#define ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK 0xFFF
|
||||
|
||||
enum ath10k_htc_conn_svc_status {
|
||||
ATH10K_HTC_CONN_SVC_STATUS_SUCCESS = 0,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NOT_FOUND = 1,
|
||||
@ -121,6 +129,10 @@ enum ath10k_htc_conn_svc_status {
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NO_MORE_EP = 4
|
||||
};
|
||||
|
||||
#define ATH10K_MAX_MSG_PER_HTC_TX_BUNDLE 32
|
||||
#define ATH10K_MIN_MSG_PER_HTC_TX_BUNDLE 2
|
||||
#define ATH10K_MIN_CREDIT_PER_HTC_TX_BUNDLE 2
|
||||
|
||||
enum ath10k_htc_setup_complete_flags {
|
||||
ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN = 1
|
||||
};
|
||||
@ -145,8 +157,14 @@ struct ath10k_htc_ready_extended {
|
||||
struct ath10k_htc_ready base;
|
||||
u8 htc_version; /* @enum ath10k_htc_version */
|
||||
u8 max_msgs_per_htc_bundle;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
union {
|
||||
__le16 reserved;
|
||||
struct {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_conn_svc {
|
||||
@ -353,7 +371,12 @@ struct ath10k_htc_ep {
|
||||
|
||||
u8 seq_no; /* for debugging */
|
||||
int tx_credits;
|
||||
int tx_credit_size;
|
||||
bool tx_credit_flow_enabled;
|
||||
bool bundle_tx;
|
||||
struct sk_buff_head tx_req_head;
|
||||
struct sk_buff_head tx_complete_head;
|
||||
|
||||
};
|
||||
|
||||
struct ath10k_htc_svc_tx_credits {
|
||||
@ -378,10 +401,12 @@ struct ath10k_htc {
|
||||
int total_transmit_credits;
|
||||
int target_credit_size;
|
||||
u8 max_msgs_per_htc_bundle;
|
||||
int alt_data_credit_size;
|
||||
};
|
||||
|
||||
int ath10k_htc_init(struct ath10k *ar);
|
||||
int ath10k_htc_wait_target(struct ath10k_htc *htc);
|
||||
void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep);
|
||||
int ath10k_htc_start(struct ath10k_htc *htc);
|
||||
int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
struct ath10k_htc_svc_conn_req *conn_req,
|
||||
@ -391,6 +416,10 @@ void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
|
||||
bool enable);
|
||||
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *packet);
|
||||
void ath10k_htc_stop_hl(struct ath10k *ar);
|
||||
|
||||
int ath10k_htc_send_hl(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *packet);
|
||||
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
|
||||
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
|
@ -135,6 +135,8 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ath10k_htc_ep *ep;
|
||||
int status;
|
||||
|
||||
memset(&conn_req, 0, sizeof(conn_req));
|
||||
@ -142,6 +144,7 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
|
||||
conn_req.ep_ops.ep_tx_complete = ath10k_htt_htc_tx_complete;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htt_htc_t2h_msg_handler;
|
||||
conn_req.ep_ops.ep_tx_credits = ath10k_htt_op_ep_tx_credits;
|
||||
|
||||
/* connect to control service */
|
||||
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
|
||||
@ -154,6 +157,11 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
|
||||
htt->eid = conn_resp.eid;
|
||||
|
||||
if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
|
||||
ep = &ar->htc.endpoint[htt->eid];
|
||||
ath10k_htc_setup_tx_req(ep);
|
||||
}
|
||||
|
||||
htt->disable_tx_comp = ath10k_hif_get_htt_tx_complete(htt->ar);
|
||||
if (htt->disable_tx_comp)
|
||||
ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
|
||||
|
@ -2032,6 +2032,9 @@ struct ath10k_htt {
|
||||
const struct ath10k_htt_tx_ops *tx_ops;
|
||||
const struct ath10k_htt_rx_ops *rx_ops;
|
||||
bool disable_tx_comp;
|
||||
bool bundle_tx;
|
||||
struct sk_buff_head tx_req_head;
|
||||
struct sk_buff_head tx_complete_head;
|
||||
};
|
||||
|
||||
struct ath10k_htt_tx_ops {
|
||||
@ -2046,6 +2049,7 @@ struct ath10k_htt_tx_ops {
|
||||
int (*htt_h2t_aggr_cfg_msg)(struct ath10k_htt *htt,
|
||||
u8 max_subfrms_ampdu,
|
||||
u8 max_subfrms_amsdu);
|
||||
void (*htt_flush_tx)(struct ath10k_htt *htt);
|
||||
};
|
||||
|
||||
static inline int ath10k_htt_send_rx_ring_cfg(struct ath10k_htt *htt)
|
||||
@ -2085,6 +2089,12 @@ static inline int ath10k_htt_tx(struct ath10k_htt *htt,
|
||||
return htt->tx_ops->htt_tx(htt, txmode, msdu);
|
||||
}
|
||||
|
||||
static inline void ath10k_htt_flush_tx(struct ath10k_htt *htt)
|
||||
{
|
||||
if (htt->tx_ops->htt_flush_tx)
|
||||
htt->tx_ops->htt_flush_tx(htt);
|
||||
}
|
||||
|
||||
static inline int ath10k_htt_alloc_txbuff(struct ath10k_htt *htt)
|
||||
{
|
||||
if (!htt->tx_ops->htt_alloc_txbuff)
|
||||
@ -2278,6 +2288,7 @@ int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
|
||||
__le16 fetch_seq_num,
|
||||
struct htt_tx_fetch_record *records,
|
||||
size_t num_records);
|
||||
void ath10k_htt_op_ep_tx_credits(struct ath10k *ar);
|
||||
|
||||
void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq);
|
||||
|
@ -3574,6 +3574,13 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
|
||||
ieee80211_tx_rate_update(ar->hw, sta, &arsta->tx_info);
|
||||
}
|
||||
|
||||
if (ar->htt.disable_tx_comp) {
|
||||
arsta->tx_retries += peer_stats->retry_pkts;
|
||||
arsta->tx_failed += peer_stats->failed_pkts;
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d tx failed %d\n",
|
||||
arsta->tx_retries, arsta->tx_failed);
|
||||
}
|
||||
|
||||
if (ath10k_debug_is_extd_tx_stats_enabled(ar))
|
||||
ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats,
|
||||
rate_idx);
|
||||
@ -3919,6 +3926,7 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt credit total %d\n",
|
||||
ep->tx_credits);
|
||||
ep->ep_ops.ep_tx_credits(htc->ar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -529,9 +529,15 @@ void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
|
||||
htt->tx_mem_allocated = false;
|
||||
}
|
||||
|
||||
static void ath10k_htt_flush_tx_queue(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htc_stop_hl(htt->ar);
|
||||
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_stop(struct ath10k_htt *htt)
|
||||
{
|
||||
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
|
||||
ath10k_htt_flush_tx_queue(htt);
|
||||
idr_destroy(&htt->pending_tx);
|
||||
}
|
||||
|
||||
@ -541,6 +547,11 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
ath10k_htt_tx_destroy(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_op_ep_tx_credits(struct ath10k *ar)
|
||||
{
|
||||
queue_work(ar->workqueue, &ar->bundle_tx_work);
|
||||
}
|
||||
|
||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
@ -1379,7 +1390,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
|
||||
*/
|
||||
tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID);
|
||||
|
||||
res = ath10k_htc_send(&htt->ar->htc, htt->eid, msdu);
|
||||
res = ath10k_htc_send_hl(&htt->ar->htc, htt->eid, msdu);
|
||||
|
||||
out:
|
||||
return res;
|
||||
@ -1819,6 +1830,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_hl = {
|
||||
.htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32,
|
||||
.htt_tx = ath10k_htt_tx_hl,
|
||||
.htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_32,
|
||||
.htt_flush_tx = ath10k_htt_flush_tx_queue,
|
||||
};
|
||||
|
||||
void ath10k_htt_set_tx_ops(struct ath10k_htt *htt)
|
||||
|
@ -623,6 +623,9 @@ struct ath10k_hw_params {
|
||||
|
||||
/* tx stats support over pktlog */
|
||||
bool tx_stats_over_pktlog;
|
||||
|
||||
/* provides bitrates for sta_statistics using WMI_TLV_PEER_STATS_INFO_EVENTID */
|
||||
bool supports_peer_stats_info;
|
||||
};
|
||||
|
||||
struct htt_rx_desc;
|
||||
|
@ -2959,6 +2959,11 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
||||
arvif->aid = bss_conf->aid;
|
||||
ether_addr_copy(arvif->bssid, bss_conf->bssid);
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar,
|
||||
ar->wmi.pdev_param->peer_stats_info_enable, 1);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to enable peer stats info: %d\n", ret);
|
||||
|
||||
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set vdev %d up: %d\n",
|
||||
@ -4529,17 +4534,18 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
|
||||
static bool ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
|
||||
{
|
||||
/* It is not clear that allowing gaps in chainmask
|
||||
* is helpful. Probably it will not do what user
|
||||
* is hoping for, so warn in that case.
|
||||
*/
|
||||
if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0)
|
||||
return;
|
||||
return true;
|
||||
|
||||
ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n",
|
||||
ath10k_warn(ar, "mac %s antenna chainmask is invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n",
|
||||
dbg, cm);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
|
||||
@ -4722,11 +4728,15 @@ static void ath10k_mac_setup_ht_vht_cap(struct ath10k *ar)
|
||||
static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
|
||||
{
|
||||
int ret;
|
||||
bool is_valid_tx_chain_mask, is_valid_rx_chain_mask;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ath10k_check_chain_mask(ar, tx_ant, "tx");
|
||||
ath10k_check_chain_mask(ar, rx_ant, "rx");
|
||||
is_valid_tx_chain_mask = ath10k_check_chain_mask(ar, tx_ant, "tx");
|
||||
is_valid_rx_chain_mask = ath10k_check_chain_mask(ar, rx_ant, "rx");
|
||||
|
||||
if (!is_valid_tx_chain_mask || !is_valid_rx_chain_mask)
|
||||
return -EINVAL;
|
||||
|
||||
ar->cfg_tx_chainmask = tx_ant;
|
||||
ar->cfg_rx_chainmask = rx_ant;
|
||||
@ -7224,6 +7234,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
ath10k_wmi_peer_flush(ar, arvif->vdev_id,
|
||||
arvif->bssid, bitmap);
|
||||
}
|
||||
ath10k_htt_flush_tx(&ar->htt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -8294,6 +8305,215 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
|
||||
peer->removed = true;
|
||||
}
|
||||
|
||||
/* HT MCS parameters with Nss = 1 */
|
||||
static const struct ath10k_index_ht_data_rate_type supported_ht_mcs_rate_nss1[] = {
|
||||
/* MCS L20 L40 S20 S40 */
|
||||
{0, { 65, 135, 72, 150} },
|
||||
{1, { 130, 270, 144, 300} },
|
||||
{2, { 195, 405, 217, 450} },
|
||||
{3, { 260, 540, 289, 600} },
|
||||
{4, { 390, 810, 433, 900} },
|
||||
{5, { 520, 1080, 578, 1200} },
|
||||
{6, { 585, 1215, 650, 1350} },
|
||||
{7, { 650, 1350, 722, 1500} }
|
||||
};
|
||||
|
||||
/* HT MCS parameters with Nss = 2 */
|
||||
static const struct ath10k_index_ht_data_rate_type supported_ht_mcs_rate_nss2[] = {
|
||||
/* MCS L20 L40 S20 S40 */
|
||||
{0, {130, 270, 144, 300} },
|
||||
{1, {260, 540, 289, 600} },
|
||||
{2, {390, 810, 433, 900} },
|
||||
{3, {520, 1080, 578, 1200} },
|
||||
{4, {780, 1620, 867, 1800} },
|
||||
{5, {1040, 2160, 1156, 2400} },
|
||||
{6, {1170, 2430, 1300, 2700} },
|
||||
{7, {1300, 2700, 1444, 3000} }
|
||||
};
|
||||
|
||||
/* MCS parameters with Nss = 1 */
|
||||
static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
|
||||
/* MCS L80 S80 L40 S40 L20 S20 */
|
||||
{0, {293, 325}, {135, 150}, {65, 72} },
|
||||
{1, {585, 650}, {270, 300}, {130, 144} },
|
||||
{2, {878, 975}, {405, 450}, {195, 217} },
|
||||
{3, {1170, 1300}, {540, 600}, {260, 289} },
|
||||
{4, {1755, 1950}, {810, 900}, {390, 433} },
|
||||
{5, {2340, 2600}, {1080, 1200}, {520, 578} },
|
||||
{6, {2633, 2925}, {1215, 1350}, {585, 650} },
|
||||
{7, {2925, 3250}, {1350, 1500}, {650, 722} },
|
||||
{8, {3510, 3900}, {1620, 1800}, {780, 867} },
|
||||
{9, {3900, 4333}, {1800, 2000}, {780, 867} }
|
||||
};
|
||||
|
||||
/*MCS parameters with Nss = 2 */
|
||||
static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
|
||||
/* MCS L80 S80 L40 S40 L20 S20 */
|
||||
{0, {585, 650}, {270, 300}, {130, 144} },
|
||||
{1, {1170, 1300}, {540, 600}, {260, 289} },
|
||||
{2, {1755, 1950}, {810, 900}, {390, 433} },
|
||||
{3, {2340, 2600}, {1080, 1200}, {520, 578} },
|
||||
{4, {3510, 3900}, {1620, 1800}, {780, 867} },
|
||||
{5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
|
||||
{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
|
||||
{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
|
||||
{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
|
||||
{9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
|
||||
};
|
||||
|
||||
static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs,
|
||||
u8 *flags, u8 *bw)
|
||||
{
|
||||
struct ath10k_index_ht_data_rate_type *mcs_rate;
|
||||
|
||||
mcs_rate = (struct ath10k_index_ht_data_rate_type *)
|
||||
((nss == 1) ? &supported_ht_mcs_rate_nss1 :
|
||||
&supported_ht_mcs_rate_nss2);
|
||||
|
||||
if (rate == mcs_rate[mcs].supported_rate[0]) {
|
||||
*bw = RATE_INFO_BW_20;
|
||||
} else if (rate == mcs_rate[mcs].supported_rate[1]) {
|
||||
*bw |= RATE_INFO_BW_40;
|
||||
} else if (rate == mcs_rate[mcs].supported_rate[2]) {
|
||||
*bw |= RATE_INFO_BW_20;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else if (rate == mcs_rate[mcs].supported_rate[3]) {
|
||||
*bw |= RATE_INFO_BW_40;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else {
|
||||
ath10k_warn(ar, "invalid ht params rate %d 100kbps nss %d mcs %d",
|
||||
rate, nss, mcs);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_get_rate_flags_vht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs,
|
||||
u8 *flags, u8 *bw)
|
||||
{
|
||||
struct ath10k_index_vht_data_rate_type *mcs_rate;
|
||||
|
||||
mcs_rate = (struct ath10k_index_vht_data_rate_type *)
|
||||
((nss == 1) ? &supported_vht_mcs_rate_nss1 :
|
||||
&supported_vht_mcs_rate_nss2);
|
||||
|
||||
if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
|
||||
*bw = RATE_INFO_BW_80;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
|
||||
*bw = RATE_INFO_BW_80;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
|
||||
*bw = RATE_INFO_BW_40;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
|
||||
*bw = RATE_INFO_BW_40;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
|
||||
*bw = RATE_INFO_BW_20;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
|
||||
*bw = RATE_INFO_BW_20;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else {
|
||||
ath10k_warn(ar, "invalid vht params rate %d 100kbps nss %d mcs %d",
|
||||
rate, nss, mcs);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_get_rate_flags(struct ath10k *ar, u32 rate,
|
||||
enum ath10k_phy_mode mode, u8 nss, u8 mcs,
|
||||
u8 *flags, u8 *bw)
|
||||
{
|
||||
if (mode == ATH10K_PHY_MODE_HT) {
|
||||
*flags = RATE_INFO_FLAGS_MCS;
|
||||
ath10k_mac_get_rate_flags_ht(ar, rate, nss, mcs, flags, bw);
|
||||
} else if (mode == ATH10K_PHY_MODE_VHT) {
|
||||
*flags = RATE_INFO_FLAGS_VHT_MCS;
|
||||
ath10k_mac_get_rate_flags_vht(ar, rate, nss, mcs, flags, bw);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_parse_bitrate(struct ath10k *ar, u32 rate_code,
|
||||
u32 bitrate_kbps, struct rate_info *rate)
|
||||
{
|
||||
enum ath10k_phy_mode mode = ATH10K_PHY_MODE_LEGACY;
|
||||
enum wmi_rate_preamble preamble = WMI_TLV_GET_HW_RC_PREAM_V1(rate_code);
|
||||
u8 nss = WMI_TLV_GET_HW_RC_NSS_V1(rate_code) + 1;
|
||||
u8 mcs = WMI_TLV_GET_HW_RC_RATE_V1(rate_code);
|
||||
u8 flags = 0, bw = 0;
|
||||
|
||||
if (preamble == WMI_RATE_PREAMBLE_HT)
|
||||
mode = ATH10K_PHY_MODE_HT;
|
||||
else if (preamble == WMI_RATE_PREAMBLE_VHT)
|
||||
mode = ATH10K_PHY_MODE_VHT;
|
||||
|
||||
ath10k_mac_get_rate_flags(ar, bitrate_kbps / 100, mode, nss, mcs, &flags, &bw);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
"mac parse bitrate preamble %d mode %d nss %d mcs %d flags %x bw %d\n",
|
||||
preamble, mode, nss, mcs, flags, bw);
|
||||
|
||||
rate->flags = flags;
|
||||
rate->bw = bw;
|
||||
rate->legacy = bitrate_kbps / 100;
|
||||
rate->nss = nss;
|
||||
rate->mcs = mcs;
|
||||
}
|
||||
|
||||
static void ath10k_mac_sta_get_peer_stats_info(struct ath10k *ar,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k_peer *peer;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
if (!(ar->hw_params.supports_peer_stats_info &&
|
||||
arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find(ar, arsta->arvif->vdev_id, sta->addr);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
reinit_completion(&ar->peer_stats_info_complete);
|
||||
|
||||
ret = ath10k_wmi_request_peer_stats_info(ar,
|
||||
arsta->arvif->vdev_id,
|
||||
WMI_REQUEST_ONE_PEER_STATS_INFO,
|
||||
arsta->arvif->bssid,
|
||||
0);
|
||||
if (ret && ret != -EOPNOTSUPP) {
|
||||
ath10k_warn(ar, "could not request peer stats info: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->peer_stats_info_complete, 3 * HZ);
|
||||
if (time_left == 0) {
|
||||
ath10k_warn(ar, "timed out waiting peer stats info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (arsta->rx_rate_code != 0 && arsta->rx_bitrate_kbps != 0) {
|
||||
ath10k_mac_parse_bitrate(ar, arsta->rx_rate_code,
|
||||
arsta->rx_bitrate_kbps,
|
||||
&sinfo->rxrate);
|
||||
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
|
||||
arsta->rx_rate_code = 0;
|
||||
arsta->rx_bitrate_kbps = 0;
|
||||
}
|
||||
|
||||
if (arsta->tx_rate_code != 0 && arsta->tx_bitrate_kbps != 0) {
|
||||
ath10k_mac_parse_bitrate(ar, arsta->tx_rate_code,
|
||||
arsta->tx_bitrate_kbps,
|
||||
&sinfo->txrate);
|
||||
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
|
||||
arsta->tx_rate_code = 0;
|
||||
arsta->tx_bitrate_kbps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_sta_statistics(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
@ -8305,6 +8525,8 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
|
||||
if (!ath10k_peer_stats_enabled(ar))
|
||||
return;
|
||||
|
||||
ath10k_debug_fw_stats_request(ar);
|
||||
|
||||
sinfo->rx_duration = arsta->rx_duration;
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
|
||||
|
||||
@ -8320,6 +8542,15 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
|
||||
}
|
||||
sinfo->txrate.flags = arsta->txrate.flags;
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
|
||||
|
||||
if (ar->htt.disable_tx_comp) {
|
||||
sinfo->tx_retries = arsta->tx_retries;
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
|
||||
sinfo->tx_failed = arsta->tx_failed;
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
|
||||
}
|
||||
|
||||
ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo);
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath10k_ops = {
|
||||
@ -8957,7 +9188,6 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
|
||||
|
||||
if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {
|
||||
ar->hw->wiphy->max_sched_scan_reqs = 1;
|
||||
ar->hw->wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS;
|
||||
ar->hw->wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
|
||||
ar->hw->wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH;
|
||||
|
@ -116,7 +116,7 @@ static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
static void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
|
||||
|
||||
static struct ce_attr host_ce_config_wlan[] = {
|
||||
static const struct ce_attr pci_host_ce_config_wlan[] = {
|
||||
/* CE0: host->target HTC control and raw streams */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
@ -222,7 +222,7 @@ static struct ce_attr host_ce_config_wlan[] = {
|
||||
};
|
||||
|
||||
/* Target firmware's Copy Engine configuration. */
|
||||
static struct ce_pipe_config target_ce_config_wlan[] = {
|
||||
static const struct ce_pipe_config pci_target_ce_config_wlan[] = {
|
||||
/* CE0: host->target HTC control and raw streams */
|
||||
{
|
||||
.pipenum = __cpu_to_le32(0),
|
||||
@ -335,7 +335,7 @@ static struct ce_pipe_config target_ce_config_wlan[] = {
|
||||
* This table is derived from the CE_PCI TABLE, above.
|
||||
* It is passed to the Target at startup for use by firmware.
|
||||
*/
|
||||
static struct service_to_pipe target_service_to_ce_map_wlan[] = {
|
||||
static const struct ce_service_to_pipe pci_target_service_to_ce_map_wlan[] = {
|
||||
{
|
||||
__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
|
||||
__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
|
||||
@ -1787,6 +1787,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
|
||||
void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||
int force)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
|
||||
|
||||
if (!force) {
|
||||
@ -1804,7 +1806,7 @@ void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||
* If at least 50% of the total resources are still available,
|
||||
* don't bother checking again yet.
|
||||
*/
|
||||
if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))
|
||||
if (resources > (ar_pci->attr[pipe].src_nentries >> 1))
|
||||
return;
|
||||
}
|
||||
ath10k_ce_per_engine_service(ar, pipe);
|
||||
@ -1820,14 +1822,15 @@ static void ath10k_pci_rx_retry_sync(struct ath10k *ar)
|
||||
int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
const struct service_to_pipe *entry;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
const struct ce_service_to_pipe *entry;
|
||||
bool ul_set = false, dl_set = false;
|
||||
int i;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
|
||||
entry = &target_service_to_ce_map_wlan[i];
|
||||
for (i = 0; i < ARRAY_SIZE(pci_target_service_to_ce_map_wlan); i++) {
|
||||
entry = &ar_pci->serv_to_pipe[i];
|
||||
|
||||
if (__le32_to_cpu(entry->service_id) != service_id)
|
||||
continue;
|
||||
@ -2316,6 +2319,7 @@ static int ath10k_bus_get_num_banks(struct ath10k *ar)
|
||||
|
||||
int ath10k_pci_init_config(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
u32 interconnect_targ_addr;
|
||||
u32 pcie_state_targ_addr = 0;
|
||||
u32 pipe_cfg_targ_addr = 0;
|
||||
@ -2361,7 +2365,7 @@ int ath10k_pci_init_config(struct ath10k *ar)
|
||||
}
|
||||
|
||||
ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr,
|
||||
target_ce_config_wlan,
|
||||
ar_pci->pipe_config,
|
||||
sizeof(struct ce_pipe_config) *
|
||||
NUM_TARGET_CE_CONFIG_WLAN);
|
||||
|
||||
@ -2386,8 +2390,8 @@ int ath10k_pci_init_config(struct ath10k *ar)
|
||||
}
|
||||
|
||||
ret = ath10k_pci_diag_write_mem(ar, svc_to_pipe_map,
|
||||
target_service_to_ce_map_wlan,
|
||||
sizeof(target_service_to_ce_map_wlan));
|
||||
ar_pci->serv_to_pipe,
|
||||
sizeof(pci_target_service_to_ce_map_wlan));
|
||||
if (ret != 0) {
|
||||
ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
|
||||
return ret;
|
||||
@ -2459,23 +2463,24 @@ static void ath10k_pci_override_ce_config(struct ath10k *ar)
|
||||
{
|
||||
struct ce_attr *attr;
|
||||
struct ce_pipe_config *config;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
/* For QCA6174 we're overriding the Copy Engine 5 configuration,
|
||||
* since it is currently used for other feature.
|
||||
*/
|
||||
|
||||
/* Override Host's Copy Engine 5 configuration */
|
||||
attr = &host_ce_config_wlan[5];
|
||||
attr = &ar_pci->attr[5];
|
||||
attr->src_sz_max = 0;
|
||||
attr->dest_nentries = 0;
|
||||
|
||||
/* Override Target firmware's Copy Engine configuration */
|
||||
config = &target_ce_config_wlan[5];
|
||||
config = &ar_pci->pipe_config[5];
|
||||
config->pipedir = __cpu_to_le32(PIPEDIR_OUT);
|
||||
config->nbytes_max = __cpu_to_le32(2048);
|
||||
|
||||
/* Map from service/endpoint to Copy Engine */
|
||||
target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
|
||||
ar_pci->serv_to_pipe[15].pipenum = __cpu_to_le32(1);
|
||||
}
|
||||
|
||||
int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
||||
@ -2491,7 +2496,7 @@ int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
||||
pipe->pipe_num = i;
|
||||
pipe->hif_ce_state = ar;
|
||||
|
||||
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
|
||||
ret = ath10k_ce_alloc_pipe(ar, i, &ar_pci->attr[i]);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
|
||||
i, ret);
|
||||
@ -2504,7 +2509,7 @@ int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
||||
continue;
|
||||
}
|
||||
|
||||
pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max);
|
||||
pipe->buf_sz = (size_t)(ar_pci->attr[i].src_sz_max);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2520,10 +2525,11 @@ void ath10k_pci_free_pipes(struct ath10k *ar)
|
||||
|
||||
int ath10k_pci_init_pipes(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < CE_COUNT; i++) {
|
||||
ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
|
||||
ret = ath10k_ce_init_pipe(ar, i, &ar_pci->attr[i]);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
|
||||
i, ret);
|
||||
@ -3595,6 +3601,30 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
|
||||
timer_setup(&ar_pci->ps_timer, ath10k_pci_ps_timer, 0);
|
||||
|
||||
ar_pci->attr = kmemdup(pci_host_ce_config_wlan,
|
||||
sizeof(pci_host_ce_config_wlan),
|
||||
GFP_KERNEL);
|
||||
if (!ar_pci->attr) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ar_pci->pipe_config = kmemdup(pci_target_ce_config_wlan,
|
||||
sizeof(pci_target_ce_config_wlan),
|
||||
GFP_KERNEL);
|
||||
if (!ar_pci->pipe_config) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ar_pci->serv_to_pipe = kmemdup(pci_target_service_to_ce_map_wlan,
|
||||
sizeof(pci_target_service_to_ce_map_wlan),
|
||||
GFP_KERNEL);
|
||||
if (!ar_pci->serv_to_pipe) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ret = ath10k_pci_setup_resource(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to setup resource: %d\n", ret);
|
||||
@ -3690,6 +3720,11 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
err_core_destroy:
|
||||
ath10k_core_destroy(ar);
|
||||
|
||||
err_free:
|
||||
kfree(ar_pci->attr);
|
||||
kfree(ar_pci->pipe_config);
|
||||
kfree(ar_pci->serv_to_pipe);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3715,6 +3750,9 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
|
||||
ath10k_pci_sleep_sync(ar);
|
||||
ath10k_pci_release(ar);
|
||||
ath10k_core_destroy(ar);
|
||||
kfree(ar_pci->attr);
|
||||
kfree(ar_pci->pipe_config);
|
||||
kfree(ar_pci->serv_to_pipe);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
|
||||
|
@ -183,6 +183,10 @@ struct ath10k_pci {
|
||||
* this struct.
|
||||
*/
|
||||
struct ath10k_ahb ahb[0];
|
||||
|
||||
struct ce_attr *attr;
|
||||
struct ce_pipe_config *pipe_config;
|
||||
struct ce_service_to_pipe *serv_to_pipe;
|
||||
};
|
||||
|
||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
|
@ -122,8 +122,8 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
req.msa_addr = qmi->msa_pa;
|
||||
req.size = qmi->msa_mem_size;
|
||||
req.msa_addr = ar->msa.paddr;
|
||||
req.size = ar->msa.mem_size;
|
||||
|
||||
ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
|
||||
wlfw_msa_info_resp_msg_v01_ei, &resp);
|
||||
@ -157,12 +157,12 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
|
||||
goto out;
|
||||
}
|
||||
|
||||
max_mapped_addr = qmi->msa_pa + qmi->msa_mem_size;
|
||||
max_mapped_addr = ar->msa.paddr + ar->msa.mem_size;
|
||||
qmi->nr_mem_region = resp.mem_region_info_len;
|
||||
for (i = 0; i < resp.mem_region_info_len; i++) {
|
||||
if (resp.mem_region_info[i].size > qmi->msa_mem_size ||
|
||||
if (resp.mem_region_info[i].size > ar->msa.mem_size ||
|
||||
resp.mem_region_info[i].region_addr > max_mapped_addr ||
|
||||
resp.mem_region_info[i].region_addr < qmi->msa_pa ||
|
||||
resp.mem_region_info[i].region_addr < ar->msa.paddr ||
|
||||
resp.mem_region_info[i].size +
|
||||
resp.mem_region_info[i].region_addr > max_mapped_addr) {
|
||||
ath10k_err(ar, "received out of range memory region address 0x%llx with size 0x%x, aborting\n",
|
||||
@ -1006,54 +1006,10 @@ static void ath10k_qmi_driver_event_work(struct work_struct *work)
|
||||
spin_unlock(&qmi->event_lock);
|
||||
}
|
||||
|
||||
static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size)
|
||||
{
|
||||
struct ath10k *ar = qmi->ar;
|
||||
struct device *dev = ar->dev;
|
||||
struct device_node *node;
|
||||
struct resource r;
|
||||
int ret;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (node) {
|
||||
ret = of_address_to_resource(node, 0, &r);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to resolve msa fixed region\n");
|
||||
return ret;
|
||||
}
|
||||
of_node_put(node);
|
||||
|
||||
qmi->msa_pa = r.start;
|
||||
qmi->msa_mem_size = resource_size(&r);
|
||||
qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size,
|
||||
MEMREMAP_WT);
|
||||
if (IS_ERR(qmi->msa_va)) {
|
||||
dev_err(dev, "failed to map memory region: %pa\n", &r.start);
|
||||
return PTR_ERR(qmi->msa_va);
|
||||
}
|
||||
} else {
|
||||
qmi->msa_va = dmam_alloc_coherent(dev, msa_size,
|
||||
&qmi->msa_pa, GFP_KERNEL);
|
||||
if (!qmi->msa_va) {
|
||||
ath10k_err(ar, "failed to allocate dma memory for msa region\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
qmi->msa_mem_size = msa_size;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "qcom,msa-fixed-perm"))
|
||||
qmi->msa_fixed_perm = true;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n",
|
||||
&qmi->msa_pa,
|
||||
qmi->msa_va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct device *dev = ar->dev;
|
||||
struct ath10k_qmi *qmi;
|
||||
int ret;
|
||||
|
||||
@ -1064,9 +1020,8 @@ int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
|
||||
qmi->ar = ar;
|
||||
ar_snoc->qmi = qmi;
|
||||
|
||||
ret = ath10k_qmi_setup_msa_resources(qmi, msa_size);
|
||||
if (ret)
|
||||
goto err;
|
||||
if (of_property_read_bool(dev->of_node, "qcom,msa-fixed-perm"))
|
||||
qmi->msa_fixed_perm = true;
|
||||
|
||||
ret = qmi_handle_init(&qmi->qmi_hdl,
|
||||
WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
|
||||
|
@ -93,9 +93,6 @@ struct ath10k_qmi {
|
||||
spinlock_t event_lock; /* spinlock for qmi event list */
|
||||
u32 nr_mem_region;
|
||||
struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS];
|
||||
dma_addr_t msa_pa;
|
||||
u32 msa_mem_size;
|
||||
void *msa_va;
|
||||
struct ath10k_qmi_chip_info chip_info;
|
||||
struct ath10k_qmi_board_info board_info;
|
||||
struct ath10k_qmi_soc_info soc_info;
|
||||
|
@ -542,7 +542,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
|
||||
int pkt_cnt = 0;
|
||||
|
||||
if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) {
|
||||
ath10k_warn(ar, "the total number of pkgs to be fetched (%u) exceeds maximum %u\n",
|
||||
ath10k_warn(ar, "the total number of pkts to be fetched (%u) exceeds maximum %u\n",
|
||||
n_lookaheads, ATH10K_SDIO_MAX_RX_MSGS);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
@ -1361,23 +1361,117 @@ static void ath10k_rx_indication_async_work(struct work_struct *work)
|
||||
napi_schedule(&ar->napi);
|
||||
}
|
||||
|
||||
static int ath10k_sdio_read_rtc_state(struct ath10k_sdio *ar_sdio, unsigned char *state)
|
||||
{
|
||||
struct ath10k *ar = ar_sdio->ar;
|
||||
unsigned char rtc_state = 0;
|
||||
int ret = 0;
|
||||
|
||||
rtc_state = sdio_f0_readb(ar_sdio->func, ATH10K_CIS_RTC_STATE_ADDR, &ret);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read rtc state: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*state = rtc_state & 0x3;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_set_mbox_sleep(struct ath10k *ar, bool enable_sleep)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
u32 val;
|
||||
int retry = ATH10K_CIS_READ_RETRY, ret = 0;
|
||||
unsigned char rtc_state = 0;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
ret = ath10k_sdio_read32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, &val);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read fifo/chip control register: %d\n",
|
||||
ret);
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (enable_sleep) {
|
||||
val &= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF;
|
||||
ar_sdio->mbox_state = SDIO_MBOX_SLEEP_STATE;
|
||||
} else {
|
||||
val |= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON;
|
||||
ar_sdio->mbox_state = SDIO_MBOX_AWAKE_STATE;
|
||||
}
|
||||
|
||||
ret = ath10k_sdio_write32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, val);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to write to FIFO_TIMEOUT_AND_CHIP_CONTROL: %d",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (!enable_sleep) {
|
||||
do {
|
||||
udelay(ATH10K_CIS_READ_WAIT_4_RTC_CYCLE_IN_US);
|
||||
ret = ath10k_sdio_read_rtc_state(ar_sdio, &rtc_state);
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to disable mbox sleep: %d", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read rtc state: %d\n",
|
||||
rtc_state);
|
||||
|
||||
if (rtc_state == ATH10K_CIS_RTC_STATE_ON)
|
||||
break;
|
||||
|
||||
udelay(ATH10K_CIS_XTAL_SETTLE_DURATION_IN_US);
|
||||
retry--;
|
||||
} while (retry > 0);
|
||||
}
|
||||
|
||||
release:
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_sdio_sleep_timer_handler(struct timer_list *t)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = from_timer(ar_sdio, t, sleep_timer);
|
||||
|
||||
ar_sdio->mbox_state = SDIO_MBOX_REQUEST_TO_SLEEP_STATE;
|
||||
queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work);
|
||||
}
|
||||
|
||||
static void ath10k_sdio_write_async_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
|
||||
wr_async_work);
|
||||
struct ath10k *ar = ar_sdio->ar;
|
||||
struct ath10k_sdio_bus_request *req, *tmp_req;
|
||||
struct ath10k_mbox_info *mbox_info = &ar_sdio->mbox_info;
|
||||
|
||||
spin_lock_bh(&ar_sdio->wr_async_lock);
|
||||
|
||||
list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) {
|
||||
list_del(&req->list);
|
||||
spin_unlock_bh(&ar_sdio->wr_async_lock);
|
||||
|
||||
if (req->address >= mbox_info->htc_addr &&
|
||||
ar_sdio->mbox_state == SDIO_MBOX_SLEEP_STATE) {
|
||||
ath10k_sdio_set_mbox_sleep(ar, false);
|
||||
mod_timer(&ar_sdio->sleep_timer, jiffies +
|
||||
msecs_to_jiffies(ATH10K_MIN_SLEEP_INACTIVITY_TIME_MS));
|
||||
}
|
||||
|
||||
__ath10k_sdio_write_async(ar, req);
|
||||
spin_lock_bh(&ar_sdio->wr_async_lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar_sdio->wr_async_lock);
|
||||
|
||||
if (ar_sdio->mbox_state == SDIO_MBOX_REQUEST_TO_SLEEP_STATE)
|
||||
ath10k_sdio_set_mbox_sleep(ar, true);
|
||||
}
|
||||
|
||||
static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
|
||||
@ -1444,7 +1538,7 @@ static void ath10k_sdio_irq_handler(struct sdio_func *func)
|
||||
|
||||
/* sdio HIF functions */
|
||||
|
||||
static int ath10k_sdio_hif_disable_intrs(struct ath10k *ar)
|
||||
static int ath10k_sdio_disable_intrs(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data;
|
||||
@ -1500,7 +1594,7 @@ static int ath10k_sdio_hif_power_up(struct ath10k *ar,
|
||||
|
||||
ar_sdio->is_disabled = false;
|
||||
|
||||
ret = ath10k_sdio_hif_disable_intrs(ar);
|
||||
ret = ath10k_sdio_disable_intrs(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1517,6 +1611,9 @@ static void ath10k_sdio_hif_power_down(struct ath10k *ar)
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power off\n");
|
||||
|
||||
del_timer_sync(&ar_sdio->sleep_timer);
|
||||
ath10k_sdio_set_mbox_sleep(ar, true);
|
||||
|
||||
/* Disable the card */
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
@ -1569,7 +1666,7 @@ static int ath10k_sdio_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_hif_enable_intrs(struct ath10k *ar)
|
||||
static int ath10k_sdio_enable_intrs(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data;
|
||||
@ -1617,33 +1714,6 @@ static int ath10k_sdio_hif_enable_intrs(struct ath10k *ar)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_hif_set_mbox_sleep(struct ath10k *ar, bool enable_sleep)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_sdio_read32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, &val);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read fifo/chip control register: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (enable_sleep)
|
||||
val &= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF;
|
||||
else
|
||||
val |= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON;
|
||||
|
||||
ret = ath10k_sdio_write32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, val);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to write to FIFO_TIMEOUT_AND_CHIP_CONTROL: %d",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HIF diagnostics */
|
||||
|
||||
static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
|
||||
@ -1679,8 +1749,8 @@ static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_hif_diag_read32(struct ath10k *ar, u32 address,
|
||||
u32 *value)
|
||||
static int ath10k_sdio_diag_read32(struct ath10k *ar, u32 address,
|
||||
u32 *value)
|
||||
{
|
||||
__le32 *val;
|
||||
int ret;
|
||||
@ -1725,7 +1795,7 @@ static int ath10k_sdio_hif_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
|
||||
static int ath10k_sdio_hif_start_post(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
|
||||
u32 addr, val;
|
||||
@ -1733,7 +1803,7 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
|
||||
|
||||
addr = host_interest_item_address(HI_ITEM(hi_acs_flags));
|
||||
|
||||
ret = ath10k_sdio_hif_diag_read32(ar, addr, &val);
|
||||
ret = ath10k_sdio_diag_read32(ar, addr, &val);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read hi_acs_flags : %d\n", ret);
|
||||
return ret;
|
||||
@ -1749,6 +1819,8 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
|
||||
ar_sdio->swap_mbox = false;
|
||||
}
|
||||
|
||||
ath10k_sdio_set_mbox_sleep(ar, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1759,7 +1831,7 @@ static int ath10k_sdio_get_htt_tx_complete(struct ath10k *ar)
|
||||
|
||||
addr = host_interest_item_address(HI_ITEM(hi_acs_flags));
|
||||
|
||||
ret = ath10k_sdio_hif_diag_read32(ar, addr, &val);
|
||||
ret = ath10k_sdio_diag_read32(ar, addr, &val);
|
||||
if (ret) {
|
||||
ath10k_warn(ar,
|
||||
"unable to read hi_acs_flags for htt tx comple : %d\n", ret);
|
||||
@ -1788,7 +1860,7 @@ static int ath10k_sdio_hif_start(struct ath10k *ar)
|
||||
* request before interrupts are disabled.
|
||||
*/
|
||||
msleep(20);
|
||||
ret = ath10k_sdio_hif_disable_intrs(ar);
|
||||
ret = ath10k_sdio_disable_intrs(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1810,19 +1882,19 @@ static int ath10k_sdio_hif_start(struct ath10k *ar)
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
ret = ath10k_sdio_hif_enable_intrs(ar);
|
||||
ret = ath10k_sdio_enable_intrs(ar);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to enable sdio interrupts: %d\n", ret);
|
||||
|
||||
/* Enable sleep and then disable it again */
|
||||
ret = ath10k_sdio_hif_set_mbox_sleep(ar, true);
|
||||
ret = ath10k_sdio_set_mbox_sleep(ar, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Wait for 20ms for the written value to take effect */
|
||||
msleep(20);
|
||||
|
||||
ret = ath10k_sdio_hif_set_mbox_sleep(ar, false);
|
||||
ret = ath10k_sdio_set_mbox_sleep(ar, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2029,17 +2101,6 @@ static void ath10k_sdio_hif_get_default_pipe(struct ath10k *ar,
|
||||
*dl_pipe = 0;
|
||||
}
|
||||
|
||||
/* This op is currently only used by htc_wait_target if the HTC ready
|
||||
* message times out. It is not applicable for SDIO since there is nothing
|
||||
* we can do if the HTC ready message does not arrive in time.
|
||||
* TODO: Make this op non mandatory by introducing a NULL check in the
|
||||
* hif op wrapper.
|
||||
*/
|
||||
static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar,
|
||||
u8 pipe, int force)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct ath10k_hif_ops ath10k_sdio_hif_ops = {
|
||||
.tx_sg = ath10k_sdio_hif_tx_sg,
|
||||
.diag_read = ath10k_sdio_hif_diag_read,
|
||||
@ -2047,11 +2108,10 @@ static const struct ath10k_hif_ops ath10k_sdio_hif_ops = {
|
||||
.exchange_bmi_msg = ath10k_sdio_bmi_exchange_msg,
|
||||
.start = ath10k_sdio_hif_start,
|
||||
.stop = ath10k_sdio_hif_stop,
|
||||
.swap_mailbox = ath10k_sdio_hif_swap_mailbox,
|
||||
.start_post = ath10k_sdio_hif_start_post,
|
||||
.get_htt_tx_complete = ath10k_sdio_get_htt_tx_complete,
|
||||
.map_service_to_pipe = ath10k_sdio_hif_map_service_to_pipe,
|
||||
.get_default_pipe = ath10k_sdio_hif_get_default_pipe,
|
||||
.send_complete_check = ath10k_sdio_hif_send_complete_check,
|
||||
.power_up = ath10k_sdio_hif_power_up,
|
||||
.power_down = ath10k_sdio_hif_power_down,
|
||||
#ifdef CONFIG_PM
|
||||
@ -2076,6 +2136,8 @@ static int ath10k_sdio_pm_suspend(struct device *device)
|
||||
if (!device_may_wakeup(ar->dev))
|
||||
return 0;
|
||||
|
||||
ath10k_sdio_set_mbox_sleep(ar, true);
|
||||
|
||||
pm_flag = MMC_PM_KEEP_POWER;
|
||||
|
||||
ret = sdio_set_host_pm_flags(func, pm_flag);
|
||||
@ -2239,6 +2301,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
|
||||
goto err_free_wq;
|
||||
}
|
||||
|
||||
timer_setup(&ar_sdio->sleep_timer, ath10k_sdio_sleep_timer_handler, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_wq:
|
||||
|
@ -98,6 +98,20 @@
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000
|
||||
|
||||
enum sdio_mbox_state {
|
||||
SDIO_MBOX_UNKNOWN_STATE = 0,
|
||||
SDIO_MBOX_REQUEST_TO_SLEEP_STATE = 1,
|
||||
SDIO_MBOX_SLEEP_STATE = 2,
|
||||
SDIO_MBOX_AWAKE_STATE = 3,
|
||||
};
|
||||
|
||||
#define ATH10K_CIS_READ_WAIT_4_RTC_CYCLE_IN_US 125
|
||||
#define ATH10K_CIS_RTC_STATE_ADDR 0x1138
|
||||
#define ATH10K_CIS_RTC_STATE_ON 0x01
|
||||
#define ATH10K_CIS_XTAL_SETTLE_DURATION_IN_US 1500
|
||||
#define ATH10K_CIS_READ_RETRY 10
|
||||
#define ATH10K_MIN_SLEEP_INACTIVITY_TIME_MS 50
|
||||
|
||||
/* TODO: remove this and use skb->cb instead, much cleaner approach */
|
||||
struct ath10k_sdio_bus_request {
|
||||
struct list_head list;
|
||||
@ -218,6 +232,8 @@ struct ath10k_sdio {
|
||||
spinlock_t wr_async_lock;
|
||||
|
||||
struct work_struct async_work_rx;
|
||||
struct timer_list sleep_timer;
|
||||
enum sdio_mbox_state mbox_state;
|
||||
};
|
||||
|
||||
static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar)
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include "ce.h"
|
||||
#include "coredump.h"
|
||||
@ -356,7 +358,7 @@ static struct ce_pipe_config target_ce_config_wlan[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct service_to_pipe target_service_to_ce_map_wlan[] = {
|
||||
static struct ce_service_to_pipe target_service_to_ce_map_wlan[] = {
|
||||
{
|
||||
__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
|
||||
__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
|
||||
@ -769,7 +771,7 @@ static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
const struct service_to_pipe *entry;
|
||||
const struct ce_service_to_pipe *entry;
|
||||
bool ul_set = false, dl_set = false;
|
||||
int i;
|
||||
|
||||
@ -1393,7 +1395,6 @@ static int ath10k_hw_power_off(struct ath10k *ar)
|
||||
static void ath10k_msa_dump_memory(struct ath10k *ar,
|
||||
struct ath10k_fw_crash_data *crash_data)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
const struct ath10k_hw_mem_layout *mem_layout;
|
||||
const struct ath10k_mem_region *current_region;
|
||||
struct ath10k_dump_ram_data_hdr *hdr;
|
||||
@ -1419,15 +1420,15 @@ static void ath10k_msa_dump_memory(struct ath10k *ar,
|
||||
buf_len -= sizeof(*hdr);
|
||||
|
||||
hdr->region_type = cpu_to_le32(current_region->type);
|
||||
hdr->start = cpu_to_le32((unsigned long)ar_snoc->qmi->msa_va);
|
||||
hdr->length = cpu_to_le32(ar_snoc->qmi->msa_mem_size);
|
||||
hdr->start = cpu_to_le32((unsigned long)ar->msa.vaddr);
|
||||
hdr->length = cpu_to_le32(ar->msa.mem_size);
|
||||
|
||||
if (current_region->len < ar_snoc->qmi->msa_mem_size) {
|
||||
memcpy(buf, ar_snoc->qmi->msa_va, current_region->len);
|
||||
if (current_region->len < ar->msa.mem_size) {
|
||||
memcpy(buf, ar->msa.vaddr, current_region->len);
|
||||
ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",
|
||||
current_region->len, ar_snoc->qmi->msa_mem_size);
|
||||
current_region->len, ar->msa.mem_size);
|
||||
} else {
|
||||
memcpy(buf, ar_snoc->qmi->msa_va, ar_snoc->qmi->msa_mem_size);
|
||||
memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1455,6 +1456,155 @@ void ath10k_snoc_fw_crashed_dump(struct ath10k *ar)
|
||||
mutex_unlock(&ar->dump_mutex);
|
||||
}
|
||||
|
||||
static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)
|
||||
{
|
||||
struct device *dev = ar->dev;
|
||||
struct device_node *node;
|
||||
struct resource r;
|
||||
int ret;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (node) {
|
||||
ret = of_address_to_resource(node, 0, &r);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to resolve msa fixed region\n");
|
||||
return ret;
|
||||
}
|
||||
of_node_put(node);
|
||||
|
||||
ar->msa.paddr = r.start;
|
||||
ar->msa.mem_size = resource_size(&r);
|
||||
ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,
|
||||
ar->msa.mem_size,
|
||||
MEMREMAP_WT);
|
||||
if (IS_ERR(ar->msa.vaddr)) {
|
||||
dev_err(dev, "failed to map memory region: %pa\n",
|
||||
&r.start);
|
||||
return PTR_ERR(ar->msa.vaddr);
|
||||
}
|
||||
} else {
|
||||
ar->msa.vaddr = dmam_alloc_coherent(dev, msa_size,
|
||||
&ar->msa.paddr,
|
||||
GFP_KERNEL);
|
||||
if (!ar->msa.vaddr) {
|
||||
ath10k_err(ar, "failed to allocate dma memory for msa region\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ar->msa.mem_size = msa_size;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa.paddr: %pad , msa.vaddr: 0x%p\n",
|
||||
&ar->msa.paddr,
|
||||
ar->msa.vaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_fw_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
struct device *host_dev = &ar_snoc->dev->dev;
|
||||
struct platform_device_info info;
|
||||
struct iommu_domain *iommu_dom;
|
||||
struct platform_device *pdev;
|
||||
struct device_node *node;
|
||||
int ret;
|
||||
|
||||
node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
|
||||
if (!node) {
|
||||
ar_snoc->use_tz = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.fwnode = &node->fwnode;
|
||||
info.parent = host_dev;
|
||||
info.name = node->name;
|
||||
info.dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
pdev = platform_device_register_full(&info);
|
||||
if (IS_ERR(pdev)) {
|
||||
of_node_put(node);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
pdev->dev.of_node = node;
|
||||
|
||||
ret = of_dma_configure(&pdev->dev, node, true);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "dma configure fail: %d\n", ret);
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ar_snoc->fw.dev = &pdev->dev;
|
||||
|
||||
iommu_dom = iommu_domain_alloc(&platform_bus_type);
|
||||
if (!iommu_dom) {
|
||||
ath10k_err(ar, "failed to allocate iommu domain\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ret = iommu_attach_device(iommu_dom, ar_snoc->fw.dev);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "could not attach device: %d\n", ret);
|
||||
goto err_iommu_free;
|
||||
}
|
||||
|
||||
ar_snoc->fw.iommu_domain = iommu_dom;
|
||||
ar_snoc->fw.fw_start_addr = ar->msa.paddr;
|
||||
|
||||
ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,
|
||||
ar->msa.paddr, ar->msa.mem_size,
|
||||
IOMMU_READ | IOMMU_WRITE);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to map firmware region: %d\n", ret);
|
||||
goto err_iommu_detach;
|
||||
}
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
return 0;
|
||||
|
||||
err_iommu_detach:
|
||||
iommu_detach_device(iommu_dom, ar_snoc->fw.dev);
|
||||
|
||||
err_iommu_free:
|
||||
iommu_domain_free(iommu_dom);
|
||||
|
||||
err_unregister:
|
||||
platform_device_unregister(pdev);
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_fw_deinit(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
|
||||
const size_t mapped_size = ar_snoc->fw.mapped_mem_size;
|
||||
struct iommu_domain *iommu;
|
||||
size_t unmapped_size;
|
||||
|
||||
if (ar_snoc->use_tz)
|
||||
return 0;
|
||||
|
||||
iommu = ar_snoc->fw.iommu_domain;
|
||||
|
||||
unmapped_size = iommu_unmap(iommu, ar_snoc->fw.fw_start_addr,
|
||||
mapped_size);
|
||||
if (unmapped_size != mapped_size)
|
||||
ath10k_err(ar, "failed to unmap firmware: %zu\n",
|
||||
unmapped_size);
|
||||
|
||||
iommu_detach_device(iommu, ar_snoc->fw.dev);
|
||||
iommu_domain_free(iommu);
|
||||
|
||||
platform_device_unregister(to_platform_device(ar_snoc->fw.dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ath10k_snoc_dt_match[] = {
|
||||
{ .compatible = "qcom,wcn3990-wifi",
|
||||
.data = &drv_priv,
|
||||
@ -1557,16 +1707,31 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = ath10k_setup_msa_resources(ar, msa_size);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
ret = ath10k_fw_init(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to initialize firmware: %d\n", ret);
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
ret = ath10k_qmi_init(ar, msa_size);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
|
||||
goto err_power_off;
|
||||
goto err_fw_deinit;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_fw_deinit:
|
||||
ath10k_fw_deinit(ar);
|
||||
|
||||
err_power_off:
|
||||
ath10k_hw_power_off(ar);
|
||||
|
||||
@ -1598,6 +1763,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
|
||||
|
||||
ath10k_core_unregister(ar);
|
||||
ath10k_hw_power_off(ar);
|
||||
ath10k_fw_deinit(ar);
|
||||
ath10k_snoc_free_irq(ar);
|
||||
ath10k_snoc_release_resource(ar);
|
||||
ath10k_qmi_deinit(ar);
|
||||
|
@ -55,6 +55,13 @@ struct regulator_bulk_data;
|
||||
struct ath10k_snoc {
|
||||
struct platform_device *dev;
|
||||
struct ath10k *ar;
|
||||
unsigned int use_tz;
|
||||
struct ath10k_firmware {
|
||||
struct device *dev;
|
||||
dma_addr_t fw_start_addr;
|
||||
struct iommu_domain *iommu_domain;
|
||||
size_t mapped_mem_size;
|
||||
} fw;
|
||||
void __iomem *mem;
|
||||
dma_addr_t mem_pa;
|
||||
struct ath10k_snoc_target_info target_info;
|
||||
|
@ -693,17 +693,6 @@ static int ath10k_usb_hif_map_service_to_pipe(struct ath10k *ar, u16 svc_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This op is currently only used by htc_wait_target if the HTC ready
|
||||
* message times out. It is not applicable for USB since there is nothing
|
||||
* we can do if the HTC ready message does not arrive in time.
|
||||
* TODO: Make this op non mandatory by introducing a NULL check in the
|
||||
* hif op wrapper.
|
||||
*/
|
||||
static void ath10k_usb_hif_send_complete_check(struct ath10k *ar,
|
||||
u8 pipe, int force)
|
||||
{
|
||||
}
|
||||
|
||||
static int ath10k_usb_hif_power_up(struct ath10k *ar,
|
||||
enum ath10k_firmware_mode fw_mode)
|
||||
{
|
||||
@ -737,7 +726,6 @@ static const struct ath10k_hif_ops ath10k_usb_hif_ops = {
|
||||
.stop = ath10k_usb_hif_stop,
|
||||
.map_service_to_pipe = ath10k_usb_hif_map_service_to_pipe,
|
||||
.get_default_pipe = ath10k_usb_hif_get_default_pipe,
|
||||
.send_complete_check = ath10k_usb_hif_send_complete_check,
|
||||
.get_free_queue_number = ath10k_usb_hif_get_free_queue_number,
|
||||
.power_up = ath10k_usb_hif_power_up,
|
||||
.power_down = ath10k_usb_hif_power_down,
|
||||
|
@ -126,6 +126,13 @@ struct wmi_ops {
|
||||
struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
|
||||
const struct wmi_wmm_params_all_arg *arg);
|
||||
struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask);
|
||||
struct sk_buff *(*gen_request_peer_stats_info)(struct ath10k *ar,
|
||||
u32 vdev_id,
|
||||
enum
|
||||
wmi_peer_stats_info_request_type
|
||||
type,
|
||||
u8 *addr,
|
||||
u32 reset);
|
||||
struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
|
||||
enum wmi_force_fw_hang_type type,
|
||||
u32 delay_ms);
|
||||
@ -1064,6 +1071,29 @@ ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask)
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_request_peer_stats_info(struct ath10k *ar,
|
||||
u32 vdev_id,
|
||||
enum wmi_peer_stats_info_request_type type,
|
||||
u8 *addr,
|
||||
u32 reset)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!ar->wmi.ops->gen_request_peer_stats_info)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
skb = ar->wmi.ops->gen_request_peer_stats_info(ar,
|
||||
vdev_id,
|
||||
type,
|
||||
addr,
|
||||
reset);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_peer_stats_info_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_force_fw_hang(struct ath10k *ar,
|
||||
enum wmi_force_fw_hang_type type, u32 delay_ms)
|
||||
|
@ -219,6 +219,91 @@ static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar,
|
||||
complete(&ar->vdev_delete_done);
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
{
|
||||
const struct wmi_tlv_peer_stats_info *stat = ptr;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
|
||||
if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO)
|
||||
return -EPROTO;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi tlv stats peer addr %pMF rx rate code 0x%x bit rate %d kbps\n",
|
||||
stat->peer_macaddr.addr,
|
||||
__le32_to_cpu(stat->last_rx_rate_code),
|
||||
__le32_to_cpu(stat->last_rx_bitrate_kbps));
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi tlv stats tx rate code 0x%x bit rate %d kbps\n",
|
||||
__le32_to_cpu(stat->last_tx_rate_code),
|
||||
__le32_to_cpu(stat->last_tx_bitrate_kbps));
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL);
|
||||
if (!sta) {
|
||||
ath10k_warn(ar, "not found station for peer stats\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code);
|
||||
arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps);
|
||||
arsta->tx_rate_code = __le32_to_cpu(stat->last_tx_rate_code);
|
||||
arsta->tx_bitrate_kbps = __le32_to_cpu(stat->last_tx_bitrate_kbps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const void **tb;
|
||||
const struct wmi_tlv_peer_stats_info_ev *ev;
|
||||
const void *data;
|
||||
u32 num_peer_stats;
|
||||
int ret;
|
||||
|
||||
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
|
||||
if (IS_ERR(tb)) {
|
||||
ret = PTR_ERR(tb);
|
||||
ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ev = tb[WMI_TLV_TAG_STRUCT_PEER_STATS_INFO_EVENT];
|
||||
data = tb[WMI_TLV_TAG_ARRAY_STRUCT];
|
||||
|
||||
if (!ev || !data) {
|
||||
kfree(tb);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
num_peer_stats = __le32_to_cpu(ev->num_peers);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n",
|
||||
__le32_to_cpu(ev->vdev_id),
|
||||
num_peer_stats,
|
||||
__le32_to_cpu(ev->more_data));
|
||||
|
||||
ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data),
|
||||
ath10k_wmi_tlv_parse_peer_stats_info, NULL);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret);
|
||||
|
||||
kfree(tb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_wmi_tlv_event_peer_stats_info(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PEER_STATS_INFO_EVENTID\n");
|
||||
ath10k_wmi_tlv_op_pull_peer_stats_info(ar, skb);
|
||||
complete(&ar->peer_stats_info_complete);
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -576,6 +661,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
case WMI_TLV_UPDATE_STATS_EVENTID:
|
||||
ath10k_wmi_event_update_stats(ar, skb);
|
||||
break;
|
||||
case WMI_TLV_PEER_STATS_INFO_EVENTID:
|
||||
ath10k_wmi_tlv_event_peer_stats_info(ar, skb);
|
||||
break;
|
||||
case WMI_TLV_VDEV_START_RESP_EVENTID:
|
||||
ath10k_wmi_event_vdev_start_resp(ar, skb);
|
||||
break;
|
||||
@ -2897,6 +2985,36 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_tlv_op_gen_request_peer_stats_info(struct ath10k *ar,
|
||||
u32 vdev_id,
|
||||
enum wmi_peer_stats_info_request_type type,
|
||||
u8 *addr,
|
||||
u32 reset)
|
||||
{
|
||||
struct wmi_tlv_request_peer_stats_info *cmd;
|
||||
struct wmi_tlv *tlv;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
tlv = (void *)skb->data;
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_PEER_STATS_INFO_CMD);
|
||||
tlv->len = __cpu_to_le16(sizeof(*cmd));
|
||||
cmd = (void *)tlv->value;
|
||||
cmd->vdev_id = __cpu_to_le32(vdev_id);
|
||||
cmd->request_type = __cpu_to_le32(type);
|
||||
|
||||
if (type == WMI_REQUEST_ONE_PEER_STATS_INFO)
|
||||
ether_addr_copy(cmd->peer_macaddr.addr, addr);
|
||||
|
||||
cmd->reset_after_request = reset;
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request peer stats info\n");
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
|
||||
dma_addr_t paddr)
|
||||
@ -4113,6 +4231,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
|
||||
.vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID,
|
||||
.vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
|
||||
.request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID,
|
||||
.request_peer_stats_info_cmdid = WMI_TLV_REQUEST_PEER_STATS_INFO_CMDID,
|
||||
.set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID,
|
||||
.network_list_offload_config_cmdid =
|
||||
WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID,
|
||||
@ -4269,6 +4388,7 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
|
||||
.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,
|
||||
.rfkill_config = WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG,
|
||||
.rfkill_enable = WMI_TLV_PDEV_PARAM_RFKILL_ENABLE,
|
||||
.peer_stats_info_enable = WMI_TLV_PDEV_PARAM_PEER_STATS_INFO_ENABLE,
|
||||
};
|
||||
|
||||
static struct wmi_peer_param_map wmi_tlv_peer_param_map = {
|
||||
@ -4416,6 +4536,7 @@ static const struct wmi_ops wmi_tlv_ops = {
|
||||
.gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
|
||||
.gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
|
||||
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
|
||||
.gen_request_peer_stats_info = ath10k_wmi_tlv_op_gen_request_peer_stats_info,
|
||||
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
|
||||
/* .gen_mgmt_tx = not implemented; HTT is used */
|
||||
.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
|
||||
|
@ -198,6 +198,12 @@ enum wmi_tlv_cmd_id {
|
||||
WMI_TLV_REQUEST_LINK_STATS_CMDID,
|
||||
WMI_TLV_START_LINK_STATS_CMDID,
|
||||
WMI_TLV_CLEAR_LINK_STATS_CMDID,
|
||||
WMI_TLV_CGET_FW_MEM_DUMP_CMDID,
|
||||
WMI_TLV_CDEBUG_MESG_FLUSH_CMDID,
|
||||
WMI_TLV_CDIAG_EVENT_LOG_CONFIG_CMDID,
|
||||
WMI_TLV_CREQUEST_WLAN_STATS_CMDID,
|
||||
WMI_TLV_CREQUEST_RCPI_CMDID,
|
||||
WMI_TLV_REQUEST_PEER_STATS_INFO_CMDID,
|
||||
WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL),
|
||||
WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
|
||||
WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
|
||||
@ -338,6 +344,13 @@ enum wmi_tlv_event_id {
|
||||
WMI_TLV_IFACE_LINK_STATS_EVENTID,
|
||||
WMI_TLV_PEER_LINK_STATS_EVENTID,
|
||||
WMI_TLV_RADIO_LINK_STATS_EVENTID,
|
||||
WMI_TLV_UPDATE_FW_MEM_DUMP_EVENTID,
|
||||
WMI_TLV_DIAG_EVENT_LOG_SUPPORTED_EVENTID,
|
||||
WMI_TLV_INST_RSSI_STATS_EVENTID,
|
||||
WMI_TLV_RADIO_TX_POWER_LEVEL_STATS_EVENTID,
|
||||
WMI_TLV_REPORT_STATS_EVENTID,
|
||||
WMI_TLV_UPDATE_RCPI_EVENTID,
|
||||
WMI_TLV_PEER_STATS_INFO_EVENTID,
|
||||
WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL),
|
||||
WMI_TLV_NLO_SCAN_COMPLETE_EVENTID,
|
||||
WMI_TLV_APFIND_EVENTID,
|
||||
@ -451,6 +464,7 @@ enum wmi_tlv_pdev_param {
|
||||
WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD,
|
||||
WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE,
|
||||
WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR,
|
||||
WMI_TLV_PDEV_PARAM_PEER_STATS_INFO_ENABLE = 0x8b,
|
||||
WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX,
|
||||
};
|
||||
|
||||
@ -2081,6 +2095,94 @@ struct wmi_tlv_stats_ev {
|
||||
__le32 num_peer_stats_extd;
|
||||
} __packed;
|
||||
|
||||
struct wmi_tlv_peer_stats_info_ev {
|
||||
__le32 vdev_id;
|
||||
__le32 num_peers;
|
||||
__le32 more_data;
|
||||
} __packed;
|
||||
|
||||
#define WMI_TLV_MAX_CHAINS 8
|
||||
|
||||
struct wmi_tlv_peer_stats_info {
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
struct {
|
||||
/* lower 32 bits of the tx_bytes value */
|
||||
__le32 low_32;
|
||||
/* upper 32 bits of the tx_bytes value */
|
||||
__le32 high_32;
|
||||
} __packed tx_bytes;
|
||||
struct {
|
||||
/* lower 32 bits of the tx_packets value */
|
||||
__le32 low_32;
|
||||
/* upper 32 bits of the tx_packets value */
|
||||
__le32 high_32;
|
||||
} __packed tx_packets;
|
||||
struct {
|
||||
/* lower 32 bits of the rx_bytes value */
|
||||
__le32 low_32;
|
||||
/* upper 32 bits of the rx_bytes value */
|
||||
__le32 high_32;
|
||||
} __packed rx_bytes;
|
||||
struct {
|
||||
/* lower 32 bits of the rx_packets value */
|
||||
__le32 low_32;
|
||||
/* upper 32 bits of the rx_packets value */
|
||||
__le32 high_32;
|
||||
} __packed rx_packets;
|
||||
__le32 tx_retries;
|
||||
__le32 tx_failed;
|
||||
|
||||
/* rate information, it is output of WMI_ASSEMBLE_RATECODE_V1
|
||||
* (in format of 0x1000RRRR)
|
||||
* The rate-code is a 4-bytes field in which,
|
||||
* for given rate, nss and preamble
|
||||
*
|
||||
* b'31-b'29 unused / reserved
|
||||
* b'28 indicate the version of rate-code (1 = RATECODE_V1)
|
||||
* b'27-b'11 unused / reserved
|
||||
* b'10-b'8 indicate the preamble (0 OFDM, 1 CCK, 2 HT, 3 VHT)
|
||||
* b'7-b'5 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3, 3 - 4x4)
|
||||
* b'4-b'0 indicate the rate, which is indicated as follows:
|
||||
* OFDM : 0: OFDM 48 Mbps
|
||||
* 1: OFDM 24 Mbps
|
||||
* 2: OFDM 12 Mbps
|
||||
* 3: OFDM 6 Mbps
|
||||
* 4: OFDM 54 Mbps
|
||||
* 5: OFDM 36 Mbps
|
||||
* 6: OFDM 18 Mbps
|
||||
* 7: OFDM 9 Mbps
|
||||
* CCK (pream == 1)
|
||||
* 0: CCK 11 Mbps Long
|
||||
* 1: CCK 5.5 Mbps Long
|
||||
* 2: CCK 2 Mbps Long
|
||||
* 3: CCK 1 Mbps Long
|
||||
* 4: CCK 11 Mbps Short
|
||||
* 5: CCK 5.5 Mbps Short
|
||||
* 6: CCK 2 Mbps Short
|
||||
* HT/VHT (pream == 2/3)
|
||||
* 0..7: MCS0..MCS7 (HT)
|
||||
* 0..9: MCS0..MCS9 (11AC VHT)
|
||||
* 0..11: MCS0..MCS11 (11AX VHT)
|
||||
* rate-code of the last transmission
|
||||
*/
|
||||
__le32 last_tx_rate_code;
|
||||
__le32 last_rx_rate_code;
|
||||
__le32 last_tx_bitrate_kbps;
|
||||
__le32 last_rx_bitrate_kbps;
|
||||
__le32 peer_rssi;
|
||||
__le32 tx_succeed;
|
||||
__le32 peer_rssi_per_chain[WMI_TLV_MAX_CHAINS];
|
||||
} __packed;
|
||||
|
||||
#define HW_RATECODE_PREAM_V1_MASK GENMASK(10, 8)
|
||||
#define WMI_TLV_GET_HW_RC_PREAM_V1(rc) FIELD_GET(HW_RATECODE_PREAM_V1_MASK, rc)
|
||||
|
||||
#define HW_RATECODE_NSS_V1_MASK GENMASK(7, 5)
|
||||
#define WMI_TLV_GET_HW_RC_NSS_V1(rc) FIELD_GET(HW_RATECODE_NSS_V1_MASK, rc)
|
||||
|
||||
#define HW_RATECODE_RATE_V1_MASK GENMASK(4, 0)
|
||||
#define WMI_TLV_GET_HW_RC_RATE_V1(rc) FIELD_GET(HW_RATECODE_RATE_V1_MASK, rc)
|
||||
|
||||
struct wmi_tlv_p2p_noa_ev {
|
||||
__le32 vdev_id;
|
||||
} __packed;
|
||||
@ -2097,6 +2199,14 @@ struct wmi_tlv_wow_add_del_event_cmd {
|
||||
__le32 event_bitmap;
|
||||
} __packed;
|
||||
|
||||
struct wmi_tlv_request_peer_stats_info {
|
||||
__le32 request_type;
|
||||
__le32 vdev_id;
|
||||
/* peer MAC address */
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
__le32 reset_after_request;
|
||||
} __packed;
|
||||
|
||||
/* Command to set/unset chip in quiet mode */
|
||||
struct wmi_tlv_set_quiet_cmd {
|
||||
__le32 vdev_id;
|
||||
|
@ -8336,7 +8336,7 @@ ath10k_wmi_fw_pdev_rx_stats_fill(const struct ath10k_fw_stats_pdev *pdev,
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to stack", pdev->loc_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Oversized AMSUs", pdev->oversize_amsdu);
|
||||
"Oversized AMSDUs", pdev->oversize_amsdu);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors", pdev->phy_errs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
|
@ -940,6 +940,7 @@ struct wmi_cmd_map {
|
||||
u32 vdev_spectral_scan_configure_cmdid;
|
||||
u32 vdev_spectral_scan_enable_cmdid;
|
||||
u32 request_stats_cmdid;
|
||||
u32 request_peer_stats_info_cmdid;
|
||||
u32 set_arp_ns_offload_cmdid;
|
||||
u32 network_list_offload_config_cmdid;
|
||||
u32 gtk_offload_cmdid;
|
||||
@ -3798,6 +3799,7 @@ struct wmi_pdev_param_map {
|
||||
u32 enable_btcoex;
|
||||
u32 rfkill_config;
|
||||
u32 rfkill_enable;
|
||||
u32 peer_stats_info_enable;
|
||||
};
|
||||
|
||||
#define WMI_PDEV_PARAM_UNSUPPORTED 0
|
||||
@ -4578,6 +4580,13 @@ struct wmi_request_stats_cmd {
|
||||
struct wlan_inst_rssi_args inst_rssi_args;
|
||||
} __packed;
|
||||
|
||||
enum wmi_peer_stats_info_request_type {
|
||||
/* request stats of one specified peer */
|
||||
WMI_REQUEST_ONE_PEER_STATS_INFO = 0x01,
|
||||
/* request stats of all peers belong to specified VDEV */
|
||||
WMI_REQUEST_VDEV_ALL_PEER_STATS_INFO = 0x02,
|
||||
};
|
||||
|
||||
/* Suspend option */
|
||||
enum {
|
||||
/* suspend */
|
||||
|
@ -60,9 +60,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
|
||||
WME_AC_VO);
|
||||
}
|
||||
|
||||
enum ath11k_skb_flags {
|
||||
ATH11K_SKB_HW_80211_ENCAP = BIT(0),
|
||||
};
|
||||
|
||||
struct ath11k_skb_cb {
|
||||
dma_addr_t paddr;
|
||||
u8 eid;
|
||||
u8 flags;
|
||||
struct ath11k *ar;
|
||||
struct ieee80211_vif *vif;
|
||||
} __packed;
|
||||
@ -392,6 +397,7 @@ struct ath11k_debug {
|
||||
u32 pktlog_mode;
|
||||
u32 pktlog_peer_valid;
|
||||
u8 pktlog_peer_addr[ETH_ALEN];
|
||||
u32 rx_filter;
|
||||
};
|
||||
|
||||
struct ath11k_per_peer_tx_stats {
|
||||
@ -656,6 +662,9 @@ struct ath11k_base {
|
||||
u32 fw_crash_counter;
|
||||
} stats;
|
||||
u32 pktlog_defs_checksum;
|
||||
|
||||
/* Round robbin based TCL ring selector */
|
||||
atomic_t tcl_ring_selector;
|
||||
};
|
||||
|
||||
struct ath11k_fw_stats_pdev {
|
||||
|
@ -195,7 +195,7 @@ void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
|
||||
total_vdevs_started += ar->num_started_vdevs;
|
||||
}
|
||||
|
||||
is_end = ((++num_vdev) == total_vdevs_started ? true : false);
|
||||
is_end = ((++num_vdev) == total_vdevs_started);
|
||||
|
||||
list_splice_tail_init(&stats.vdevs,
|
||||
&ar->debug.fw_stats.vdevs);
|
||||
@ -215,7 +215,7 @@ void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
|
||||
/* Mark end until we reached the count of all started VDEVs
|
||||
* within the PDEV
|
||||
*/
|
||||
is_end = ((++num_bcn) == ar->num_started_vdevs ? true : false);
|
||||
is_end = ((++num_bcn) == ar->num_started_vdevs);
|
||||
|
||||
list_splice_tail_init(&stats.bcn,
|
||||
&ar->debug.fw_stats.bcn);
|
||||
@ -698,6 +698,8 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file,
|
||||
tlv_filter = ath11k_mac_mon_status_filter_default;
|
||||
}
|
||||
|
||||
ar->debug.rx_filter = tlv_filter.rx_filter;
|
||||
|
||||
ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
|
||||
ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
|
||||
HAL_RXDMA_MONITOR_STATUS,
|
||||
@ -803,6 +805,9 @@ static const struct file_operations fops_soc_rx_stats = {
|
||||
|
||||
int ath11k_debug_pdev_create(struct ath11k_base *ab)
|
||||
{
|
||||
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
|
||||
return 0;
|
||||
|
||||
ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
|
||||
|
||||
if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
|
||||
|
@ -67,7 +67,7 @@ struct debug_htt_stats_req {
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
struct completion cmpln;
|
||||
u32 buf_len;
|
||||
u8 buf[0];
|
||||
u8 buf[];
|
||||
};
|
||||
|
||||
struct ath_pktlog_hdr {
|
||||
@ -77,9 +77,11 @@ struct ath_pktlog_hdr {
|
||||
u16 size;
|
||||
u32 timestamp;
|
||||
u32 type_specific_data;
|
||||
u8 payload[0];
|
||||
u8 payload[];
|
||||
};
|
||||
|
||||
#define ATH11K_HTT_PEER_STATS_RESET BIT(16)
|
||||
|
||||
#define ATH11K_HTT_STATS_BUF_SIZE (1024 * 512)
|
||||
#define ATH11K_FW_STATS_BUF_SIZE (1024 * 1024)
|
||||
|
||||
@ -188,6 +190,11 @@ static inline int ath11k_debug_is_extd_rx_stats_enabled(struct ath11k *ar)
|
||||
return ar->debug.extd_rx_stats;
|
||||
}
|
||||
|
||||
static inline int ath11k_debug_rx_filter(struct ath11k *ar)
|
||||
{
|
||||
return ar->debug.rx_filter;
|
||||
}
|
||||
|
||||
void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir);
|
||||
void
|
||||
@ -269,6 +276,11 @@ static inline bool ath11k_debug_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int ath11k_debug_rx_filter(struct ath11k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
|
||||
struct ath11k_per_peer_tx_stats *peer_stats,
|
||||
|
@ -239,7 +239,7 @@ struct htt_tx_pdev_stats_tx_ppdu_stats_tlv_v {
|
||||
*/
|
||||
struct htt_tx_pdev_stats_tried_mpdu_cnt_hist_tlv_v {
|
||||
u32 hist_bin_size;
|
||||
u32 tried_mpdu_cnt_hist[0]; /* HTT_TX_PDEV_TRIED_MPDU_CNT_HIST */
|
||||
u32 tried_mpdu_cnt_hist[]; /* HTT_TX_PDEV_TRIED_MPDU_CNT_HIST */
|
||||
};
|
||||
|
||||
/* == SOC ERROR STATS == */
|
||||
@ -550,7 +550,7 @@ struct htt_tx_hwq_stats_cmn_tlv {
|
||||
struct htt_tx_hwq_difs_latency_stats_tlv_v {
|
||||
u32 hist_intvl;
|
||||
/* histogram of ppdu post to hwsch - > cmd status received */
|
||||
u32 difs_latency_hist[0]; /* HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS */
|
||||
u32 difs_latency_hist[]; /* HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS */
|
||||
};
|
||||
|
||||
/* NOTE: Variable length TLV, use length spec to infer array size */
|
||||
@ -586,7 +586,7 @@ struct htt_tx_hwq_fes_result_stats_tlv_v {
|
||||
struct htt_tx_hwq_tried_mpdu_cnt_hist_tlv_v {
|
||||
u32 hist_bin_size;
|
||||
/* Histogram of number of mpdus on tried mpdu */
|
||||
u32 tried_mpdu_cnt_hist[0]; /* HTT_TX_HWQ_TRIED_MPDU_CNT_HIST */
|
||||
u32 tried_mpdu_cnt_hist[]; /* HTT_TX_HWQ_TRIED_MPDU_CNT_HIST */
|
||||
};
|
||||
|
||||
/* NOTE: Variable length TLV, use length spec to infer array size
|
||||
@ -1584,7 +1584,7 @@ struct htt_pdev_stats_twt_session_tlv {
|
||||
struct htt_pdev_stats_twt_sessions_tlv {
|
||||
u32 pdev_id;
|
||||
u32 num_sessions;
|
||||
struct htt_pdev_stats_twt_session_tlv twt_session[0];
|
||||
struct htt_pdev_stats_twt_session_tlv twt_session[];
|
||||
};
|
||||
|
||||
enum htt_rx_reo_resource_sample_id_enum {
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "core.h"
|
||||
#include "peer.h"
|
||||
#include "debug.h"
|
||||
#include "dp_tx.h"
|
||||
#include "debug_htt_stats.h"
|
||||
|
||||
void
|
||||
ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
|
||||
@ -435,13 +437,22 @@ ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
out:
|
||||
vfree(stats_req);
|
||||
ar->debug.htt_stats.stats_req = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ieee80211_sta *sta = inode->i_private;
|
||||
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
||||
struct ath11k *ar = arsta->arvif->ar;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
vfree(file->private_data);
|
||||
ar->debug.htt_stats.stats_req = NULL;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -749,6 +760,66 @@ static const struct file_operations fops_aggr_mode = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
ath11k_write_htt_peer_stats_reset(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
||||
struct ath11k *ar = arsta->arvif->ar;
|
||||
struct htt_ext_stats_cfg_params cfg_params = { 0 };
|
||||
int ret;
|
||||
u8 type;
|
||||
|
||||
ret = kstrtou8_from_user(user_buf, count, 0, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!type)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
|
||||
cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
|
||||
HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
|
||||
|
||||
cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
|
||||
|
||||
cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
|
||||
cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
|
||||
cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
|
||||
cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
|
||||
|
||||
cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
|
||||
cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
|
||||
|
||||
cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
|
||||
|
||||
ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
|
||||
ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
|
||||
&cfg_params,
|
||||
0ULL);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
ret = count;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_htt_peer_stats_reset = {
|
||||
.write = ath11k_write_htt_peer_stats_reset,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir)
|
||||
{
|
||||
@ -771,4 +842,9 @@ void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
|
||||
debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
|
||||
debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
|
||||
|
||||
if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
|
||||
ar->ab->wmi_ab.svc_map))
|
||||
debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
|
||||
&fops_htt_peer_stats_reset);
|
||||
}
|
||||
|
@ -880,6 +880,8 @@ int ath11k_dp_alloc(struct ath11k_base *ab)
|
||||
INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list);
|
||||
spin_lock_init(&dp->reo_cmd_lock);
|
||||
|
||||
dp->reo_cmd_cache_flush_count = 0;
|
||||
|
||||
ret = ath11k_wbm_idle_ring_setup(ab, &n_link_desc);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret);
|
||||
@ -909,8 +911,10 @@ int ath11k_dp_alloc(struct ath11k_base *ab)
|
||||
dp->tx_ring[i].tx_status_head = 0;
|
||||
dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE - 1;
|
||||
dp->tx_ring[i].tx_status = kmalloc(size, GFP_KERNEL);
|
||||
if (!dp->tx_ring[i].tx_status)
|
||||
if (!dp->tx_ring[i].tx_status) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_cmn_srng_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < HAL_DSCP_TID_MAP_TBL_NUM_ENTRIES_MAX; i++)
|
||||
|
@ -36,6 +36,7 @@ struct dp_rx_tid {
|
||||
struct ath11k_base *ab;
|
||||
};
|
||||
|
||||
#define DP_REO_DESC_FREE_THRESHOLD 64
|
||||
#define DP_REO_DESC_FREE_TIMEOUT_MS 1000
|
||||
|
||||
struct dp_reo_cache_flush_elem {
|
||||
@ -222,7 +223,13 @@ struct ath11k_dp {
|
||||
struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
|
||||
struct list_head reo_cmd_list;
|
||||
struct list_head reo_cmd_cache_flush_list;
|
||||
/* protects access to reo_cmd_list and reo_cmd_cache_flush_list */
|
||||
u32 reo_cmd_cache_flush_count;
|
||||
/**
|
||||
* protects access to below fields,
|
||||
* - reo_cmd_list
|
||||
* - reo_cmd_cache_flush_list
|
||||
* - reo_cmd_cache_flush_count
|
||||
*/
|
||||
spinlock_t reo_cmd_lock;
|
||||
};
|
||||
|
||||
|
@ -252,7 +252,7 @@ static bool ath11k_dp_rxdesc_mpdu_valid(struct hal_rx_desc *rx_desc)
|
||||
tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG,
|
||||
__le32_to_cpu(rx_desc->mpdu_start_tag));
|
||||
|
||||
return tlv_tag == HAL_RX_MPDU_START ? true : false;
|
||||
return tlv_tag == HAL_RX_MPDU_START;
|
||||
}
|
||||
|
||||
static u32 ath11k_dp_rxdesc_get_ppduid(struct hal_rx_desc *rx_desc)
|
||||
@ -565,6 +565,7 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
|
||||
list_for_each_entry_safe(cmd_cache, tmp_cache,
|
||||
&dp->reo_cmd_cache_flush_list, list) {
|
||||
list_del(&cmd_cache->list);
|
||||
dp->reo_cmd_cache_flush_count--;
|
||||
dma_unmap_single(ab->dev, cmd_cache->data.paddr,
|
||||
cmd_cache->data.size, DMA_BIDIRECTIONAL);
|
||||
kfree(cmd_cache->data.vaddr);
|
||||
@ -651,15 +652,18 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
|
||||
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list);
|
||||
dp->reo_cmd_cache_flush_count++;
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
|
||||
/* Flush and invalidate aged REO desc from HW cache */
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list,
|
||||
list) {
|
||||
if (time_after(jiffies, elem->ts +
|
||||
if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
|
||||
time_after(jiffies, elem->ts +
|
||||
msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) {
|
||||
list_del(&elem->list);
|
||||
dp->reo_cmd_cache_flush_count--;
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
|
||||
ath11k_dp_reo_cache_flush(ab, &elem->data);
|
||||
@ -892,7 +896,7 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
|
||||
else
|
||||
hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
|
||||
|
||||
vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_KERNEL);
|
||||
vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
|
||||
if (!vaddr) {
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
return -ENOMEM;
|
||||
@ -2266,6 +2270,7 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *last_buf;
|
||||
u8 l3_pad_bytes;
|
||||
u8 *hdr_status;
|
||||
u16 msdu_len;
|
||||
int ret;
|
||||
|
||||
@ -2294,8 +2299,13 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
|
||||
skb_pull(msdu, HAL_RX_DESC_SIZE);
|
||||
} else if (!rxcb->is_continuation) {
|
||||
if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
|
||||
hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
|
||||
ret = -EINVAL;
|
||||
ath11k_warn(ar->ab, "invalid msdu len %u\n", msdu_len);
|
||||
ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
|
||||
sizeof(struct ieee80211_hdr));
|
||||
ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc,
|
||||
sizeof(struct hal_rx_desc));
|
||||
goto free_out;
|
||||
}
|
||||
skb_put(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes + msdu_len);
|
||||
@ -2961,8 +2971,8 @@ static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer
|
||||
return 0;
|
||||
|
||||
mic_fail:
|
||||
(ATH11K_SKB_RXCB(msdu))->is_first_msdu = 1;
|
||||
(ATH11K_SKB_RXCB(msdu))->is_last_msdu = 1;
|
||||
(ATH11K_SKB_RXCB(msdu))->is_first_msdu = true;
|
||||
(ATH11K_SKB_RXCB(msdu))->is_last_msdu = true;
|
||||
|
||||
rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED |
|
||||
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
|
||||
@ -3390,6 +3400,7 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool
|
||||
struct sk_buff *msdu;
|
||||
struct ath11k_skb_rxcb *rxcb;
|
||||
struct hal_rx_desc *rx_desc;
|
||||
u8 *hdr_status;
|
||||
u16 msdu_len;
|
||||
|
||||
spin_lock_bh(&rx_ring->idr_lock);
|
||||
@ -3427,6 +3438,17 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool
|
||||
|
||||
rx_desc = (struct hal_rx_desc *)msdu->data;
|
||||
msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
|
||||
if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
|
||||
hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
|
||||
ath11k_warn(ar->ab, "invalid msdu leng %u", msdu_len);
|
||||
ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
|
||||
sizeof(struct ieee80211_hdr));
|
||||
ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc,
|
||||
sizeof(struct hal_rx_desc));
|
||||
dev_kfree_skb_any(msdu);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
skb_put(msdu, HAL_RX_DESC_SIZE + msdu_len);
|
||||
|
||||
if (ath11k_dp_rx_frag_h_mpdu(ar, msdu, ring_desc)) {
|
||||
|
@ -9,14 +9,14 @@
|
||||
#include "hw.h"
|
||||
#include "peer.h"
|
||||
|
||||
/* NOTE: Any of the mapped ring id value must not exceed DP_TCL_NUM_RING_MAX */
|
||||
static const u8
|
||||
ath11k_txq_tcl_ring_map[ATH11K_HW_MAX_QUEUES] = { 0x0, 0x1, 0x2, 0x2 };
|
||||
|
||||
static enum hal_tcl_encap_type
|
||||
ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
|
||||
{
|
||||
/* TODO: Determine encap type based on vif_type and configuration */
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (tx_info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
|
||||
return HAL_TCL_ENCAP_TYPE_ETHERNET;
|
||||
|
||||
return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
|
||||
}
|
||||
|
||||
@ -40,8 +40,11 @@ static void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb)
|
||||
static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ath11k_skb_cb *cb = ATH11K_SKB_CB(skb);
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
if (cb->flags & ATH11K_SKB_HW_80211_ENCAP)
|
||||
return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
else if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
return HAL_DESC_REO_NON_QOS_TID;
|
||||
else
|
||||
return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
@ -84,15 +87,31 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
u8 pool_id;
|
||||
u8 hal_ring_id;
|
||||
int ret;
|
||||
u8 ring_selector = 0, ring_map = 0;
|
||||
bool tcl_ring_retry;
|
||||
|
||||
if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
|
||||
return -ESHUTDOWN;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
|
||||
!ieee80211_is_data(hdr->frame_control))
|
||||
return -ENOTSUPP;
|
||||
|
||||
pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
|
||||
ti.ring_id = ath11k_txq_tcl_ring_map[pool_id];
|
||||
|
||||
/* Let the default ring selection be based on a round robin
|
||||
* fashion where one of the 3 tcl rings are selected based on
|
||||
* the tcl_ring_selector counter. In case that ring
|
||||
* is full/busy, we resort to other available rings.
|
||||
* If all rings are full, we drop the packet.
|
||||
* //TODO Add throttling logic when all rings are full
|
||||
*/
|
||||
ring_selector = atomic_inc_return(&ab->tcl_ring_selector);
|
||||
|
||||
tcl_ring_sel:
|
||||
tcl_ring_retry = false;
|
||||
ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX;
|
||||
ring_map |= BIT(ti.ring_id);
|
||||
|
||||
tx_ring = &dp->tx_ring[ti.ring_id];
|
||||
|
||||
@ -101,8 +120,14 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
DP_TX_IDR_SIZE - 1, GFP_ATOMIC);
|
||||
spin_unlock_bh(&tx_ring->tx_idr_lock);
|
||||
|
||||
if (ret < 0)
|
||||
return -ENOSPC;
|
||||
if (ret < 0) {
|
||||
if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1))
|
||||
return -ENOSPC;
|
||||
|
||||
/* Check if the next ring is available */
|
||||
ring_selector++;
|
||||
goto tcl_ring_sel;
|
||||
}
|
||||
|
||||
ti.desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, ar->pdev_idx) |
|
||||
FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) |
|
||||
@ -149,7 +174,10 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
* skb_checksum_help() is needed
|
||||
*/
|
||||
case HAL_TCL_ENCAP_TYPE_ETHERNET:
|
||||
/* no need to encap */
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_802_3:
|
||||
default:
|
||||
/* TODO: Take care of other encap modes as well */
|
||||
ret = -EINVAL;
|
||||
goto fail_remove_idr;
|
||||
@ -178,11 +206,21 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
if (!hal_tcl_desc) {
|
||||
/* NOTE: It is highly unlikely we'll be running out of tcl_ring
|
||||
* desc because the desc is directly enqueued onto hw queue.
|
||||
* So add tx packet throttling logic in future if required.
|
||||
*/
|
||||
ath11k_hal_srng_access_end(ab, tcl_ring);
|
||||
spin_unlock_bh(&tcl_ring->lock);
|
||||
ret = -ENOMEM;
|
||||
|
||||
/* Checking for available tcl descritors in another ring in
|
||||
* case of failure due to full tcl ring now, is better than
|
||||
* checking this ring earlier for each pkt tx.
|
||||
* Restart ring selection if some rings are not checked yet.
|
||||
*/
|
||||
if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1)) {
|
||||
tcl_ring_retry = true;
|
||||
ring_selector++;
|
||||
}
|
||||
|
||||
goto fail_unmap_dma;
|
||||
}
|
||||
|
||||
@ -206,6 +244,9 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id));
|
||||
spin_unlock_bh(&tx_ring->tx_idr_lock);
|
||||
|
||||
if (tcl_ring_retry)
|
||||
goto tcl_ring_sel;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -543,8 +584,12 @@ int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid,
|
||||
cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id];
|
||||
cmd_num = ath11k_hal_reo_cmd_send(ab, cmd_ring, type, cmd);
|
||||
|
||||
/* cmd_num should start from 1, during failure return the error code */
|
||||
if (cmd_num < 0)
|
||||
return cmd_num;
|
||||
|
||||
/* reo cmd ring descriptors has cmd_num starting from 1 */
|
||||
if (cmd_num <= 0)
|
||||
if (cmd_num == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!cb)
|
||||
|
@ -477,7 +477,7 @@ enum hal_tlv_tag {
|
||||
|
||||
struct hal_tlv_hdr {
|
||||
u32 tl;
|
||||
u8 value[0];
|
||||
u8 value[];
|
||||
} __packed;
|
||||
|
||||
#define RX_MPDU_DESC_INFO0_MSDU_COUNT GENMASK(7, 0)
|
||||
@ -1972,7 +1972,7 @@ struct hal_rx_reo_queue {
|
||||
u32 processed_total_bytes;
|
||||
u32 info5;
|
||||
u32 rsvd[3];
|
||||
struct hal_rx_reo_queue_ext ext_desc[0];
|
||||
struct hal_rx_reo_queue_ext ext_desc[];
|
||||
} __packed;
|
||||
|
||||
/* hal_rx_reo_queue
|
||||
|
@ -23,7 +23,7 @@ struct hal_rx_wbm_rel_info {
|
||||
|
||||
struct hal_rx_mon_status_tlv_hdr {
|
||||
u32 hdr;
|
||||
u8 value[0];
|
||||
u8 value[];
|
||||
};
|
||||
|
||||
enum hal_rx_su_mu_coding {
|
||||
|
@ -111,7 +111,7 @@ struct ath11k_hw_params {
|
||||
struct ath11k_fw_ie {
|
||||
__le32 id;
|
||||
__le32 len;
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
enum ath11k_bd_ie_board_type {
|
||||
|
@ -33,6 +33,12 @@
|
||||
.max_power = 30, \
|
||||
}
|
||||
|
||||
/* frame mode values are mapped as per enum ath11k_hw_txrx_mode */
|
||||
static unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI;
|
||||
module_param_named(frame_mode, ath11k_frame_mode, uint, 0644);
|
||||
MODULE_PARM_DESC(frame_mode,
|
||||
"Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");
|
||||
|
||||
static const struct ieee80211_channel ath11k_2ghz_channels[] = {
|
||||
CHAN2G(1, 2412, 0),
|
||||
CHAN2G(2, 2417, 0),
|
||||
@ -1142,6 +1148,10 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
|
||||
arg->tx_mcs_set &= ~IEEE80211_VHT_MCS_SUPPORT_0_11_MASK;
|
||||
arg->tx_mcs_set |= IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11;
|
||||
|
||||
if ((arg->tx_mcs_set & IEEE80211_VHT_MCS_NOT_SUPPORTED) ==
|
||||
IEEE80211_VHT_MCS_NOT_SUPPORTED)
|
||||
arg->peer_vht_caps &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||
|
||||
/* TODO: Check */
|
||||
arg->tx_max_mcs_nss = 0xFF;
|
||||
|
||||
@ -3682,10 +3692,10 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
|
||||
|
||||
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
|
||||
{
|
||||
struct sk_buff *msdu = skb;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
|
||||
struct ath11k *ar = ctx;
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct sk_buff *msdu = skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
spin_lock_bh(&ar->txmgmt_idr_lock);
|
||||
idr_remove(&ar->txmgmt_idr, buf_id);
|
||||
@ -3725,6 +3735,7 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
{
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *info;
|
||||
dma_addr_t paddr;
|
||||
int buf_id;
|
||||
int ret;
|
||||
@ -3736,11 +3747,14 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
if (buf_id < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
skb_put(skb, IEEE80211_CCMP_MIC_LEN);
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) {
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
skb_put(skb, IEEE80211_CCMP_MIC_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
||||
@ -3789,15 +3803,30 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
||||
|
||||
while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) {
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
arvif = ath11k_vif_to_arvif(info->control.vif);
|
||||
|
||||
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to transmit management frame %d\n",
|
||||
ret);
|
||||
if (!info->control.vif) {
|
||||
ath11k_warn(ar->ab, "no vif found for mgmt frame, flags 0x%x\n",
|
||||
info->control.flags);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
arvif = ath11k_vif_to_arvif(info->control.vif);
|
||||
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
|
||||
arvif->is_started) {
|
||||
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
|
||||
if (ret) {
|
||||
ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n",
|
||||
arvif->vdev_id, ret);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
} else {
|
||||
atomic_inc(&ar->num_pending_mgmt_tx);
|
||||
}
|
||||
} else {
|
||||
atomic_inc(&ar->num_pending_mgmt_tx);
|
||||
ath11k_warn(ar->ab,
|
||||
"dropping mgmt frame for vdev %d, flags 0x%x is_started %d\n",
|
||||
arvif->vdev_id, info->control.flags,
|
||||
arvif->is_started);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3837,6 +3866,7 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_control *control,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
|
||||
struct ath11k *ar = hw->priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
@ -3845,7 +3875,9 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
|
||||
bool is_prb_rsp;
|
||||
int ret;
|
||||
|
||||
if (ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
|
||||
skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
|
||||
} else if (ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
|
||||
ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp);
|
||||
if (ret) {
|
||||
@ -3877,8 +3909,10 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
|
||||
struct htt_rx_ring_tlv_filter tlv_filter = {0};
|
||||
u32 ring_id;
|
||||
|
||||
if (enable)
|
||||
if (enable) {
|
||||
tlv_filter = ath11k_mac_mon_status_filter_default;
|
||||
tlv_filter.rx_filter = ath11k_debug_rx_filter(ar);
|
||||
}
|
||||
|
||||
ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
|
||||
|
||||
@ -4124,6 +4158,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
||||
struct vdev_create_params vdev_param = {0};
|
||||
struct peer_create_params peer_param;
|
||||
u32 param_id, param_value;
|
||||
int hw_encap = 0;
|
||||
u16 nss;
|
||||
int i;
|
||||
int ret;
|
||||
@ -4208,6 +4243,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
ar->num_created_vdevs++;
|
||||
ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
|
||||
vif->addr, arvif->vdev_id);
|
||||
ar->allocated_vdev_map |= 1LL << arvif->vdev_id;
|
||||
ab->free_vdev_map &= ~(1LL << arvif->vdev_id);
|
||||
|
||||
@ -4216,7 +4253,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
|
||||
param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
|
||||
if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET)
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_AP:
|
||||
hw_encap = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ieee80211_set_hw_80211_encap(vif, hw_encap))
|
||||
param_value = ATH11K_HW_TXRX_ETHERNET;
|
||||
else
|
||||
param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
|
||||
|
||||
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
|
||||
param_id, param_value);
|
||||
if (ret) {
|
||||
@ -4378,6 +4430,8 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
|
||||
arvif->vdev_id, ret);
|
||||
|
||||
ar->num_created_vdevs--;
|
||||
ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
|
||||
vif->addr, arvif->vdev_id);
|
||||
ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
|
||||
ab->free_vdev_map |= 1LL << (arvif->vdev_id);
|
||||
|
||||
@ -4643,6 +4697,8 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
|
||||
}
|
||||
|
||||
ar->num_started_vdevs++;
|
||||
ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM started, vdev_id %d\n",
|
||||
arvif->vif->addr, arvif->vdev_id);
|
||||
|
||||
/* Enable CAC Flag in the driver by checking the channel DFS cac time,
|
||||
* i.e dfs_cac_ms value which will be valid only for radar channels
|
||||
@ -4701,6 +4757,8 @@ static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif)
|
||||
WARN_ON(ar->num_started_vdevs == 0);
|
||||
|
||||
ar->num_started_vdevs--;
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n",
|
||||
arvif->vif->addr, arvif->vdev_id);
|
||||
|
||||
if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
|
||||
clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
|
||||
@ -5891,6 +5949,9 @@ int ath11k_mac_register(struct ath11k_base *ab)
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
pdev = &ab->pdevs[i];
|
||||
ar = pdev->ar;
|
||||
|
@ -39,7 +39,7 @@ struct wmi_cmd_hdr {
|
||||
|
||||
struct wmi_tlv {
|
||||
u32 header;
|
||||
u8 value[0];
|
||||
u8 value[];
|
||||
} __packed;
|
||||
|
||||
#define WMI_TLV_LEN GENMASK(15, 0)
|
||||
@ -1976,6 +1976,43 @@ enum wmi_tlv_service {
|
||||
WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI = 174,
|
||||
WMI_TLV_SERVICE_NAN_DISABLE_SUPPORT = 175,
|
||||
WMI_TLV_SERVICE_HTT_H2T_NO_HTC_HDR_LEN_IN_MSG_LEN = 176,
|
||||
WMI_TLV_SERVICE_COEX_SUPPORT_UNEQUAL_ISOLATION = 177,
|
||||
WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT = 178,
|
||||
WMI_TLV_SERVICE_SUPPORT_EXTEND_ADDRESS = 179,
|
||||
WMI_TLV_SERVICE_BEACON_RECEPTION_STATS = 180,
|
||||
WMI_TLV_SERVICE_FETCH_TX_PN = 181,
|
||||
WMI_TLV_SERVICE_PEER_UNMAP_RESPONSE_SUPPORT = 182,
|
||||
WMI_TLV_SERVICE_TX_PER_PEER_AMPDU_SIZE = 183,
|
||||
WMI_TLV_SERVICE_BSS_COLOR_SWITCH_COUNT = 184,
|
||||
WMI_TLV_SERVICE_HTT_PEER_STATS_SUPPORT = 185,
|
||||
WMI_TLV_SERVICE_UL_RU26_ALLOWED = 186,
|
||||
WMI_TLV_SERVICE_GET_MWS_COEX_STATE = 187,
|
||||
WMI_TLV_SERVICE_GET_MWS_DPWB_STATE = 188,
|
||||
WMI_TLV_SERVICE_GET_MWS_TDM_STATE = 189,
|
||||
WMI_TLV_SERVICE_GET_MWS_IDRX_STATE = 190,
|
||||
WMI_TLV_SERVICE_GET_MWS_ANTENNA_SHARING_STATE = 191,
|
||||
WMI_TLV_SERVICE_ENHANCED_TPC_CONFIG_EVENT = 192,
|
||||
WMI_TLV_SERVICE_WLM_STATS_REQUEST = 193,
|
||||
WMI_TLV_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT = 194,
|
||||
WMI_TLV_SERVICE_WPA3_FT_SAE_SUPPORT = 195,
|
||||
WMI_TLV_SERVICE_WPA3_FT_SUITE_B_SUPPORT = 196,
|
||||
WMI_TLV_SERVICE_VOW_ENABLE = 197,
|
||||
WMI_TLV_SERVICE_CFR_CAPTURE_IND_EVT_TYPE_1 = 198,
|
||||
WMI_TLV_SERVICE_BROADCAST_TWT = 199,
|
||||
WMI_TLV_SERVICE_RAP_DETECTION_SUPPORT = 200,
|
||||
WMI_TLV_SERVICE_PS_TDCC = 201,
|
||||
WMI_TLV_SERVICE_THREE_WAY_COEX_CONFIG_LEGACY = 202,
|
||||
WMI_TLV_SERVICE_THREE_WAY_COEX_CONFIG_OVERRIDE = 203,
|
||||
WMI_TLV_SERVICE_TX_PWR_PER_PEER = 204,
|
||||
WMI_TLV_SERVICE_STA_PLUS_STA_SUPPORT = 205,
|
||||
WMI_TLV_SERVICE_WPA3_FT_FILS = 206,
|
||||
WMI_TLV_SERVICE_ADAPTIVE_11R_ROAM = 207,
|
||||
WMI_TLV_SERVICE_CHAN_RF_CHARACTERIZATION_INFO = 208,
|
||||
WMI_TLV_SERVICE_FW_IFACE_COMBINATION_SUPPORT = 209,
|
||||
WMI_TLV_SERVICE_TX_COMPL_TSF64 = 210,
|
||||
WMI_TLV_SERVICE_DSM_ROAM_FILTER = 211,
|
||||
WMI_TLV_SERVICE_PACKET_CAPTURE_SUPPORT = 212,
|
||||
WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213,
|
||||
|
||||
WMI_MAX_EXT_SERVICE
|
||||
|
||||
@ -4568,6 +4605,9 @@ enum wmi_sta_ps_param_rx_wake_policy {
|
||||
WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1,
|
||||
};
|
||||
|
||||
/* Do not change existing values! Used by ath11k_frame_mode parameter
|
||||
* module parameter.
|
||||
*/
|
||||
enum ath11k_hw_txrx_mode {
|
||||
ATH11K_HW_TXRX_RAW = 0,
|
||||
ATH11K_HW_TXRX_NATIVE_WIFI = 1,
|
||||
|
@ -501,7 +501,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
|
||||
|
||||
if (as->ofdm_errors > ofdm_high || as->cck_errors > cck_high) {
|
||||
/* too many PHY errors - we have to raise immunity */
|
||||
bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false;
|
||||
bool ofdm_flag = as->ofdm_errors > ofdm_high;
|
||||
ath5k_ani_raise_immunity(ah, as, ofdm_flag);
|
||||
ath5k_ani_period_restart(as);
|
||||
|
||||
|
@ -160,7 +160,7 @@ enum ath6kl_fw_capability {
|
||||
struct ath6kl_fw_ie {
|
||||
__le32 id;
|
||||
__le32 len;
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
enum ath6kl_hw_flags {
|
||||
@ -406,7 +406,7 @@ struct ath6kl_mgmt_buff {
|
||||
u32 id;
|
||||
bool no_cck;
|
||||
size_t len;
|
||||
u8 buf[0];
|
||||
u8 buf[];
|
||||
};
|
||||
|
||||
struct ath6kl_sta {
|
||||
|
@ -30,7 +30,7 @@ struct ath6kl_fwlog_slot {
|
||||
__le32 length;
|
||||
|
||||
/* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
|
||||
u8 payload[0];
|
||||
u8 payload[];
|
||||
};
|
||||
|
||||
#define ATH6KL_FWLOG_MAX_ENTRIES 20
|
||||
|
@ -199,7 +199,7 @@ struct hif_scatter_req {
|
||||
|
||||
u32 scat_q_depth;
|
||||
|
||||
struct hif_scatter_item scat_list[0];
|
||||
struct hif_scatter_item scat_list[];
|
||||
};
|
||||
|
||||
struct ath6kl_irq_proc_registers {
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "ar9002_phy.h"
|
||||
|
||||
#define AR9285_CLCAL_REDO_THRESH 1
|
||||
/* AGC & I/Q calibrations time limit, ms */
|
||||
#define AR9002_CAL_MAX_TIME 30000
|
||||
|
||||
enum ar9002_cal_types {
|
||||
ADC_GAIN_CAL = BIT(0),
|
||||
@ -37,9 +39,8 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
|
||||
break;
|
||||
case ADC_GAIN_CAL:
|
||||
case ADC_DC_CAL:
|
||||
/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
|
||||
if (!((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
|
||||
IS_CHAN_HT20(chan)))
|
||||
/* Run even/odd ADCs calibrations for HT40 channels only */
|
||||
if (IS_CHAN_HT40(chan))
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
@ -105,6 +106,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
|
||||
} else {
|
||||
ar9002_hw_setup_calibration(ah, currCal);
|
||||
}
|
||||
} else if (time_after(jiffies, ah->cal_start_time +
|
||||
msecs_to_jiffies(AR9002_CAL_MAX_TIME))) {
|
||||
REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0),
|
||||
AR_PHY_TIMING_CTRL4_DO_CAL);
|
||||
ath_dbg(ath9k_hw_common(ah), CALIBRATE,
|
||||
"calibration timeout\n");
|
||||
currCal->calState = CAL_WAITING; /* Try later */
|
||||
iscaldone = true;
|
||||
}
|
||||
} else if (!(caldata->CalValid & currCal->calData->calType)) {
|
||||
ath9k_hw_reset_calibration(ah, currCal);
|
||||
@ -664,8 +673,13 @@ static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
int ret;
|
||||
|
||||
nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
|
||||
if (ah->caldata)
|
||||
if (ah->caldata) {
|
||||
nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
|
||||
if (longcal) /* Remember to not miss */
|
||||
set_bit(LONGCAL_PENDING, &ah->caldata->cal_flags);
|
||||
else if (test_bit(LONGCAL_PENDING, &ah->caldata->cal_flags))
|
||||
longcal = true; /* Respin a previous one */
|
||||
}
|
||||
|
||||
percal_pending = (currCal &&
|
||||
(currCal->calState == CAL_RUNNING ||
|
||||
@ -675,9 +689,24 @@ static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
|
||||
return 0;
|
||||
|
||||
ah->cal_list_curr = currCal = currCal->calNext;
|
||||
if (currCal->calState == CAL_WAITING)
|
||||
ath9k_hw_reset_calibration(ah, currCal);
|
||||
/* Looking for next waiting calibration if any */
|
||||
for (currCal = currCal->calNext; currCal != ah->cal_list_curr;
|
||||
currCal = currCal->calNext) {
|
||||
if (currCal->calState == CAL_WAITING)
|
||||
break;
|
||||
}
|
||||
if (currCal->calState == CAL_WAITING) {
|
||||
percal_pending = true;
|
||||
ah->cal_list_curr = currCal;
|
||||
} else {
|
||||
percal_pending = false;
|
||||
ah->cal_list_curr = ah->cal_list;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not start a next calibration if the longcal is in action */
|
||||
if (percal_pending && !nfcal && !longcal) {
|
||||
ath9k_hw_reset_calibration(ah, currCal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -701,6 +730,9 @@ static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
}
|
||||
|
||||
if (longcal) {
|
||||
if (ah->caldata)
|
||||
clear_bit(LONGCAL_PENDING,
|
||||
&ah->caldata->cal_flags);
|
||||
ath9k_hw_start_nfcal(ah, false);
|
||||
/* Do periodic PAOffset Cal */
|
||||
ar9002_hw_pa_cal(ah, false);
|
||||
@ -858,9 +890,6 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
ath9k_hw_loadnf(ah, chan);
|
||||
ath9k_hw_start_nfcal(ah, true);
|
||||
|
||||
if (ah->caldata)
|
||||
set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
|
||||
|
||||
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
|
||||
|
||||
/* Enable IQ, ADC Gain and ADC DC offset CALs */
|
||||
|
@ -176,6 +176,7 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
||||
|
||||
ath9k_hw_setup_calibration(ah, currCal);
|
||||
|
||||
ah->cal_start_time = jiffies;
|
||||
currCal->calState = CAL_RUNNING;
|
||||
|
||||
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
|
||||
@ -209,14 +210,17 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(ah->supp_cals & currCal->calData->calType))
|
||||
return true;
|
||||
currCal = ah->cal_list;
|
||||
do {
|
||||
ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n",
|
||||
currCal->calData->calType,
|
||||
ah->curchan->chan->center_freq);
|
||||
|
||||
ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n",
|
||||
currCal->calData->calType, ah->curchan->chan->center_freq);
|
||||
ah->caldata->CalValid &= ~currCal->calData->calType;
|
||||
currCal->calState = CAL_WAITING;
|
||||
|
||||
ah->caldata->CalValid &= ~currCal->calData->calType;
|
||||
currCal->calState = CAL_WAITING;
|
||||
currCal = currCal->calNext;
|
||||
} while (currCal != ah->cal_list);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -999,9 +999,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
|
||||
* which are not PHY_ERROR (short radar pulses have a length of 3)
|
||||
*/
|
||||
if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) {
|
||||
ath_warn(common,
|
||||
"Short RX data len, dropping (dlen: %d)\n",
|
||||
rs_datalen);
|
||||
ath_dbg(common, ANY,
|
||||
"Short RX data len, dropping (dlen: %d)\n",
|
||||
rs_datalen);
|
||||
goto rx_next;
|
||||
}
|
||||
|
||||
|
@ -427,6 +427,7 @@ enum ath9k_cal_flags {
|
||||
TXIQCAL_DONE,
|
||||
TXCLCAL_DONE,
|
||||
SW_PKDET_DONE,
|
||||
LONGCAL_PENDING,
|
||||
};
|
||||
|
||||
struct ath9k_hw_cal_data {
|
||||
@ -833,6 +834,7 @@ struct ath_hw {
|
||||
|
||||
/* Calibration */
|
||||
u32 supp_cals;
|
||||
unsigned long cal_start_time;
|
||||
struct ath9k_cal_list iq_caldata;
|
||||
struct ath9k_cal_list adcgain_caldata;
|
||||
struct ath9k_cal_list adcdc_caldata;
|
||||
|
@ -338,9 +338,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
if (SUPP(CARL9170FW_WLANTX_CAB)) {
|
||||
if_comb_types |=
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
if_comb_types |= BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if_comb_types |=
|
||||
|
@ -582,11 +582,10 @@ static int carl9170_init_interface(struct ar9170 *ar,
|
||||
ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
|
||||
(vif->type != NL80211_IFTYPE_AP));
|
||||
|
||||
/* While the driver supports HW offload in a single
|
||||
* P2P client configuration, it doesn't support HW
|
||||
* offload in the favourit, concurrent P2P GO+CLIENT
|
||||
* configuration. Hence, HW offload will always be
|
||||
* disabled for P2P.
|
||||
/* The driver used to have P2P GO+CLIENT support,
|
||||
* but since this was dropped and we don't know if
|
||||
* there are any gremlins lurking in the shadows,
|
||||
* so best we keep HW offload disabled for P2P.
|
||||
*/
|
||||
ar->disable_offload |= vif->p2p;
|
||||
|
||||
@ -639,18 +638,6 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
break;
|
||||
|
||||
/* P2P GO [master] use-case
|
||||
* Because the P2P GO station is selected dynamically
|
||||
* by all participating peers of a WIFI Direct network,
|
||||
* the driver has be able to change the main interface
|
||||
* operating mode on the fly.
|
||||
*/
|
||||
if (main_vif->p2p && vif->p2p &&
|
||||
vif->type == NL80211_IFTYPE_AP) {
|
||||
old_main = main_vif;
|
||||
break;
|
||||
}
|
||||
|
||||
err = -EBUSY;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user