Commit 839ae637 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: add new htt message generation/parsing logic

This merely adds some parsing, generation and
sanity checks with placeholders for real
code/functionality to be added later.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 6942726f
......@@ -1752,6 +1752,11 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu);
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
__le32 token,
__le16 fetch_seq_num,
struct htt_tx_fetch_record *records,
size_t num_records);
void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
bool is_mgmt);
......
......@@ -1982,6 +1982,198 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
tasklet_schedule(&htt->rx_replenish_task);
}
static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
const __le32 *resp_ids,
int num_resp_ids)
{
int i;
u32 resp_id;
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch confirm num_resp_ids %d\n",
num_resp_ids);
for (i = 0; i < num_resp_ids; i++) {
resp_id = le32_to_cpu(resp_ids[i]);
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch confirm resp_id %u\n",
resp_id);
/* TODO: free resp_id */
}
}
static void ath10k_htt_rx_tx_fetch_ind(struct ath10k *ar, struct sk_buff *skb)
{
struct htt_resp *resp = (struct htt_resp *)skb->data;
struct htt_tx_fetch_record *record;
size_t len;
size_t max_num_bytes;
size_t max_num_msdus;
const __le32 *resp_ids;
u16 num_records;
u16 num_resp_ids;
u16 peer_id;
u8 tid;
int i;
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch ind\n");
len = sizeof(resp->hdr) + sizeof(resp->tx_fetch_ind);
if (unlikely(skb->len < len)) {
ath10k_warn(ar, "received corrupted tx_fetch_ind event: buffer too short\n");
return;
}
num_records = le16_to_cpu(resp->tx_fetch_ind.num_records);
num_resp_ids = le16_to_cpu(resp->tx_fetch_ind.num_resp_ids);
len += sizeof(resp->tx_fetch_ind.records[0]) * num_records;
len += sizeof(resp->tx_fetch_ind.resp_ids[0]) * num_resp_ids;
if (unlikely(skb->len < len)) {
ath10k_warn(ar, "received corrupted tx_fetch_ind event: too many records/resp_ids\n");
return;
}
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch ind num records %hu num resps %hu seq %hu\n",
num_records, num_resp_ids,
le16_to_cpu(resp->tx_fetch_ind.fetch_seq_num));
/* TODO: runtime sanity checks */
for (i = 0; i < num_records; i++) {
record = &resp->tx_fetch_ind.records[i];
peer_id = MS(le16_to_cpu(record->info),
HTT_TX_FETCH_RECORD_INFO_PEER_ID);
tid = MS(le16_to_cpu(record->info),
HTT_TX_FETCH_RECORD_INFO_TID);
max_num_msdus = le16_to_cpu(record->num_msdus);
max_num_bytes = le32_to_cpu(record->num_bytes);
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch record %i peer_id %hu tid %hhu msdus %zu bytes %zu\n",
i, peer_id, tid, max_num_msdus, max_num_bytes);
if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) ||
unlikely(tid >= ar->htt.tx_q_state.num_tids)) {
ath10k_warn(ar, "received out of range peer_id %hu tid %hhu\n",
peer_id, tid);
continue;
}
/* TODO: dequeue and submit tx to device */
}
resp_ids = ath10k_htt_get_tx_fetch_ind_resp_ids(&resp->tx_fetch_ind);
ath10k_htt_rx_tx_fetch_resp_id_confirm(ar, resp_ids, num_resp_ids);
/* TODO: generate and send fetch response to device */
}
static void ath10k_htt_rx_tx_fetch_confirm(struct ath10k *ar,
struct sk_buff *skb)
{
const struct htt_resp *resp = (void *)skb->data;
size_t len;
int num_resp_ids;
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx fetch confirm\n");
len = sizeof(resp->hdr) + sizeof(resp->tx_fetch_confirm);
if (unlikely(skb->len < len)) {
ath10k_warn(ar, "received corrupted tx_fetch_confirm event: buffer too short\n");
return;
}
num_resp_ids = le16_to_cpu(resp->tx_fetch_confirm.num_resp_ids);
len += sizeof(resp->tx_fetch_confirm.resp_ids[0]) * num_resp_ids;
if (unlikely(skb->len < len)) {
ath10k_warn(ar, "received corrupted tx_fetch_confirm event: resp_ids buffer overflow\n");
return;
}
ath10k_htt_rx_tx_fetch_resp_id_confirm(ar,
resp->tx_fetch_confirm.resp_ids,
num_resp_ids);
}
static void ath10k_htt_rx_tx_mode_switch_ind(struct ath10k *ar,
struct sk_buff *skb)
{
const struct htt_resp *resp = (void *)skb->data;
const struct htt_tx_mode_switch_record *record;
size_t len;
size_t num_records;
enum htt_tx_mode_switch_mode mode;
bool enable;
u16 info0;
u16 info1;
u16 threshold;
u16 peer_id;
u8 tid;
int i;
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx tx mode switch ind\n");
len = sizeof(resp->hdr) + sizeof(resp->tx_mode_switch_ind);
if (unlikely(skb->len < len)) {
ath10k_warn(ar, "received corrupted tx_mode_switch_ind event: buffer too short\n");
return;
}
info0 = le16_to_cpu(resp->tx_mode_switch_ind.info0);
info1 = le16_to_cpu(resp->tx_mode_switch_ind.info1);
enable = !!(info0 & HTT_TX_MODE_SWITCH_IND_INFO0_ENABLE);
num_records = MS(info0, HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD);
mode = MS(info1, HTT_TX_MODE_SWITCH_IND_INFO1_MODE);
threshold = MS(info1, HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx tx mode switch ind info0 0x%04hx info1 0x%04hx enable %d num records %zd mode %d threshold %hu\n",
info0, info1, enable, num_records, mode, threshold);
len += sizeof(resp->tx_mode_switch_ind.records[0]) * num_records;
if (unlikely(skb->len < len)) {
ath10k_warn(ar, "received corrupted tx_mode_switch_mode_ind event: too many records\n");
return;
}
switch (mode) {
case HTT_TX_MODE_SWITCH_PUSH:
case HTT_TX_MODE_SWITCH_PUSH_PULL:
break;
default:
ath10k_warn(ar, "received invalid tx_mode_switch_mode_ind mode %d, ignoring\n",
mode);
return;
}
if (!enable)
return;
/* TODO: apply configuration */
for (i = 0; i < num_records; i++) {
record = &resp->tx_mode_switch_ind.records[i];
info0 = le16_to_cpu(record->info0);
peer_id = MS(info0, HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID);
tid = MS(info0, HTT_TX_MODE_SWITCH_RECORD_INFO0_TID);
if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) ||
unlikely(tid >= ar->htt.tx_q_state.num_tids)) {
ath10k_warn(ar, "received out of range peer_id %hu tid %hhu\n",
peer_id, tid);
continue;
}
/* TODO: apply configuration */
}
/* TODO: apply configuration */
}
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
......@@ -2120,9 +2312,13 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
case HTT_T2H_MSG_TYPE_AGGR_CONF:
break;
case HTT_T2H_MSG_TYPE_TX_FETCH_IND:
ath10k_htt_rx_tx_fetch_ind(ar, skb);
break;
case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
ath10k_htt_rx_tx_fetch_confirm(ar, skb);
break;
case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
/* TODO: Implement pull-push logic */
ath10k_htt_rx_tx_mode_switch_ind(ar, skb);
break;
case HTT_T2H_MSG_TYPE_EN_STATS:
default:
......
......@@ -526,6 +526,59 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
return 0;
}
int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
__le32 token,
__le16 fetch_seq_num,
struct htt_tx_fetch_record *records,
size_t num_records)
{
struct sk_buff *skb;
struct htt_cmd *cmd;
u16 resp_id;
int len = 0;
int ret;
len += sizeof(cmd->hdr);
len += sizeof(cmd->tx_fetch_resp);
len += sizeof(cmd->tx_fetch_resp.records[0]) * num_records;
skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
resp_id = 0; /* TODO: allocate resp_id */
ret = 0;
if (ret)
goto err_free_skb;
skb_put(skb, len);
cmd = (struct htt_cmd *)skb->data;
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FETCH_RESP;
cmd->tx_fetch_resp.resp_id = cpu_to_le16(resp_id);
cmd->tx_fetch_resp.fetch_seq_num = fetch_seq_num;
cmd->tx_fetch_resp.num_records = cpu_to_le16(num_records);
cmd->tx_fetch_resp.token = token;
memcpy(cmd->tx_fetch_resp.records, records,
sizeof(records[0]) * num_records);
ret = ath10k_htc_send(&ar->htc, ar->htt.eid, skb);
if (ret) {
ath10k_warn(ar, "failed to submit htc command: %d\n", ret);
goto err_free_resp_id;
}
return 0;
err_free_resp_id:
(void)resp_id; /* TODO: free resp_id */
err_free_skb:
dev_kfree_skb_any(skb);
return ret;
}
static u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment