Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+93 −2
Original line number Diff line number Diff line
@@ -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;

+27 −3
Original line number Diff line number Diff line
@@ -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