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