1*5113495bSYour Name /*
2*5113495bSYour Name * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
3*5113495bSYour Name * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name *
5*5113495bSYour Name * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name * above copyright notice and this permission notice appear in all
8*5113495bSYour Name * copies.
9*5113495bSYour Name *
10*5113495bSYour Name * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name */
19*5113495bSYour Name
20*5113495bSYour Name
21*5113495bSYour Name #define ATH_MODULE_NAME hif
22*5113495bSYour Name #include <qdf_types.h>
23*5113495bSYour Name #include <qdf_status.h>
24*5113495bSYour Name #include <qdf_timer.h>
25*5113495bSYour Name #include <qdf_time.h>
26*5113495bSYour Name #include <qdf_lock.h>
27*5113495bSYour Name #include <qdf_mem.h>
28*5113495bSYour Name #include <qdf_util.h>
29*5113495bSYour Name #include <qdf_defer.h>
30*5113495bSYour Name #include <qdf_atomic.h>
31*5113495bSYour Name #include <qdf_nbuf.h>
32*5113495bSYour Name #include <athdefs.h>
33*5113495bSYour Name #include <qdf_net_types.h>
34*5113495bSYour Name #include <a_types.h>
35*5113495bSYour Name #include <athdefs.h>
36*5113495bSYour Name #include <a_osapi.h>
37*5113495bSYour Name #include <hif.h>
38*5113495bSYour Name #include <htc_services.h>
39*5113495bSYour Name #include <a_debug.h>
40*5113495bSYour Name #include <htc_internal.h>
41*5113495bSYour Name #include "hif_sdio_internal.h"
42*5113495bSYour Name #include "transfer.h"
43*5113495bSYour Name
44*5113495bSYour Name /**
45*5113495bSYour Name * hif_dev_rw_completion_handler() - Completion routine
46*5113495bSYour Name * for ALL HIF layer async I/O
47*5113495bSYour Name * @ctx: hif send context
48*5113495bSYour Name * @status: completion routine sync/async context
49*5113495bSYour Name *
50*5113495bSYour Name * Return: 0 for success and non-zero for failure
51*5113495bSYour Name */
52*5113495bSYour Name
hif_dev_rw_completion_handler(void * ctx,QDF_STATUS status)53*5113495bSYour Name QDF_STATUS hif_dev_rw_completion_handler(void *ctx, QDF_STATUS status)
54*5113495bSYour Name {
55*5113495bSYour Name QDF_STATUS (*txCompHandler)(void *, qdf_nbuf_t, uint32_t, uint32_t);
56*5113495bSYour Name struct hif_sendContext *sctx = (struct hif_sendContext *)ctx;
57*5113495bSYour Name struct hif_sdio_device *pdev = sctx->pDev;
58*5113495bSYour Name unsigned int xfer_id = sctx->transferID;
59*5113495bSYour Name uint32_t toeplitz_hash_result = 0;
60*5113495bSYour Name qdf_nbuf_t buf = sctx->netbuf;
61*5113495bSYour Name
62*5113495bSYour Name if (sctx->bNewAlloc)
63*5113495bSYour Name qdf_mem_free(ctx);
64*5113495bSYour Name else
65*5113495bSYour Name qdf_nbuf_pull_head(buf, sctx->head_data_len);
66*5113495bSYour Name
67*5113495bSYour Name txCompHandler = pdev->hif_callbacks.txCompletionHandler;
68*5113495bSYour Name if (txCompHandler) {
69*5113495bSYour Name txCompHandler(pdev->hif_callbacks.Context, buf,
70*5113495bSYour Name xfer_id, toeplitz_hash_result);
71*5113495bSYour Name }
72*5113495bSYour Name
73*5113495bSYour Name return QDF_STATUS_SUCCESS;
74*5113495bSYour Name }
75*5113495bSYour Name
76*5113495bSYour Name /**
77*5113495bSYour Name * hif_dev_send_buffer() - send buffer to sdio device
78*5113495bSYour Name * @pdev: HIf device object
79*5113495bSYour Name * @xfer_id: transfer id
80*5113495bSYour Name * @pipe: ul/dl pipe
81*5113495bSYour Name * @nbytes: no of bytes to transfer
82*5113495bSYour Name * @buf: pointer to buffer
83*5113495bSYour Name *
84*5113495bSYour Name * Return: 0 for success and non-zero for failure
85*5113495bSYour Name */
hif_dev_send_buffer(struct hif_sdio_device * pdev,uint32_t xfer_id,uint8_t pipe,uint32_t nbytes,qdf_nbuf_t buf)86*5113495bSYour Name QDF_STATUS hif_dev_send_buffer(struct hif_sdio_device *pdev, uint32_t xfer_id,
87*5113495bSYour Name uint8_t pipe, uint32_t nbytes, qdf_nbuf_t buf)
88*5113495bSYour Name {
89*5113495bSYour Name QDF_STATUS status;
90*5113495bSYour Name unsigned char *pData;
91*5113495bSYour Name struct hif_sendContext *sctx;
92*5113495bSYour Name uint32_t request = hif_get_send_buffer_flags(pdev);
93*5113495bSYour Name uint32_t padded_length;
94*5113495bSYour Name unsigned long addr = 0;
95*5113495bSYour Name int frag_count = 0, i, count, head_len;
96*5113495bSYour Name
97*5113495bSYour Name if (hif_get_send_address(pdev, pipe, &addr)) {
98*5113495bSYour Name hif_err("Invalid address map for pipe 0x%x", pipe);
99*5113495bSYour Name
100*5113495bSYour Name return QDF_STATUS_E_INVAL;
101*5113495bSYour Name }
102*5113495bSYour Name
103*5113495bSYour Name padded_length = DEV_CALC_SEND_PADDED_LEN(pdev, nbytes);
104*5113495bSYour Name A_ASSERT(padded_length - nbytes < HIF_DUMMY_SPACE_MASK + 1);
105*5113495bSYour Name
106*5113495bSYour Name request |= ((padded_length - nbytes) << 16);
107*5113495bSYour Name
108*5113495bSYour Name frag_count = qdf_nbuf_get_num_frags(buf);
109*5113495bSYour Name
110*5113495bSYour Name if (frag_count > 1) {
111*5113495bSYour Name /* Header data length should be total sending length.
112*5113495bSYour Name * Subtract internal data length of netbuf
113*5113495bSYour Name */
114*5113495bSYour Name head_len = sizeof(struct hif_sendContext) +
115*5113495bSYour Name (nbytes - qdf_nbuf_get_frag_len(buf, frag_count - 1));
116*5113495bSYour Name } else {
117*5113495bSYour Name /*
118*5113495bSYour Name * | hif_sendContext | netbuf->data
119*5113495bSYour Name */
120*5113495bSYour Name head_len = sizeof(struct hif_sendContext);
121*5113495bSYour Name }
122*5113495bSYour Name
123*5113495bSYour Name /* Check whether head room is enough to save extra head data */
124*5113495bSYour Name if ((head_len <= qdf_nbuf_headroom(buf)) &&
125*5113495bSYour Name (qdf_nbuf_tailroom(buf) >= (padded_length - nbytes))) {
126*5113495bSYour Name sctx = (struct hif_sendContext *)qdf_nbuf_push_head(buf,
127*5113495bSYour Name head_len);
128*5113495bSYour Name sctx->bNewAlloc = false;
129*5113495bSYour Name } else {
130*5113495bSYour Name sctx = (struct hif_sendContext *)qdf_mem_malloc(sizeof(*sctx) +
131*5113495bSYour Name padded_length);
132*5113495bSYour Name if (sctx)
133*5113495bSYour Name sctx->bNewAlloc = true;
134*5113495bSYour Name else
135*5113495bSYour Name return QDF_STATUS_E_NOMEM;
136*5113495bSYour Name }
137*5113495bSYour Name
138*5113495bSYour Name sctx->netbuf = buf;
139*5113495bSYour Name sctx->pDev = pdev;
140*5113495bSYour Name sctx->transferID = xfer_id;
141*5113495bSYour Name sctx->head_data_len = head_len;
142*5113495bSYour Name /*
143*5113495bSYour Name * Copy data to head part of netbuf or head of allocated buffer.
144*5113495bSYour Name * if buffer is new allocated, the last buffer should be copied also.
145*5113495bSYour Name * It assume last fragment is internal buffer of netbuf
146*5113495bSYour Name * sometime total length of fragments larger than nbytes
147*5113495bSYour Name */
148*5113495bSYour Name pData = (unsigned char *)sctx + sizeof(struct hif_sendContext);
149*5113495bSYour Name for (i = 0, count = sctx->bNewAlloc ? frag_count : frag_count - 1;
150*5113495bSYour Name i < count;
151*5113495bSYour Name i++) {
152*5113495bSYour Name int frag_len = qdf_nbuf_get_frag_len(buf, i);
153*5113495bSYour Name unsigned char *frag_addr = qdf_nbuf_get_frag_vaddr(buf, i);
154*5113495bSYour Name
155*5113495bSYour Name if (frag_len > nbytes)
156*5113495bSYour Name frag_len = nbytes;
157*5113495bSYour Name memcpy(pData, frag_addr, frag_len);
158*5113495bSYour Name pData += frag_len;
159*5113495bSYour Name nbytes -= frag_len;
160*5113495bSYour Name if (nbytes <= 0)
161*5113495bSYour Name break;
162*5113495bSYour Name }
163*5113495bSYour Name
164*5113495bSYour Name /* Reset pData pointer and sctx out */
165*5113495bSYour Name pData = (unsigned char *)sctx + sizeof(struct hif_sendContext);
166*5113495bSYour Name
167*5113495bSYour Name status = hif_read_write(pdev->HIFDevice, addr, (char *)pData,
168*5113495bSYour Name padded_length, request, (void *)sctx);
169*5113495bSYour Name
170*5113495bSYour Name if (status == QDF_STATUS_E_PENDING) {
171*5113495bSYour Name /*
172*5113495bSYour Name * it will return QDF_STATUS_E_PENDING in native HIF
173*5113495bSYour Name * implementation, which should be treated as successful
174*5113495bSYour Name * result here.
175*5113495bSYour Name */
176*5113495bSYour Name status = QDF_STATUS_SUCCESS;
177*5113495bSYour Name }
178*5113495bSYour Name
179*5113495bSYour Name /* release buffer or move back data pointer when failed */
180*5113495bSYour Name if (status != QDF_STATUS_SUCCESS) {
181*5113495bSYour Name if (sctx->bNewAlloc)
182*5113495bSYour Name qdf_mem_free(sctx);
183*5113495bSYour Name else
184*5113495bSYour Name qdf_nbuf_pull_head(buf, head_len);
185*5113495bSYour Name }
186*5113495bSYour Name
187*5113495bSYour Name return status;
188*5113495bSYour Name }
189*5113495bSYour Name
190*5113495bSYour Name /**
191*5113495bSYour Name * hif_dev_alloc_and_prepare_rx_packets() - Allocate packets for recv frames.
192*5113495bSYour Name * @pdev : HIF device object
193*5113495bSYour Name * @look_aheads : Look ahead information on the frames
194*5113495bSYour Name * @messages : Number of messages
195*5113495bSYour Name * @queue : Queue to put the allocated frames
196*5113495bSYour Name *
197*5113495bSYour Name * Return : QDF_STATUS_SUCCESS on success else error value
198*5113495bSYour Name */
hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device * pdev,uint32_t look_aheads[],int messages,HTC_PACKET_QUEUE * queue)199*5113495bSYour Name QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev,
200*5113495bSYour Name uint32_t look_aheads[],
201*5113495bSYour Name int messages,
202*5113495bSYour Name HTC_PACKET_QUEUE *queue)
203*5113495bSYour Name {
204*5113495bSYour Name int i, j;
205*5113495bSYour Name bool no_recycle;
206*5113495bSYour Name int num_messages;
207*5113495bSYour Name HTC_PACKET *packet;
208*5113495bSYour Name HTC_FRAME_HDR *hdr;
209*5113495bSYour Name uint32_t full_length;
210*5113495bSYour Name QDF_STATUS status = QDF_STATUS_SUCCESS;
211*5113495bSYour Name
212*5113495bSYour Name /* lock RX while we assemble the packet buffers */
213*5113495bSYour Name LOCK_HIF_DEV_RX(pdev);
214*5113495bSYour Name
215*5113495bSYour Name for (i = 0; i < messages; i++) {
216*5113495bSYour Name hdr = (HTC_FRAME_HDR *)&look_aheads[i];
217*5113495bSYour Name if (hdr->EndpointID >= ENDPOINT_MAX) {
218*5113495bSYour Name hif_err("Invalid Endpoint:%d", hdr->EndpointID);
219*5113495bSYour Name status = QDF_STATUS_E_INVAL;
220*5113495bSYour Name break;
221*5113495bSYour Name }
222*5113495bSYour Name
223*5113495bSYour Name if (hdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
224*5113495bSYour Name hif_err("Payload length %d exceeds max HTC : %u",
225*5113495bSYour Name hdr->PayloadLen,
226*5113495bSYour Name (uint32_t)HTC_MAX_PAYLOAD_LENGTH);
227*5113495bSYour Name status = QDF_STATUS_E_INVAL;
228*5113495bSYour Name break;
229*5113495bSYour Name }
230*5113495bSYour Name
231*5113495bSYour Name if ((hdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
232*5113495bSYour Name /* HTC header only indicates 1 message to fetch */
233*5113495bSYour Name num_messages = 1;
234*5113495bSYour Name } else {
235*5113495bSYour Name /* HTC header indicates that every packet to follow
236*5113495bSYour Name * has the same padded length so that it can
237*5113495bSYour Name * be optimally fetched as a full bundle
238*5113495bSYour Name */
239*5113495bSYour Name num_messages = GET_RECV_BUNDLE_COUNT(hdr->Flags);
240*5113495bSYour Name /* the count doesn't include the starter frame, just
241*5113495bSYour Name * a count of frames to follow
242*5113495bSYour Name */
243*5113495bSYour Name num_messages++;
244*5113495bSYour Name
245*5113495bSYour Name hif_info("HTC header : %u messages in bundle",
246*5113495bSYour Name num_messages);
247*5113495bSYour Name }
248*5113495bSYour Name
249*5113495bSYour Name full_length = DEV_CALC_RECV_PADDED_LEN(pdev,
250*5113495bSYour Name hdr->PayloadLen +
251*5113495bSYour Name sizeof(HTC_FRAME_HDR));
252*5113495bSYour Name
253*5113495bSYour Name /* get packet buffers for each message, if there was a
254*5113495bSYour Name * bundle detected in the header,
255*5113495bSYour Name * use pHdr as a template to fetch all packets in the bundle
256*5113495bSYour Name */
257*5113495bSYour Name for (j = 0; j < num_messages; j++) {
258*5113495bSYour Name /* reset flag, any packets allocated using the
259*5113495bSYour Name * RecvAlloc() API cannot be recycled on cleanup,
260*5113495bSYour Name * they must be explicitly returned
261*5113495bSYour Name */
262*5113495bSYour Name no_recycle = false;
263*5113495bSYour Name packet = hif_dev_alloc_rx_buffer(pdev);
264*5113495bSYour Name
265*5113495bSYour Name if (!packet) {
266*5113495bSYour Name /* No error, simply need to mark that
267*5113495bSYour Name * we are waiting for buffers.
268*5113495bSYour Name */
269*5113495bSYour Name pdev->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS;
270*5113495bSYour Name /* pDev->EpWaitingForBuffers = pEndpoint->Id; */
271*5113495bSYour Name status = QDF_STATUS_E_RESOURCES;
272*5113495bSYour Name break;
273*5113495bSYour Name }
274*5113495bSYour Name /* clear flags */
275*5113495bSYour Name packet->PktInfo.AsRx.HTCRxFlags = 0;
276*5113495bSYour Name packet->PktInfo.AsRx.IndicationFlags = 0;
277*5113495bSYour Name packet->Status = QDF_STATUS_SUCCESS;
278*5113495bSYour Name
279*5113495bSYour Name if (no_recycle) {
280*5113495bSYour Name /* flag that these packets cannot be recycled,
281*5113495bSYour Name * they have to be returned to the user
282*5113495bSYour Name */
283*5113495bSYour Name packet->PktInfo.AsRx.HTCRxFlags |=
284*5113495bSYour Name HTC_RX_PKT_NO_RECYCLE;
285*5113495bSYour Name }
286*5113495bSYour Name /* add packet to queue (also incase we need to
287*5113495bSYour Name * cleanup down below)
288*5113495bSYour Name */
289*5113495bSYour Name HTC_PACKET_ENQUEUE(queue, packet);
290*5113495bSYour Name
291*5113495bSYour Name /* if (HTC_STOPPING(target)) {
292*5113495bSYour Name * status = QDF_STATUS_E_CANCELED;
293*5113495bSYour Name * break;
294*5113495bSYour Name * }
295*5113495bSYour Name */
296*5113495bSYour Name
297*5113495bSYour Name /* make sure message can fit in the endpoint buffer */
298*5113495bSYour Name if (full_length > packet->BufferLength) {
299*5113495bSYour Name hif_err("Payload Length Error");
300*5113495bSYour Name hif_err("header reports payload: %u(%u)",
301*5113495bSYour Name hdr->PayloadLen,
302*5113495bSYour Name full_length);
303*5113495bSYour Name hif_err("endpoint buffer size: %d",
304*5113495bSYour Name packet->BufferLength);
305*5113495bSYour Name status = QDF_STATUS_E_INVAL;
306*5113495bSYour Name break;
307*5113495bSYour Name }
308*5113495bSYour Name
309*5113495bSYour Name if (j > 0) {
310*5113495bSYour Name /* for messages fetched in a bundle the expected
311*5113495bSYour Name * lookahead is unknown as we are only using the
312*5113495bSYour Name * lookahead of the first packet as a template
313*5113495bSYour Name * of what to expect for lengths
314*5113495bSYour Name */
315*5113495bSYour Name packet->PktInfo.AsRx.HTCRxFlags |=
316*5113495bSYour Name HTC_RX_PKT_REFRESH_HDR;
317*5113495bSYour Name /* set it to something invalid */
318*5113495bSYour Name packet->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF;
319*5113495bSYour Name } else {
320*5113495bSYour Name packet->PktInfo.AsRx.ExpectedHdr =
321*5113495bSYour Name look_aheads[i];
322*5113495bSYour Name }
323*5113495bSYour Name /* set the amount of data to fetch */
324*5113495bSYour Name packet->ActualLength =
325*5113495bSYour Name hdr->PayloadLen + HTC_HDR_LENGTH;
326*5113495bSYour Name if ((j == (num_messages - 1)) &&
327*5113495bSYour Name ((hdr->Flags) & HTC_FLAGS_RECV_1MORE_BLOCK))
328*5113495bSYour Name packet->PktInfo.AsRx.HTCRxFlags |=
329*5113495bSYour Name HTC_RX_PKT_LAST_BUNDLED_PKT_HAS_ADDTIONAL_BLOCK;
330*5113495bSYour Name packet->Endpoint = hdr->EndpointID;
331*5113495bSYour Name packet->Completion = NULL;
332*5113495bSYour Name }
333*5113495bSYour Name
334*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
335*5113495bSYour Name break;
336*5113495bSYour Name }
337*5113495bSYour Name
338*5113495bSYour Name UNLOCK_HIF_DEV_RX(pdev);
339*5113495bSYour Name
340*5113495bSYour Name /* for NO RESOURCE error, no need to flush data queue */
341*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status) &&
342*5113495bSYour Name (status != QDF_STATUS_E_RESOURCES)) {
343*5113495bSYour Name while (!HTC_QUEUE_EMPTY(queue)) {
344*5113495bSYour Name qdf_nbuf_t netbuf;
345*5113495bSYour Name
346*5113495bSYour Name packet = htc_packet_dequeue(queue);
347*5113495bSYour Name if (!packet)
348*5113495bSYour Name break;
349*5113495bSYour Name netbuf = (qdf_nbuf_t)packet->pNetBufContext;
350*5113495bSYour Name if (netbuf)
351*5113495bSYour Name qdf_nbuf_free(netbuf);
352*5113495bSYour Name }
353*5113495bSYour Name }
354*5113495bSYour Name if (status == QDF_STATUS_E_RESOURCES)
355*5113495bSYour Name status = QDF_STATUS_SUCCESS;
356*5113495bSYour Name return status;
357*5113495bSYour Name }
358*5113495bSYour Name
359*5113495bSYour Name /**
360*5113495bSYour Name * hif_dev_process_trailer() - Process the receive frame trailer
361*5113495bSYour Name * @pdev : HIF device object
362*5113495bSYour Name * @buffer : The buffer containing the trailer
363*5113495bSYour Name * @length : Length of the buffer
364*5113495bSYour Name * @next_look_aheads : The lookahead that is next
365*5113495bSYour Name * @num_look_aheads : Number of lookahead information
366*5113495bSYour Name * @from_endpoint : The endpoint on which the trailer is received
367*5113495bSYour Name */
hif_dev_process_trailer(struct hif_sdio_device * pdev,uint8_t * buffer,int length,uint32_t * next_look_aheads,int * num_look_aheads,HTC_ENDPOINT_ID from_endpoint)368*5113495bSYour Name QDF_STATUS hif_dev_process_trailer(struct hif_sdio_device *pdev,
369*5113495bSYour Name uint8_t *buffer, int length,
370*5113495bSYour Name uint32_t *next_look_aheads,
371*5113495bSYour Name int *num_look_aheads,
372*5113495bSYour Name HTC_ENDPOINT_ID from_endpoint)
373*5113495bSYour Name {
374*5113495bSYour Name int orig_length;
375*5113495bSYour Name QDF_STATUS status;
376*5113495bSYour Name uint8_t *record_buf;
377*5113495bSYour Name uint8_t *orig_buffer;
378*5113495bSYour Name HTC_RECORD_HDR *record;
379*5113495bSYour Name HTC_LOOKAHEAD_REPORT *look_ahead;
380*5113495bSYour Name
381*5113495bSYour Name hif_debug("length:%d", length);
382*5113495bSYour Name
383*5113495bSYour Name orig_buffer = buffer;
384*5113495bSYour Name orig_length = length;
385*5113495bSYour Name status = QDF_STATUS_SUCCESS;
386*5113495bSYour Name
387*5113495bSYour Name while (length > 0) {
388*5113495bSYour Name if (length < sizeof(HTC_RECORD_HDR)) {
389*5113495bSYour Name status = QDF_STATUS_E_PROTO;
390*5113495bSYour Name break;
391*5113495bSYour Name }
392*5113495bSYour Name /* these are byte aligned structs */
393*5113495bSYour Name record = (HTC_RECORD_HDR *)buffer;
394*5113495bSYour Name length -= sizeof(HTC_RECORD_HDR);
395*5113495bSYour Name buffer += sizeof(HTC_RECORD_HDR);
396*5113495bSYour Name
397*5113495bSYour Name if (record->Length > length) {
398*5113495bSYour Name /* no room left in buffer for record */
399*5113495bSYour Name hif_err("Invalid record len: (%u, %u)",
400*5113495bSYour Name record->Length,
401*5113495bSYour Name record->RecordID);
402*5113495bSYour Name hif_err("Buffer has %d bytes left", length);
403*5113495bSYour Name status = QDF_STATUS_E_PROTO;
404*5113495bSYour Name break;
405*5113495bSYour Name }
406*5113495bSYour Name /* start of record follows the header */
407*5113495bSYour Name record_buf = buffer;
408*5113495bSYour Name
409*5113495bSYour Name switch (record->RecordID) {
410*5113495bSYour Name case HTC_RECORD_CREDITS:
411*5113495bSYour Name /* Process in HTC, ignore here */
412*5113495bSYour Name break;
413*5113495bSYour Name case HTC_RECORD_LOOKAHEAD:
414*5113495bSYour Name A_ASSERT(record->Length >= sizeof(*look_ahead));
415*5113495bSYour Name look_ahead = (HTC_LOOKAHEAD_REPORT *)record_buf;
416*5113495bSYour Name if ((look_ahead->PreValid ==
417*5113495bSYour Name ((~look_ahead->PostValid) & 0xFF)) &&
418*5113495bSYour Name next_look_aheads) {
419*5113495bSYour Name hif_debug("Look_ahead Report");
420*5113495bSYour Name hif_debug("Prevalid:0x%x, postvalid:0x%x",
421*5113495bSYour Name look_ahead->PreValid,
422*5113495bSYour Name look_ahead->PostValid);
423*5113495bSYour Name hif_debug("From endpoint %d : %u",
424*5113495bSYour Name from_endpoint,
425*5113495bSYour Name look_ahead->LookAhead0);
426*5113495bSYour Name /* look ahead bytes are valid, copy them over */
427*5113495bSYour Name ((uint8_t *)(&next_look_aheads[0]))[0] =
428*5113495bSYour Name look_ahead->LookAhead0;
429*5113495bSYour Name ((uint8_t *)(&next_look_aheads[0]))[1] =
430*5113495bSYour Name look_ahead->LookAhead1;
431*5113495bSYour Name ((uint8_t *)(&next_look_aheads[0]))[2] =
432*5113495bSYour Name look_ahead->LookAhead2;
433*5113495bSYour Name ((uint8_t *)(&next_look_aheads[0]))[3] =
434*5113495bSYour Name look_ahead->LookAhead3;
435*5113495bSYour Name
436*5113495bSYour Name if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
437*5113495bSYour Name debug_dump_bytes((uint8_t *)
438*5113495bSYour Name next_look_aheads, 4,
439*5113495bSYour Name "Next Look Ahead");
440*5113495bSYour Name }
441*5113495bSYour Name /* just one normal lookahead */
442*5113495bSYour Name if (num_look_aheads)
443*5113495bSYour Name *num_look_aheads = 1;
444*5113495bSYour Name }
445*5113495bSYour Name break;
446*5113495bSYour Name case HTC_RECORD_LOOKAHEAD_BUNDLE:
447*5113495bSYour Name A_ASSERT(record->Length >=
448*5113495bSYour Name sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT));
449*5113495bSYour Name if ((record->Length >=
450*5113495bSYour Name sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)) &&
451*5113495bSYour Name next_look_aheads) {
452*5113495bSYour Name HTC_BUNDLED_LOOKAHEAD_REPORT
453*5113495bSYour Name *pBundledLookAheadRpt;
454*5113495bSYour Name int i;
455*5113495bSYour Name
456*5113495bSYour Name pBundledLookAheadRpt =
457*5113495bSYour Name (HTC_BUNDLED_LOOKAHEAD_REPORT *)record_buf;
458*5113495bSYour Name
459*5113495bSYour Name if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
460*5113495bSYour Name debug_dump_bytes(record_buf,
461*5113495bSYour Name record->Length,
462*5113495bSYour Name "Bundle look_ahead");
463*5113495bSYour Name }
464*5113495bSYour Name
465*5113495bSYour Name if ((record->Length /
466*5113495bSYour Name (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)))
467*5113495bSYour Name > HTC_MAX_MSG_PER_BUNDLE_RX) {
468*5113495bSYour Name /* this should never happen, the target
469*5113495bSYour Name * restricts the number of messages per
470*5113495bSYour Name * bundle configured by the host
471*5113495bSYour Name */
472*5113495bSYour Name A_ASSERT(false);
473*5113495bSYour Name status = QDF_STATUS_E_PROTO;
474*5113495bSYour Name break;
475*5113495bSYour Name }
476*5113495bSYour Name for (i = 0;
477*5113495bSYour Name i <
478*5113495bSYour Name (int)(record->Length /
479*5113495bSYour Name (sizeof
480*5113495bSYour Name (HTC_BUNDLED_LOOKAHEAD_REPORT)));
481*5113495bSYour Name i++) {
482*5113495bSYour Name ((uint8_t *)(&next_look_aheads[i]))[0] =
483*5113495bSYour Name pBundledLookAheadRpt->LookAhead0;
484*5113495bSYour Name ((uint8_t *)(&next_look_aheads[i]))[1] =
485*5113495bSYour Name pBundledLookAheadRpt->LookAhead1;
486*5113495bSYour Name ((uint8_t *)(&next_look_aheads[i]))[2] =
487*5113495bSYour Name pBundledLookAheadRpt->LookAhead2;
488*5113495bSYour Name ((uint8_t *)(&next_look_aheads[i]))[3] =
489*5113495bSYour Name pBundledLookAheadRpt->LookAhead3;
490*5113495bSYour Name pBundledLookAheadRpt++;
491*5113495bSYour Name }
492*5113495bSYour Name if (num_look_aheads)
493*5113495bSYour Name *num_look_aheads = i;
494*5113495bSYour Name }
495*5113495bSYour Name break;
496*5113495bSYour Name default:
497*5113495bSYour Name hif_err("HIF unhandled record: id:%u length:%u",
498*5113495bSYour Name record->RecordID, record->Length);
499*5113495bSYour Name break;
500*5113495bSYour Name }
501*5113495bSYour Name
502*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
503*5113495bSYour Name break;
504*5113495bSYour Name
505*5113495bSYour Name /* advance buffer past this record for next time around */
506*5113495bSYour Name buffer += record->Length;
507*5113495bSYour Name length -= record->Length;
508*5113495bSYour Name }
509*5113495bSYour Name
510*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
511*5113495bSYour Name debug_dump_bytes(orig_buffer, orig_length,
512*5113495bSYour Name "BAD Recv Trailer");
513*5113495bSYour Name
514*5113495bSYour Name hif_debug("status = %d", status);
515*5113495bSYour Name
516*5113495bSYour Name return status;
517*5113495bSYour Name }
518*5113495bSYour Name
519*5113495bSYour Name /* process a received message (i.e. strip off header,
520*5113495bSYour Name * process any trailer data).
521*5113495bSYour Name * note : locks must be released when this function is called
522*5113495bSYour Name */
hif_dev_process_recv_header(struct hif_sdio_device * pdev,HTC_PACKET * packet,uint32_t * next_look_aheads,int * num_look_aheads)523*5113495bSYour Name QDF_STATUS hif_dev_process_recv_header(struct hif_sdio_device *pdev,
524*5113495bSYour Name HTC_PACKET *packet,
525*5113495bSYour Name uint32_t *next_look_aheads,
526*5113495bSYour Name int *num_look_aheads)
527*5113495bSYour Name {
528*5113495bSYour Name uint8_t temp;
529*5113495bSYour Name uint8_t *buf;
530*5113495bSYour Name QDF_STATUS status = QDF_STATUS_SUCCESS;
531*5113495bSYour Name uint16_t payloadLen;
532*5113495bSYour Name uint32_t look_ahead, actual_length;
533*5113495bSYour Name
534*5113495bSYour Name buf = packet->pBuffer;
535*5113495bSYour Name actual_length = packet->ActualLength;
536*5113495bSYour Name
537*5113495bSYour Name if (num_look_aheads)
538*5113495bSYour Name *num_look_aheads = 0;
539*5113495bSYour Name
540*5113495bSYour Name AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader\n"));
541*5113495bSYour Name
542*5113495bSYour Name if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV))
543*5113495bSYour Name AR_DEBUG_PRINTBUF(buf, packet->ActualLength, "HTC Recv PKT");
544*5113495bSYour Name
545*5113495bSYour Name do {
546*5113495bSYour Name /* note, we cannot assume the alignment of pBuffer,
547*5113495bSYour Name * so we use the safe macros to
548*5113495bSYour Name * retrieve 16 bit fields
549*5113495bSYour Name */
550*5113495bSYour Name payloadLen = HTC_GET_FIELD(buf, HTC_FRAME_HDR,
551*5113495bSYour Name PAYLOADLEN);
552*5113495bSYour Name
553*5113495bSYour Name ((uint8_t *)&look_ahead)[0] = buf[0];
554*5113495bSYour Name ((uint8_t *)&look_ahead)[1] = buf[1];
555*5113495bSYour Name ((uint8_t *)&look_ahead)[2] = buf[2];
556*5113495bSYour Name ((uint8_t *)&look_ahead)[3] = buf[3];
557*5113495bSYour Name
558*5113495bSYour Name if (packet->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) {
559*5113495bSYour Name /* refresh expected hdr, since this was unknown
560*5113495bSYour Name * at the time we grabbed the packets
561*5113495bSYour Name * as part of a bundle
562*5113495bSYour Name */
563*5113495bSYour Name packet->PktInfo.AsRx.ExpectedHdr = look_ahead;
564*5113495bSYour Name /* refresh actual length since we now have the
565*5113495bSYour Name * real header
566*5113495bSYour Name */
567*5113495bSYour Name packet->ActualLength = payloadLen + HTC_HDR_LENGTH;
568*5113495bSYour Name
569*5113495bSYour Name /* validate the actual header that was refreshed */
570*5113495bSYour Name if (packet->ActualLength > packet->BufferLength) {
571*5113495bSYour Name hif_err("Bundled RECV Look ahead: 0x%X",
572*5113495bSYour Name look_ahead);
573*5113495bSYour Name hif_err("Invalid HDR payload length(%d)",
574*5113495bSYour Name payloadLen);
575*5113495bSYour Name /* limit this to max buffer just to print out
576*5113495bSYour Name * some of the buffer
577*5113495bSYour Name */
578*5113495bSYour Name packet->ActualLength =
579*5113495bSYour Name min(packet->ActualLength,
580*5113495bSYour Name packet->BufferLength);
581*5113495bSYour Name status = QDF_STATUS_E_PROTO;
582*5113495bSYour Name break;
583*5113495bSYour Name }
584*5113495bSYour Name
585*5113495bSYour Name if (packet->Endpoint
586*5113495bSYour Name != HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID)) {
587*5113495bSYour Name hif_err("Refreshed HDR EP (%d)",
588*5113495bSYour Name HTC_GET_FIELD(buf, HTC_FRAME_HDR,
589*5113495bSYour Name ENDPOINTID));
590*5113495bSYour Name hif_err("Doesn't match expected EP (%d)",
591*5113495bSYour Name packet->Endpoint);
592*5113495bSYour Name status = QDF_STATUS_E_PROTO;
593*5113495bSYour Name break;
594*5113495bSYour Name }
595*5113495bSYour Name }
596*5113495bSYour Name
597*5113495bSYour Name if (look_ahead != packet->PktInfo.AsRx.ExpectedHdr) {
598*5113495bSYour Name /* somehow the lookahead that gave us the full read
599*5113495bSYour Name * length did not reflect the actual header
600*5113495bSYour Name * in the pending message
601*5113495bSYour Name */
602*5113495bSYour Name hif_err("Lookahead mismatch!");
603*5113495bSYour Name hif_err("pPkt:0x%lX flags:0x%X",
604*5113495bSYour Name (unsigned long)packet,
605*5113495bSYour Name packet->PktInfo.AsRx.HTCRxFlags);
606*5113495bSYour Name hif_err("Look_ahead 0x%08X != 0x%08X",
607*5113495bSYour Name look_ahead,
608*5113495bSYour Name packet->PktInfo.AsRx.ExpectedHdr);
609*5113495bSYour Name #ifdef ATH_DEBUG_MODULE
610*5113495bSYour Name debug_dump_bytes((uint8_t *)&packet->PktInfo.AsRx.
611*5113495bSYour Name ExpectedHdr, 4,
612*5113495bSYour Name "Expected Message look_ahead");
613*5113495bSYour Name debug_dump_bytes(buf, sizeof(HTC_FRAME_HDR),
614*5113495bSYour Name "Current Frame Header");
615*5113495bSYour Name #ifdef HTC_CAPTURE_LAST_FRAME
616*5113495bSYour Name debug_dump_bytes((uint8_t *)&target->LastFrameHdr,
617*5113495bSYour Name sizeof(HTC_FRAME_HDR),
618*5113495bSYour Name "Last Frame Header");
619*5113495bSYour Name if (target->LastTrailerLength != 0)
620*5113495bSYour Name debug_dump_bytes(target->LastTrailer,
621*5113495bSYour Name target->LastTrailerLength,
622*5113495bSYour Name "Last trailer");
623*5113495bSYour Name #endif
624*5113495bSYour Name #endif
625*5113495bSYour Name status = QDF_STATUS_E_PROTO;
626*5113495bSYour Name break;
627*5113495bSYour Name }
628*5113495bSYour Name
629*5113495bSYour Name /* get flags */
630*5113495bSYour Name temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, FLAGS);
631*5113495bSYour Name
632*5113495bSYour Name if (temp & HTC_FLAGS_RECV_TRAILER) {
633*5113495bSYour Name /* this packet has a trailer */
634*5113495bSYour Name
635*5113495bSYour Name /* extract the trailer length in control byte 0 */
636*5113495bSYour Name temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, CONTROLBYTES0);
637*5113495bSYour Name
638*5113495bSYour Name if ((temp < sizeof(HTC_RECORD_HDR)) ||
639*5113495bSYour Name (temp > payloadLen)) {
640*5113495bSYour Name hif_err("Invalid header");
641*5113495bSYour Name hif_err("Payloadlength should be :%d",
642*5113495bSYour Name payloadLen);
643*5113495bSYour Name hif_err("But control bytes is :%d)", temp);
644*5113495bSYour Name status = QDF_STATUS_E_PROTO;
645*5113495bSYour Name break;
646*5113495bSYour Name }
647*5113495bSYour Name
648*5113495bSYour Name if (packet->PktInfo.AsRx.
649*5113495bSYour Name HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
650*5113495bSYour Name /* this packet was fetched as part of an HTC
651*5113495bSYour Name * bundle as the lookahead is not valid.
652*5113495bSYour Name * Next packet may have already been fetched as
653*5113495bSYour Name * part of the bundle
654*5113495bSYour Name */
655*5113495bSYour Name next_look_aheads = NULL;
656*5113495bSYour Name num_look_aheads = NULL;
657*5113495bSYour Name }
658*5113495bSYour Name
659*5113495bSYour Name /* process trailer data that follows HDR and
660*5113495bSYour Name * application payload
661*5113495bSYour Name */
662*5113495bSYour Name status =
663*5113495bSYour Name hif_dev_process_trailer(pdev,
664*5113495bSYour Name (buf + HTC_HDR_LENGTH +
665*5113495bSYour Name payloadLen - temp),
666*5113495bSYour Name temp,
667*5113495bSYour Name next_look_aheads,
668*5113495bSYour Name num_look_aheads,
669*5113495bSYour Name packet->Endpoint);
670*5113495bSYour Name
671*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status))
672*5113495bSYour Name break;
673*5113495bSYour Name }
674*5113495bSYour Name } while (false);
675*5113495bSYour Name
676*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status)) {
677*5113495bSYour Name /* dump the whole packet */
678*5113495bSYour Name debug_dump_bytes(buf, packet->ActualLength,
679*5113495bSYour Name "BAD HTC Recv PKT");
680*5113495bSYour Name } else {
681*5113495bSYour Name if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
682*5113495bSYour Name if (packet->ActualLength > 0) {
683*5113495bSYour Name AR_DEBUG_PRINTBUF(packet->pBuffer,
684*5113495bSYour Name packet->ActualLength,
685*5113495bSYour Name "HTC - Application Msg");
686*5113495bSYour Name }
687*5113495bSYour Name }
688*5113495bSYour Name }
689*5113495bSYour Name AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
690*5113495bSYour Name ("-hif_dev_process_recv_header\n"));
691*5113495bSYour Name return status;
692*5113495bSYour Name }
693*5113495bSYour Name
694*5113495bSYour Name /**
695*5113495bSYour Name * hif_dev_free_recv_pkt_queue() - Free the allocated recv packets in the queue
696*5113495bSYour Name * @recv_pkt_queue : The queue that contains the packets to be queued
697*5113495bSYour Name *
698*5113495bSYour Name * Return : NONE
699*5113495bSYour Name */
hif_dev_free_recv_pkt_queue(HTC_PACKET_QUEUE * recv_pkt_queue)700*5113495bSYour Name void hif_dev_free_recv_pkt_queue(HTC_PACKET_QUEUE *recv_pkt_queue)
701*5113495bSYour Name {
702*5113495bSYour Name HTC_PACKET *packet;
703*5113495bSYour Name qdf_nbuf_t netbuf;
704*5113495bSYour Name
705*5113495bSYour Name while (!HTC_QUEUE_EMPTY(recv_pkt_queue)) {
706*5113495bSYour Name packet = htc_packet_dequeue(recv_pkt_queue);
707*5113495bSYour Name if (!packet)
708*5113495bSYour Name break;
709*5113495bSYour Name netbuf = (qdf_nbuf_t)packet->pNetBufContext;
710*5113495bSYour Name if (netbuf)
711*5113495bSYour Name qdf_nbuf_free(netbuf);
712*5113495bSYour Name }
713*5113495bSYour Name }
714