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, ...@@ -231,11 +231,78 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
spin_unlock_bh(&htc->tx_lock); 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, int ath10k_htc_process_trailer(struct ath10k_htc *htc,
u8 *buffer, u8 *buffer,
int length, 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; struct ath10k *ar = htc->ar;
int status = 0; int status = 0;
struct ath10k_htc_record *record; struct ath10k_htc_record *record;
...@@ -275,6 +342,29 @@ int ath10k_htc_process_trailer(struct ath10k_htc *htc, ...@@ -275,6 +342,29 @@ int ath10k_htc_process_trailer(struct ath10k_htc *htc,
record->hdr.len, record->hdr.len,
src_eid); src_eid);
break; 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: default:
ath10k_warn(ar, "Unhandled record: id:%d length:%d\n", ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
record->hdr.id, record->hdr.len); record->hdr.id, record->hdr.len);
...@@ -362,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) ...@@ -362,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
trailer += payload_len; trailer += payload_len;
trailer -= trailer_len; trailer -= trailer_len;
status = ath10k_htc_process_trailer(htc, trailer, status = ath10k_htc_process_trailer(htc, trailer,
trailer_len, hdr->eid); trailer_len, hdr->eid,
NULL, NULL);
if (status) if (status)
goto out; goto out;
......
...@@ -50,6 +50,8 @@ struct ath10k; ...@@ -50,6 +50,8 @@ struct ath10k;
* 4-byte aligned. * 4-byte aligned.
*/ */
#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
enum ath10k_htc_tx_flags { enum ath10k_htc_tx_flags {
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01, ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02 ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02
...@@ -174,8 +176,10 @@ struct ath10k_htc_msg { ...@@ -174,8 +176,10 @@ struct ath10k_htc_msg {
} __packed __aligned(4); } __packed __aligned(4);
enum ath10k_ath10k_htc_record_id { enum ath10k_ath10k_htc_record_id {
ATH10K_HTC_RECORD_NULL = 0, 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 { struct ath10k_ath10k_htc_record_hdr {
...@@ -192,10 +196,28 @@ struct ath10k_htc_credit_report { ...@@ -192,10 +196,28 @@ struct ath10k_htc_credit_report {
u8 pad1; u8 pad1;
} __packed; } __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_htc_record {
struct ath10k_ath10k_htc_record_hdr hdr; struct ath10k_ath10k_htc_record_hdr hdr;
union { union {
struct ath10k_htc_credit_report credit_report[0]; 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]; u8 pauload[0];
}; };
} __packed __aligned(4); } __packed __aligned(4);
...@@ -356,6 +378,8 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, ...@@ -356,6 +378,8 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
int ath10k_htc_process_trailer(struct ath10k_htc *htc, int ath10k_htc_process_trailer(struct ath10k_htc *htc,
u8 *buffer, u8 *buffer,
int length, int length,
enum ath10k_htc_ep_id src_eid); enum ath10k_htc_ep_id src_eid,
void *next_lookaheads,
int *next_lookaheads_len);
#endif #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