xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/transfer/adma.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <qdf_lock.h>
21 #include "adma.h"
22 #include "hif_sdio_internal.h"
23 #include "pld_sdio.h"
24 #include "if_sdio.h"
25 
26 /**
27  * hif_dev_get_fifo_address() - get the fifo addresses for dma
28  * @pdev:  SDIO HIF object
29  * @c : FIFO address config pointer
30  *
31  * Return : 0 for success, non-zero for error
32  */
33 int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
34 			     void *c,
35 			     uint32_t config_len)
36 {
37 	/* SDIO AL handles DMA Addresses */
38 	return 0;
39 }
40 
41 /**
42  * hif_dev_get_block_size() - get the adma block size for dma
43  * @config : block size config pointer
44  *
45  * Return : NONE
46  */
47 void hif_dev_get_block_size(void *config)
48 {
49 	/* TODO Get block size used by AL Layer in Mission ROM Mode */
50 	*((uint32_t *)config) = HIF_BLOCK_SIZE; /* QCN_SDIO_MROM_BLK_SZ TODO */
51 }
52 
53 /**
54  * hif_dev_configure_pipes() - configure pipes
55  * @pdev: SDIO HIF object
56  * @func: sdio function object
57  *
58  * Return : 0 for success, non-zero for error
59  */
60 int hif_dev_configure_pipes(struct hif_sdio_dev *pdev, struct sdio_func *func)
61 {
62 	/* SDIO AL Configures SDIO Channels */
63 	return 0;
64 }
65 
66 /** hif_dev_set_mailbox_swap() - Set the mailbox swap
67  * @pdev : The HIF layer object
68  *
69  * Return: none
70  */
71 void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
72 {
73 	/* SDIO AL doesn't use mailbox architecture */
74 }
75 
76 /** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
77  * @pdev : The HIF layer object
78  *
79  * Return: true or false
80  */
81 bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
82 {
83 	/* SDIO AL doesn't use mailbox architecture */
84 	return false;
85 }
86 
87 /**
88  * hif_dev_dsr_handler() - Synchronous interrupt handler
89  *
90  * @context: hif send context
91  *
92  * Return: 0 for success and non-zero for failure
93  */
94 QDF_STATUS hif_dev_dsr_handler(void *context)
95 {
96 	/* SDIO AL handles interrupts */
97 	return QDF_STATUS_SUCCESS;
98 }
99 
100 /**
101  * hif_dev_map_service_to_pipe() - maps ul/dl pipe to service id.
102  * @pDev: SDIO HIF object
103  * @ServiceId: service index
104  * @ULPipe: uplink pipe id
105  * @DLPipe: down-linklink pipe id
106  *
107  * Return: 0 on success, error value on invalid map
108  */
109 QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_dev *pdev, uint16_t svc,
110 				       uint8_t *ul_pipe, uint8_t *dl_pipe)
111 {
112 	QDF_STATUS status = QDF_STATUS_SUCCESS;
113 
114 	switch (svc) {
115 	case HTT_DATA_MSG_SVC:
116 		*dl_pipe = 2;
117 		*ul_pipe = 3;
118 		break;
119 
120 	case HTC_CTRL_RSVD_SVC:
121 	case HTC_RAW_STREAMS_SVC:
122 		*dl_pipe = 0;
123 		*ul_pipe = 1;
124 		break;
125 
126 	case WMI_DATA_BE_SVC:
127 	case WMI_DATA_BK_SVC:
128 	case WMI_DATA_VI_SVC:
129 	case WMI_DATA_VO_SVC:
130 		*dl_pipe = 2;
131 		*ul_pipe = 3;
132 		break;
133 
134 	case WMI_CONTROL_SVC:
135 		*dl_pipe = 0;
136 		*ul_pipe = 1;
137 		break;
138 
139 	default:
140 		hif_err("Invalid service: %d", svc);
141 		status = QDF_STATUS_E_INVAL;
142 		break;
143 	}
144 	return status;
145 }
146 
147 /**
148  * hif_bus_configure() - configure the bus
149  * @hif_sc: pointer to the hif context.
150  *
151  * return: 0 for success. nonzero for failure.
152  */
153 int hif_sdio_bus_configure(struct hif_softc *hif_sc)
154 {
155 	struct pld_wlan_enable_cfg cfg;
156 	enum pld_driver_mode mode;
157 	uint32_t con_mode = hif_get_conparam(hif_sc);
158 
159 	if (con_mode == QDF_GLOBAL_FTM_MODE)
160 		mode = PLD_FTM;
161 	else if (con_mode == QDF_GLOBAL_COLDBOOT_CALIB_MODE)
162 		mode = PLD_COLDBOOT_CALIBRATION;
163 	else if (QDF_IS_EPPING_ENABLED(con_mode))
164 		mode = PLD_EPPING;
165 	else
166 		mode = PLD_MISSION;
167 
168 	return pld_wlan_enable(hif_sc->qdf_dev->dev, &cfg, mode);
169 }
170 
171 /** hif_dev_setup_device() - Setup device specific stuff here required for hif
172  * @pdev : HIF layer object
173  *
174  * return 0 on success, error otherwise
175  */
176 int hif_dev_setup_device(struct hif_sdio_device *pdev)
177 {
178 	hif_dev_get_block_size(&pdev->BlockSize);
179 
180 	return 0;
181 }
182 
183 /** hif_dev_mask_interrupts() - Disable the interrupts in the device
184  * @pdev SDIO HIF Object
185  *
186  * Return: NONE
187  */
188 void hif_dev_mask_interrupts(struct hif_sdio_device *pdev)
189 {
190 	/* SDIO AL Handles Interrupts */
191 }
192 
193 /** hif_dev_unmask_interrupts() - Enable the interrupts in the device
194  * @pdev SDIO HIF Object
195  *
196  * Return: NONE
197  */
198 void hif_dev_unmask_interrupts(struct hif_sdio_device *pdev)
199 {
200 	/* SDIO AL Handles Interrupts */
201 }
202 
203 /**
204  * hif_dev_map_pipe_to_adma_chan() - maps pipe id to adma chan
205  * @pdev: The pointer to the hif device object
206  * @pipeid: pipe index
207  *
208  * Return: adma channel handle
209  */
210 struct sdio_al_channel_handle *hif_dev_map_pipe_to_adma_chan
211 (
212 struct hif_sdio_device *dev,
213 uint8_t pipeid
214 )
215 {
216 	struct hif_sdio_dev *pdev = dev->HIFDevice;
217 
218 	HIF_ENTER();
219 
220 	if ((pipeid == 0) || (pipeid == 1))
221 		return pdev->al_chan[0];
222 	else if ((pipeid == 2) || (pipeid == 3))
223 		return pdev->al_chan[1];
224 	else
225 		return NULL;
226 }
227 
228 /**
229  * hif_dev_map_adma_chan_to_pipe() - map adma chan to htc pipe
230  * @pdev: The pointer to the hif device object
231  * @chan: channel number
232  * @upload: boolean to decide upload or download
233  *
234  * Return: Invalid pipe index
235  */
236 uint8_t hif_dev_map_adma_chan_to_pipe(struct hif_sdio_device *pdev,
237 				      uint8_t chan, bool upload)
238 {
239 	hif_info("chan: %u, %s", chan, upload ? "Upload" : "Download");
240 
241 	if (chan == 0) /* chan 0 is mapped to HTT */
242 		return upload ? 1 : 0;
243 	else if (chan == 1) /* chan 1 is mapped to WMI */
244 		return upload ? 3 : 2;
245 
246 	return (uint8_t)-1; /* invalid channel id */
247 }
248 
249 /**
250  * hif_get_send_address() - Get the transfer pipe address
251  * @pdev: The pointer to the hif device object
252  * @pipe: The pipe identifier
253  *
254  * Return 0 for success and non-zero for failure to map
255  */
256 int hif_get_send_address(struct hif_sdio_device *pdev,
257 			 uint8_t pipe, unsigned long *addr)
258 {
259 	struct sdio_al_channel_handle *chan = NULL;
260 
261 	if (!addr)
262 		return -EINVAL;
263 
264 	*addr = 0;
265 	chan = hif_dev_map_pipe_to_adma_chan(pdev, pipe);
266 
267 	if (!chan)
268 		return -EINVAL;
269 
270 	*addr = (unsigned long)chan;
271 
272 	return 0;
273 }
274 
275 /**
276  * hif_fixup_write_param() - Tweak the address and length parameters
277  * @pdev: The pointer to the hif device object
278  * @length: The length pointer
279  * @addr: The addr pointer
280  *
281  * Return: None
282  */
283 void hif_fixup_write_param(struct hif_sdio_dev *pdev, uint32_t req,
284 			   uint32_t *length, uint32_t *addr)
285 {
286 	HIF_ENTER();
287 	HIF_EXIT();
288 }
289 
290 #define HIF_MAX_RX_Q_ALLOC 0 /* TODO */
291 #define HIF_RX_Q_ALLOC_THRESHOLD 100
292 QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
293 			    struct sdio_func *func,
294 			    bool reset)
295 {
296 	QDF_STATUS status = QDF_STATUS_SUCCESS;
297 #if HIF_MAX_RX_Q_ALLOC
298 	qdf_list_node_t *node;
299 	struct rx_q_entry *rx_q_elem;
300 #endif
301 	HIF_ENTER();
302 
303 #if HIF_MAX_RX_Q_ALLOC
304 	qdf_spin_lock_irqsave(&device->rx_q_lock);
305 
306 	for (; device->rx_q.count; ) {
307 		qdf_list_remove_back(&device->rx_q, &node);
308 		rx_q_elem = container_of(node, struct rx_q_entry, entry);
309 		if (rx_q_elem) {
310 			if (rx_q_elem->nbuf)
311 				qdf_nbuf_free(rx_q_elem->nbuf);
312 			qdf_mem_free(rx_q_elem);
313 		}
314 	}
315 	qdf_destroy_work(0, &device->rx_q_alloc_work);
316 
317 	qdf_spin_unlock_irqrestore(&device->rx_q_lock);
318 
319 	qdf_spinlock_destroy(&device->rx_q_lock);
320 #endif
321 
322 	status = hif_sdio_func_disable(device, func, reset);
323 	if (status == QDF_STATUS_SUCCESS)
324 		device->is_disabled = true;
325 
326 	cleanup_hif_scatter_resources(device);
327 
328 	HIF_EXIT();
329 
330 	return status;
331 }
332 
333 /**
334  * hif_enable_func() - Enable SDIO function
335  *
336  * @ol_sc: HIF object pointer
337  * @device: HIF device pointer
338  * @sdio_func: SDIO function pointer
339  * @resume: If this is called from resume or probe
340  *
341  * Return: 0 in case of success, else error value
342  */
343 QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
344 			   struct sdio_func *func, bool resume)
345 {
346 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
347 
348 	if (!device) {
349 		hif_err("HIF device is NULL");
350 		return QDF_STATUS_E_INVAL;
351 	}
352 
353 	if (!resume)
354 		ret = hif_sdio_probe(ol_sc, func, device);
355 
356 #if HIF_MAX_RX_Q_ALLOC
357 	if (!ret) {
358 		qdf_list_create(&device->rx_q, HIF_MAX_RX_Q_ALLOC);
359 		qdf_spinlock_create(&device->rx_q_lock);
360 		qdf_create_work(0, &device->rx_q_alloc_work,
361 				hif_sdio_rx_q_alloc, (void *)device);
362 		device->rx_q_alloc_work_scheduled = true;
363 		qdf_sched_work(0, &device->rx_q_alloc_work);
364 	}
365 #endif
366 	return ret;
367 }
368 
369 /**
370  * hif_sdio_get_net_buf() - Get a network buffer from the rx q
371  * @dev - HIF device object
372  *
373  * Return - NULL if out of buffers, else qdf_nbuf_t
374  */
375 #if HIF_MAX_RX_Q_ALLOC
376 static qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev, uint16_t buf_len)
377 {
378 	qdf_list_node_t *node;
379 	qdf_nbuf_t nbuf = NULL;
380 	qdf_list_t *q = &dev->rx_q;
381 	struct rx_q_entry *elem = NULL;
382 
383 	/* TODO - Alloc nbuf based on buf_len */
384 	qdf_spin_lock_irqsave(&dev->rx_q_lock);
385 
386 	if (q->count) {
387 		qdf_list_remove_front(q, &node);
388 		elem = qdf_container_of(node, struct rx_q_entry, entry);
389 		nbuf = elem->nbuf;
390 	} else {
391 		hif_err("no rx q elements");
392 	}
393 
394 	if (q->count <= HIF_RX_Q_ALLOC_THRESHOLD &&
395 	    !dev->rx_q_alloc_work_scheduled) {
396 		dev->rx_q_alloc_work_scheduled = true;
397 		qdf_sched_work(0, &dev->rx_q_alloc_work);
398 	}
399 
400 	qdf_spin_unlock_irqrestore(&dev->rx_q_lock);
401 
402 	qdf_mem_free(elem);
403 
404 	return nbuf;
405 }
406 #else
407 static qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev, uint16_t buf_len)
408 {
409 	qdf_nbuf_t nbuf;
410 
411 	if (!buf_len)
412 		buf_len = HIF_SDIO_RX_BUFFER_SIZE;
413 
414 	nbuf = qdf_nbuf_alloc(NULL, buf_len, 0, 4, false);
415 
416 	return nbuf;
417 }
418 #endif
419 /**
420  * hif_sdio_rx_q_alloc() - Deferred work for pre-alloc rx q
421  * @ctx - Pointer to context object
422  *
423  * Return NONE
424  */
425 #if HIF_MAX_RX_Q_ALLOC
426 void hif_sdio_rx_q_alloc(void *ctx)
427 {
428 	struct rx_q_entry *rx_q_elem;
429 	struct hif_sdio_dev *dev = (struct hif_sdio_dev *)ctx;
430 	unsigned int rx_q_count = dev->rx_q.count;
431 
432 	HIF_ENTER();
433 	qdf_spin_lock_irqsave(&dev->rx_q_lock);
434 
435 	for (; rx_q_count < dev->rx_q.max_size; rx_q_count++) {
436 		rx_q_elem = qdf_mem_malloc(sizeof(struct rx_q_entry));
437 		if (!rx_q_elem) {
438 			hif_err("Failed to alloc rx q elem");
439 			break;
440 		}
441 
442 		/* TODO - Alloc nbuf based on payload_len in HTC Header */
443 		rx_q_elem->nbuf = qdf_nbuf_alloc(NULL, HIF_SDIO_RX_BUFFER_SIZE,
444 						 0, 4, false);
445 		if (!rx_q_elem->nbuf) {
446 			hif_err("Failed to alloc nbuf for rx");
447 			qdf_mem_free(rx_q_elem);
448 			break;
449 		}
450 
451 		qdf_list_insert_back(&dev->rx_q, &rx_q_elem->entry);
452 	}
453 	dev->rx_q_alloc_work_scheduled = false;
454 
455 	qdf_spin_unlock_irqrestore(&dev->rx_q_lock);
456 	HIF_EXIT();
457 }
458 #else
459 void hif_sdio_rx_q_alloc(void *ctx)
460 {
461 }
462 #endif
463 
464 #include <linux/qcn_sdio_al.h>
465 
466 struct sdio_al_channel_data qcn7605_chan[HIF_SDIO_MAX_AL_CHANNELS] = {
467 	{
468 		.name = "SDIO_AL_WLAN_CH0", /* HTT */
469 		.client_data = NULL, /* populate from client handle */
470 		.ul_xfer_cb = ul_xfer_cb,
471 		.dl_xfer_cb = dl_xfer_cb,
472 		.dl_data_avail_cb = dl_data_avail_cb,
473 		.dl_meta_data_cb = NULL
474 	},
475 	{
476 		.name = "SDIO_AL_WLAN_CH1", /* WMI */
477 		.client_data = NULL, /* populate from client handle */
478 		.ul_xfer_cb = ul_xfer_cb,
479 		.dl_xfer_cb = dl_xfer_cb,
480 		.dl_data_avail_cb = dl_data_avail_cb,
481 		.dl_meta_data_cb = NULL
482 	}
483 };
484 
485 /**
486  * hif_dev_register_channels()- Register transport layer channels
487  * @dev  : HIF device object
488  * @func : SDIO function pointer
489  *
490  * Return : success on configuration, else failure
491  */
492 int hif_dev_register_channels(struct hif_sdio_dev *dev, struct sdio_func *func)
493 {
494 	int ret = 0;
495 	unsigned int chan;
496 	struct sdio_al_channel_data *chan_data[HIF_ADMA_MAX_CHANS];
497 
498 	HIF_ENTER();
499 
500 	dev->al_client = pld_sdio_get_sdio_al_client_handle(func);
501 	if (ret || !dev->al_client) {
502 		hif_err("Failed to get get sdio al handle");
503 		return ret;
504 	}
505 
506 	if ((func->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
507 	    MANUFACTURER_ID_QCN7605_BASE) {
508 		dev->adma_chans_used = 2;
509 		qcn7605_chan[0].client_data = dev->al_client->client_data;
510 		qcn7605_chan[1].client_data = dev->al_client->client_data;
511 		chan_data[0] = &qcn7605_chan[0];
512 		chan_data[1] = &qcn7605_chan[1];
513 	} else {
514 		dev->adma_chans_used = 0;
515 	}
516 
517 	for (chan = 0; chan < dev->adma_chans_used; chan++) {
518 		dev->al_chan[chan] =
519 		pld_sdio_register_sdio_al_channel(dev->al_client,
520 						  chan_data[chan]);
521 		if (!dev->al_chan[chan] || IS_ERR(dev->al_chan[chan])) {
522 			ret = -EINVAL;
523 			hif_err("Channel registration failed");
524 		} else {
525 			dev->al_chan[chan]->priv = (void *)dev;
526 			hif_info("chan %s : id : %u",
527 				 chan_data[chan]->name,
528 				 dev->al_chan[chan]->channel_id);
529 		}
530 	}
531 
532 	HIF_EXIT();
533 
534 	return ret;
535 }
536 
537 /**
538  * hif_dev_unregister_channels()- Register transport layer channels
539  * @dev  : HIF device object
540  * @func : SDIO Function pointer
541  *
542  * Return : None
543  */
544 void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
545 				 struct sdio_func *func)
546 {
547 	unsigned int chan;
548 
549 	if (!dev) {
550 		hif_err("hif_sdio_dev is null");
551 		return;
552 	}
553 
554 	for (chan = 0; chan < dev->adma_chans_used; chan++) {
555 		dev->al_chan[chan]->priv = NULL;
556 		pld_sdio_unregister_sdio_al_channel(dev->al_chan[chan]);
557 	}
558 }
559 
560 /**
561  * hif_read_write() - queue a read/write request
562  * @dev: pointer to hif device structure
563  * @address: address to read, actually channel pointer
564  * @buffer: buffer to hold read/write data
565  * @length: length to read/write
566  * @request: read/write/sync/async request
567  * @context: pointer to hold calling context
568  *
569  * Return: 0, pending  on success, error number otherwise.
570  */
571 QDF_STATUS
572 hif_read_write(struct hif_sdio_dev *dev,
573 	       unsigned long sdio_al_ch_handle,
574 	       char *cbuffer, uint32_t length,
575 	       uint32_t request, void *context)
576 {
577 	QDF_STATUS status = QDF_STATUS_SUCCESS;
578 	struct sdio_al_channel_handle *ch;
579 	struct bus_request *bus_req;
580 	enum sdio_al_dma_direction dir;
581 	struct hif_sdio_device *device;
582 	QDF_STATUS (*rx_comp)(void *, qdf_nbuf_t, uint8_t);
583 	qdf_nbuf_t nbuf;
584 	int ret = 0, payload_len = 0;
585 	unsigned char *buffer = (unsigned char *)cbuffer;
586 
587 	if (!dev || !sdio_al_ch_handle) {
588 		hif_err("Device = %pK, addr = %lu", dev, sdio_al_ch_handle);
589 		return QDF_STATUS_E_INVAL;
590 	}
591 
592 	if (!(request & HIF_ASYNCHRONOUS) &&
593 	    !(request & HIF_SYNCHRONOUS)) {
594 		hif_err("Invalid request mode: %d", request);
595 		return QDF_STATUS_E_INVAL;
596 	}
597 
598 	/*sdio r/w action is not needed when suspend, so just return */
599 	if ((dev->is_suspend) &&
600 	    (dev->power_config == HIF_DEVICE_POWER_CUT)) {
601 		hif_info("skip in suspend");
602 		return QDF_STATUS_SUCCESS;
603 	}
604 
605 	ch = (struct sdio_al_channel_handle *)sdio_al_ch_handle;
606 
607 	bus_req = hif_allocate_bus_request(dev);
608 	if (!bus_req) {
609 		hif_err("Bus alloc failed");
610 		return QDF_STATUS_E_FAILURE;
611 	}
612 
613 	bus_req->address = sdio_al_ch_handle;
614 	bus_req->length = length;
615 	bus_req->request = request;
616 	bus_req->context = context;
617 	bus_req->buffer = buffer;
618 
619 	/* Request SDIO AL to do transfer */
620 	dir = (request & HIF_SDIO_WRITE) ? SDIO_AL_TX : SDIO_AL_RX;
621 
622 	if (request & HIF_SYNCHRONOUS) {
623 		ret = sdio_al_queue_transfer(ch,
624 					     dir,
625 					     bus_req->buffer,
626 					     bus_req->length,
627 					     1); /* higher priority */
628 		if (ret) {
629 			status = QDF_STATUS_E_FAILURE;
630 			hif_err("SYNC REQ failed ret: %d", ret);
631 		} else {
632 			status = QDF_STATUS_SUCCESS;
633 		}
634 
635 		hif_free_bus_request(dev, bus_req);
636 
637 		if ((status == QDF_STATUS_SUCCESS) && (dir == SDIO_AL_RX)) {
638 			nbuf = (qdf_nbuf_t)context;
639 			payload_len = HTC_GET_FIELD(bus_req->buffer,
640 						    HTC_FRAME_HDR,
641 						    PAYLOADLEN);
642 			qdf_nbuf_set_pktlen(nbuf, payload_len + HTC_HDR_LENGTH);
643 			device = (struct hif_sdio_device *)dev->htc_context;
644 			rx_comp = device->hif_callbacks.rxCompletionHandler;
645 			rx_comp(device->hif_callbacks.Context, nbuf, 0);
646 		}
647 	} else {
648 		ret = sdio_al_queue_transfer_async(ch,
649 						   dir,
650 						   bus_req->buffer,
651 						   bus_req->length,
652 						   1, /* higher priority */
653 						   (void *)bus_req);
654 		if (ret) {
655 			status = QDF_STATUS_E_FAILURE;
656 			hif_err("ASYNC REQ fail ret: %d for len: %d ch: %d",
657 				ret, length, ch->channel_id);
658 			hif_free_bus_request(dev, bus_req);
659 		} else {
660 			status = QDF_STATUS_E_PENDING;
661 		}
662 	}
663 	return status;
664 }
665 
666 /**
667  * ul_xfer_cb() - Completion call back for asynchronous transfer
668  * @ch_handle: The sdio al channel handle
669  * @result: The result of the operation
670  * @context: pointer to request context
671  *
672  * Return: None
673  */
674 void ul_xfer_cb(struct sdio_al_channel_handle *ch_handle,
675 		struct sdio_al_xfer_result *result,
676 		void *ctx)
677 {
678 	struct bus_request *req = (struct bus_request *)ctx;
679 	struct hif_sdio_dev *dev;
680 
681 	if (!ch_handle || !result) {
682 		hif_err("Invalid args");
683 		qdf_assert_always(0);
684 		return;
685 	}
686 
687 	dev = (struct hif_sdio_dev *)ch_handle->priv;
688 
689 	if (result->xfer_status) {
690 		req->status = QDF_STATUS_E_FAILURE;
691 		hif_err("ASYNC Tx failed status: %d", result->xfer_status);
692 	} else {
693 		req->status = QDF_STATUS_SUCCESS;
694 	}
695 
696 	dev->htc_callbacks.rw_compl_handler(req->context, req->status);
697 
698 	hif_free_bus_request(dev, req);
699 }
700 
701 /**
702  * dl_data_avail_cb() - Called when data is available on a channel
703  * @ch_handle: The sdio al channel handle
704  * @len: The len of data available to download
705  *
706  * Return: None
707  */
708 /* Use the asynchronous method of transfer. This will help in
709  * completing READ in the transfer done callback later which
710  * runs in sdio al thread context. If we do the synchronous
711  * transfer here, the thread context won't be available and
712  * perhaps a new thread may be required here.
713  */
714 void dl_data_avail_cb(struct sdio_al_channel_handle *ch_handle,
715 		      unsigned int len)
716 {
717 	struct hif_sdio_dev *dev;
718 	unsigned int chan;
719 	qdf_nbuf_t nbuf;
720 
721 	if (!ch_handle || !len) {
722 		hif_err("Invalid args %u", len);
723 		qdf_assert_always(0);
724 		return;
725 	}
726 
727 	dev = (struct hif_sdio_dev *)ch_handle->priv;
728 	chan = ch_handle->channel_id;
729 
730 	if (chan > HIF_SDIO_MAX_AL_CHANNELS) {
731 		hif_err("Invalid Ch ID %d", chan);
732 		return;
733 	}
734 
735 	/* allocate a buffer for reading the data from the chip.
736 	 * Note that this is raw, unparsed buffer and will be
737 	 * processed in the transfer done callback.
738 	 */
739 	/* TODO, use global buffer instead of runtime allocations */
740 	nbuf = qdf_nbuf_alloc(NULL, len, 0, 4, false);
741 
742 	if (!nbuf) {
743 		hif_err("Unable to alloc netbuf %u bytes", len);
744 		return;
745 	}
746 
747 	hif_read_write(dev, (unsigned long)ch_handle, nbuf->data, len,
748 		       HIF_RD_ASYNC_BLOCK_FIX, nbuf);
749 }
750 
751 #define is_pad_block(buf)	(*((uint32_t *)buf) == 0xbabababa)
752 uint16_t g_dbg_payload_len;
753 
754 /**
755  * dl_xfer_cb() - Call from lower layer after transfer is completed
756  * @ch_handle: The sdio al channel handle
757  * @result: The xfer result
758  * @ctx: Context passed in the transfer queuing
759  *
760  * Return: None
761  */
762 void dl_xfer_cb(struct sdio_al_channel_handle *ch_handle,
763 		struct sdio_al_xfer_result *result,
764 		void *ctx)
765 {
766 	unsigned char *buf;
767 	qdf_nbuf_t nbuf;
768 	uint32_t len;
769 	uint16_t payload_len = 0;
770 	struct hif_sdio_dev *dev;
771 	struct hif_sdio_device *device;
772 	struct bus_request *bus_req = (struct bus_request *)ctx;
773 	QDF_STATUS (*rx_completion)(void *, qdf_nbuf_t, uint8_t);
774 
775 	if (!bus_req) {
776 		hif_err("Bus Req NULL!!!");
777 		qdf_assert_always(0);
778 		return;
779 	}
780 
781 	if (!ch_handle || !result) {
782 		hif_err("Invalid args %pK %pK", ch_handle, result);
783 		qdf_assert_always(0);
784 		return;
785 	}
786 
787 	dev = (struct hif_sdio_dev *)ch_handle->priv;
788 	if (result->xfer_status) {
789 		hif_err("ASYNC Rx failed %d", result->xfer_status);
790 		qdf_nbuf_free((qdf_nbuf_t)bus_req->context);
791 		hif_free_bus_request(dev, bus_req);
792 		return;
793 	}
794 
795 	device = (struct hif_sdio_device *)dev->htc_context;
796 	rx_completion = device->hif_callbacks.rxCompletionHandler;
797 
798 	buf = (unsigned char *)result->buf_addr;
799 	len = (unsigned int)result->xfer_len;
800 
801 	while (len >= sizeof(HTC_FRAME_HDR)) {
802 		if (is_pad_block(buf)) {
803 			/* End of Rx Buffer */
804 			break;
805 		}
806 
807 		if (HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID) >=
808 		    ENDPOINT_MAX) {
809 			hif_err("Invalid endpoint id: %u",
810 				HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID));
811 			break;
812 		}
813 
814 		/* Copy the HTC frame to the alloc'd packet buffer */
815 		payload_len = HTC_GET_FIELD(buf, HTC_FRAME_HDR, PAYLOADLEN);
816 		payload_len = qdf_le16_to_cpu(payload_len);
817 		if (!payload_len) {
818 			hif_err("Invalid Payload len %d bytes", payload_len);
819 			break;
820 		}
821 		if (payload_len > g_dbg_payload_len) {
822 			g_dbg_payload_len = payload_len;
823 			hif_err("Max Rx HTC Payload = %d", g_dbg_payload_len);
824 		}
825 
826 		nbuf = hif_sdio_get_nbuf(dev, payload_len + HTC_HEADER_LEN);
827 		if (!nbuf) {
828 			hif_err("Failed to alloc rx buffer");
829 			break;
830 		}
831 
832 		/* Check if payload fits in skb */
833 		if (qdf_nbuf_tailroom(nbuf) < payload_len + HTC_HEADER_LEN) {
834 			hif_err("Payload + HTC_HDR %d > skb tailroom %d",
835 				(payload_len + 8),
836 				qdf_nbuf_tailroom(nbuf));
837 			qdf_nbuf_free(nbuf);
838 			break;
839 		}
840 
841 		qdf_mem_copy((uint8_t *)qdf_nbuf_data(nbuf), buf,
842 			     payload_len + HTC_HEADER_LEN);
843 
844 		qdf_nbuf_put_tail(nbuf, payload_len + HTC_HDR_LENGTH);
845 
846 		rx_completion(device->hif_callbacks.Context, nbuf,
847 			      0); /* don't care, not used */
848 
849 		len -= payload_len + HTC_HDR_LENGTH;
850 		buf += payload_len + HTC_HDR_LENGTH;
851 	}
852 
853 	qdf_nbuf_free((qdf_nbuf_t)bus_req->context);
854 	hif_free_bus_request(dev, bus_req);
855 }
856