Commit 680ebb4e authored by Erik Stromdahl's avatar Erik Stromdahl Committed by Kalle Valo

ath10k: htc: rx trailer lookahead support

The RX trailer parsing is now capable of parsing lookahead reports.
A lookahead contains the first 4 bytes of the next HTC message
(that will be read in the next SDIO read operation).
Lookaheads are used by the SDIO/mbox HIF layer to determine if
the next message is part of a bundle, which endpoint it belongs
to and how long it is.
Signed-off-by: default avatarErik Stromdahl <erik.stromdahl@gmail.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 3e0dd820
......@@ -231,11 +231,78 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
spin_unlock_bh(&htc->tx_lock);
}
static int
ath10k_htc_process_lookahead(struct ath10k_htc *htc,
const struct ath10k_htc_lookahead_report *report,
int len,
enum ath10k_htc_ep_id eid,
void *next_lookaheads,
int *next_lookaheads_len)
{
struct ath10k *ar = htc->ar;
/* Invalid lookahead flags are actually transmitted by
* the target in the HTC control message.
* Since this will happen at every boot we silently ignore
* the lookahead in this case
*/
if (report->pre_valid != ((~report->post_valid) & 0xFF))
return 0;
if (next_lookaheads && next_lookaheads_len) {
ath10k_dbg(ar, ATH10K_DBG_HTC,
"htc rx lookahead found pre_valid 0x%x post_valid 0x%x\n",
report->pre_valid, report->post_valid);
/* look ahead bytes are valid, copy them over */
memcpy((u8 *)next_lookaheads, report->lookahead, 4);
*next_lookaheads_len = 1;
}
return 0;
}
static int
ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc,
const struct ath10k_htc_lookahead_bundle *report,
int len,
enum ath10k_htc_ep_id eid,
void *next_lookaheads,
int *next_lookaheads_len)
{
struct ath10k *ar = htc->ar;
int bundle_cnt = len / sizeof(*report);
if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE)) {
ath10k_warn(ar, "Invalid lookahead bundle count: %d\n",
bundle_cnt);
return -EINVAL;
}
if (next_lookaheads && next_lookaheads_len) {
int i;
for (i = 0; i < bundle_cnt; i++) {
memcpy(((u8 *)next_lookaheads) + 4 * i,
report->lookahead, 4);
report++;
}
*next_lookaheads_len = bundle_cnt;
}
return 0;
}
int ath10k_htc_process_trailer(struct ath10k_htc *htc,
u8 *buffer,
int length,
enum ath10k_htc_ep_id src_eid)
enum ath10k_htc_ep_id src_eid,
void *next_lookaheads,
int *next_lookaheads_len)
{
struct ath10k_htc_lookahead_bundle *bundle;
struct ath10k *ar = htc->ar;
int status = 0;
struct ath10k_htc_record *record;
......@@ -275,6 +342,29 @@ int ath10k_htc_process_trailer(struct ath10k_htc *htc,
record->hdr.len,
src_eid);
break;
case ATH10K_HTC_RECORD_LOOKAHEAD:
len = sizeof(struct ath10k_htc_lookahead_report);
if (record->hdr.len < len) {
ath10k_warn(ar, "Lookahead report too long\n");
status = -EINVAL;
break;
}
status = ath10k_htc_process_lookahead(htc,
record->lookahead_report,
record->hdr.len,
src_eid,
next_lookaheads,
next_lookaheads_len);
break;
case ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE:
bundle = record->lookahead_bundle;
status = ath10k_htc_process_lookahead_bundle(htc,
bundle,
record->hdr.len,
src_eid,
next_lookaheads,
next_lookaheads_len);
break;
default:
ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
record->hdr.id, record->hdr.len);
......@@ -362,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
trailer += payload_len;
trailer -= trailer_len;
status = ath10k_htc_process_trailer(htc, trailer,
trailer_len, hdr->eid);
trailer_len, hdr->eid,
NULL, NULL);
if (status)
goto out;
......
......@@ -50,6 +50,8 @@ struct ath10k;
* 4-byte aligned.
*/
#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
enum ath10k_htc_tx_flags {
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02
......@@ -175,7 +177,9 @@ struct ath10k_htc_msg {
enum ath10k_ath10k_htc_record_id {
ATH10K_HTC_RECORD_NULL = 0,
ATH10K_HTC_RECORD_CREDITS = 1
ATH10K_HTC_RECORD_CREDITS = 1,
ATH10K_HTC_RECORD_LOOKAHEAD = 2,
ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE = 3,
};
struct ath10k_ath10k_htc_record_hdr {
......@@ -192,10 +196,28 @@ struct ath10k_htc_credit_report {
u8 pad1;
} __packed;
struct ath10k_htc_lookahead_report {
u8 pre_valid;
u8 pad0;
u8 pad1;
u8 pad2;
u8 lookahead[4];
u8 post_valid;
u8 pad3;
u8 pad4;
u8 pad5;
} __packed;
struct ath10k_htc_lookahead_bundle {
u8 lookahead[4];
} __packed;
struct ath10k_htc_record {
struct ath10k_ath10k_htc_record_hdr hdr;
union {
struct ath10k_htc_credit_report credit_report[0];
struct ath10k_htc_lookahead_report lookahead_report[0];
struct ath10k_htc_lookahead_bundle lookahead_bundle[0];
u8 pauload[0];
};
} __packed __aligned(4);
......@@ -356,6 +378,8 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
int ath10k_htc_process_trailer(struct ath10k_htc *htc,
u8 *buffer,
int length,
enum ath10k_htc_ep_id src_eid);
enum ath10k_htc_ep_id src_eid,
void *next_lookaheads,
int *next_lookaheads_len);
#endif
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