1 /*
2 * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 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 #ifdef CONFIG_SDIO_TRANSFER_MAILBOX
21 #define ATH_MODULE_NAME hif
22 #include <linux/kthread.h>
23 #include <qdf_types.h>
24 #include <qdf_status.h>
25 #include <qdf_timer.h>
26 #include <qdf_time.h>
27 #include <qdf_lock.h>
28 #include <qdf_mem.h>
29 #include <qdf_util.h>
30 #include <qdf_defer.h>
31 #include <qdf_atomic.h>
32 #include <qdf_nbuf.h>
33 #include <qdf_threads.h>
34 #include <athdefs.h>
35 #include <qdf_net_types.h>
36 #include <a_types.h>
37 #include <athdefs.h>
38 #include <a_osapi.h>
39 #include <hif.h>
40 #include <htc_internal.h>
41 #include <htc_services.h>
42 #include <a_debug.h>
43 #include "hif_sdio_internal.h"
44 #include "if_sdio.h"
45 #include "regtable.h"
46 #include "transfer.h"
47
48 /*
49 * The following commit was introduced in v5.17:
50 * cead18552660 ("exit: Rename complete_and_exit to kthread_complete_and_exit")
51 * Use the old name for kernels before 5.17
52 */
53 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
54 #define kthread_complete_and_exit(c, s) complete_and_exit(c, s)
55 #endif
56
57 /* by default setup a bounce buffer for the data packets,
58 * if the underlying host controller driver
59 * does not use DMA you may be able to skip this step
60 * and save the memory allocation and transfer time
61 */
62 #define HIF_USE_DMA_BOUNCE_BUFFER 1
63 #if HIF_USE_DMA_BOUNCE_BUFFER
64 /* macro to check if DMA buffer is WORD-aligned and DMA-able.
65 * Most host controllers assume the
66 * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
67 * virt_addr_valid check fails on stack memory.
68 */
69 #define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || \
70 !virt_addr_valid((buffer)))
71 #else
72 #define BUFFER_NEEDS_BOUNCE(buffer) (false)
73 #endif
74
75 #ifdef SDIO_3_0
76 /**
77 * set_extended_mbox_size() - set extended MBOX size
78 * @pinfo: sdio mailbox info
79 *
80 * Return: none.
81 */
set_extended_mbox_size(struct hif_device_mbox_info * pinfo)82 static void set_extended_mbox_size(struct hif_device_mbox_info *pinfo)
83 {
84 pinfo->mbox_prop[0].extended_size =
85 HIF_MBOX0_EXTENDED_WIDTH_AR6320_ROME_2_0;
86 pinfo->mbox_prop[1].extended_size =
87 HIF_MBOX1_EXTENDED_WIDTH_AR6320;
88 }
89
90 /**
91 * set_extended_mbox_address() - set extended MBOX address
92 * @pinfo: sdio mailbox info
93 *
94 * Return: none.
95 */
set_extended_mbox_address(struct hif_device_mbox_info * pinfo)96 static void set_extended_mbox_address(struct hif_device_mbox_info *pinfo)
97 {
98 pinfo->mbox_prop[1].extended_address =
99 pinfo->mbox_prop[0].extended_address +
100 pinfo->mbox_prop[0].extended_size +
101 HIF_MBOX_DUMMY_SPACE_SIZE_AR6320;
102 }
103 #else
set_extended_mbox_size(struct hif_device_mbox_info * pinfo)104 static void set_extended_mbox_size(struct hif_device_mbox_info *pinfo)
105 {
106 pinfo->mbox_prop[0].extended_size =
107 HIF_MBOX0_EXTENDED_WIDTH_AR6320;
108 }
109
110 static inline void
set_extended_mbox_address(struct hif_device_mbox_info * pinfo)111 set_extended_mbox_address(struct hif_device_mbox_info *pinfo)
112 {
113 }
114 #endif
115
116 /**
117 * set_extended_mbox_window_info() - set extended MBOX window
118 * information for SDIO interconnects
119 * @manf_id: manufacturer id
120 * @pinfo: sdio mailbox info
121 *
122 * Return: none.
123 */
set_extended_mbox_window_info(uint16_t manf_id,struct hif_device_mbox_info * pinfo)124 static void set_extended_mbox_window_info(uint16_t manf_id,
125 struct hif_device_mbox_info *pinfo)
126 {
127 switch (manf_id & MANUFACTURER_ID_AR6K_BASE_MASK) {
128 case MANUFACTURER_ID_AR6002_BASE:
129 /* MBOX 0 has an extended range */
130
131 pinfo->mbox_prop[0].extended_address =
132 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1;
133 pinfo->mbox_prop[0].extended_size =
134 HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1;
135
136 pinfo->mbox_prop[0].extended_address =
137 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1;
138 pinfo->mbox_prop[0].extended_size =
139 HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1;
140
141 pinfo->mbox_prop[0].extended_address =
142 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6004;
143 pinfo->mbox_prop[0].extended_size =
144 HIF_MBOX0_EXTENDED_WIDTH_AR6004;
145
146 break;
147 case MANUFACTURER_ID_AR6003_BASE:
148 /* MBOX 0 has an extended range */
149 pinfo->mbox_prop[0].extended_address =
150 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1;
151 pinfo->mbox_prop[0].extended_size =
152 HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1;
153 pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR;
154 pinfo->gmbox_size = HIF_GMBOX_WIDTH;
155 break;
156 case MANUFACTURER_ID_AR6004_BASE:
157 pinfo->mbox_prop[0].extended_address =
158 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6004;
159 pinfo->mbox_prop[0].extended_size =
160 HIF_MBOX0_EXTENDED_WIDTH_AR6004;
161 pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR;
162 pinfo->gmbox_size = HIF_GMBOX_WIDTH;
163 break;
164 case MANUFACTURER_ID_AR6320_BASE:
165 {
166 uint16_t rev = manf_id & MANUFACTURER_ID_AR6K_REV_MASK;
167
168 pinfo->mbox_prop[0].extended_address =
169 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6320;
170 if (rev < 4)
171 pinfo->mbox_prop[0].extended_size =
172 HIF_MBOX0_EXTENDED_WIDTH_AR6320;
173 else
174 set_extended_mbox_size(pinfo);
175 set_extended_mbox_address(pinfo);
176 pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR;
177 pinfo->gmbox_size = HIF_GMBOX_WIDTH;
178 break;
179 }
180 case MANUFACTURER_ID_QCA9377_BASE:
181 case MANUFACTURER_ID_QCA9379_BASE:
182 pinfo->mbox_prop[0].extended_address =
183 HIF_MBOX0_EXTENDED_BASE_ADDR_AR6320;
184 pinfo->mbox_prop[0].extended_size =
185 HIF_MBOX0_EXTENDED_WIDTH_AR6320_ROME_2_0;
186 pinfo->mbox_prop[1].extended_address =
187 pinfo->mbox_prop[0].extended_address +
188 pinfo->mbox_prop[0].extended_size +
189 HIF_MBOX_DUMMY_SPACE_SIZE_AR6320;
190 pinfo->mbox_prop[1].extended_size =
191 HIF_MBOX1_EXTENDED_WIDTH_AR6320;
192 pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR;
193 pinfo->gmbox_size = HIF_GMBOX_WIDTH;
194 break;
195 default:
196 A_ASSERT(false);
197 break;
198 }
199 }
200
201 /** hif_dev_set_mailbox_swap() - Set the mailbox swap from firmware
202 * @pdev : The HIF layer object
203 *
204 * Return: none
205 */
hif_dev_set_mailbox_swap(struct hif_sdio_dev * pdev)206 void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
207 {
208 struct hif_sdio_device *hif_device = hif_dev_from_hif(pdev);
209
210 HIF_ENTER();
211
212 hif_device->swap_mailbox = true;
213
214 HIF_EXIT();
215 }
216
217 /** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
218 * @pdev : The HIF layer object
219 *
220 * Return: true or false
221 */
hif_dev_get_mailbox_swap(struct hif_sdio_dev * pdev)222 bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
223 {
224 struct hif_sdio_device *hif_device;
225
226 HIF_ENTER();
227
228 hif_device = hif_dev_from_hif(pdev);
229
230 HIF_EXIT();
231
232 return hif_device->swap_mailbox;
233 }
234
235 /**
236 * hif_dev_get_fifo_address() - get the fifo addresses for dma
237 * @pdev: SDIO HIF object
238 * @config: mbox address config pointer
239 * @config_len: config length
240 *
241 * Return : 0 for success, non-zero for error
242 */
hif_dev_get_fifo_address(struct hif_sdio_dev * pdev,void * config,uint32_t config_len)243 int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
244 void *config,
245 uint32_t config_len)
246 {
247 uint32_t count;
248 struct hif_device_mbox_info *cfg =
249 (struct hif_device_mbox_info *)config;
250
251 for (count = 0; count < 4; count++)
252 cfg->mbox_addresses[count] = HIF_MBOX_START_ADDR(count);
253
254 if (config_len >= sizeof(struct hif_device_mbox_info)) {
255 set_extended_mbox_window_info((uint16_t)pdev->func->device,
256 cfg);
257 return 0;
258 }
259
260 return -EINVAL;
261 }
262
263 /**
264 * hif_dev_get_block_size() - get the mbox block size for dma
265 * @config : mbox size config pointer
266 *
267 * Return : NONE
268 */
hif_dev_get_block_size(void * config)269 void hif_dev_get_block_size(void *config)
270 {
271 ((uint32_t *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
272 ((uint32_t *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
273 ((uint32_t *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
274 ((uint32_t *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
275 }
276
277 /**
278 * hif_dev_map_service_to_pipe() - maps ul/dl pipe to service id.
279 * @pdev: SDIO HIF object
280 * @svc: service index
281 * @ul_pipe: uplink pipe id
282 * @dl_pipe: down-linklink pipe id
283 *
284 * Return: 0 on success, error value on invalid map
285 */
hif_dev_map_service_to_pipe(struct hif_sdio_dev * pdev,uint16_t svc,uint8_t * ul_pipe,uint8_t * dl_pipe)286 QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_dev *pdev, uint16_t svc,
287 uint8_t *ul_pipe, uint8_t *dl_pipe)
288 {
289 QDF_STATUS status = QDF_STATUS_SUCCESS;
290
291 switch (svc) {
292 case HTT_DATA_MSG_SVC:
293 if (hif_dev_get_mailbox_swap(pdev)) {
294 *ul_pipe = 1;
295 *dl_pipe = 0;
296 } else {
297 *ul_pipe = 3;
298 *dl_pipe = 2;
299 }
300 break;
301
302 case HTC_CTRL_RSVD_SVC:
303 case HTC_RAW_STREAMS_SVC:
304 *ul_pipe = 1;
305 *dl_pipe = 0;
306 break;
307
308 case WMI_DATA_BE_SVC:
309 case WMI_DATA_BK_SVC:
310 case WMI_DATA_VI_SVC:
311 case WMI_DATA_VO_SVC:
312 *ul_pipe = 1;
313 *dl_pipe = 0;
314 break;
315
316 case WMI_CONTROL_SVC:
317 if (hif_dev_get_mailbox_swap(pdev)) {
318 *ul_pipe = 3;
319 *dl_pipe = 2;
320 } else {
321 *ul_pipe = 1;
322 *dl_pipe = 0;
323 }
324 break;
325
326 default:
327 hif_err("Invalid service: %d", svc);
328 status = QDF_STATUS_E_INVAL;
329 break;
330 }
331 return status;
332 }
333
334 /** hif_dev_setup_device() - Setup device specific stuff here required for hif
335 * @pdev : HIF layer object
336 *
337 * return 0 on success, error otherwise
338 */
hif_dev_setup_device(struct hif_sdio_device * pdev)339 int hif_dev_setup_device(struct hif_sdio_device *pdev)
340 {
341 int status = 0;
342 uint32_t blocksizes[MAILBOX_COUNT];
343
344 status = hif_configure_device(NULL, pdev->HIFDevice,
345 HIF_DEVICE_GET_FIFO_ADDR,
346 &pdev->MailBoxInfo,
347 sizeof(pdev->MailBoxInfo));
348
349 if (status != QDF_STATUS_SUCCESS)
350 hif_err("HIF_DEVICE_GET_MBOX_ADDR failed");
351
352 status = hif_configure_device(NULL, pdev->HIFDevice,
353 HIF_DEVICE_GET_BLOCK_SIZE,
354 blocksizes, sizeof(blocksizes));
355 if (status != QDF_STATUS_SUCCESS)
356 hif_err("HIF_DEVICE_GET_MBOX_BLOCK_SIZE fail");
357
358 pdev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE];
359
360 return status;
361 }
362
363 /** hif_dev_mask_interrupts() - Disable the interrupts in the device
364 * @pdev SDIO HIF Object
365 *
366 * Return: NONE
367 */
hif_dev_mask_interrupts(struct hif_sdio_device * pdev)368 void hif_dev_mask_interrupts(struct hif_sdio_device *pdev)
369 {
370 int status = QDF_STATUS_SUCCESS;
371
372 HIF_ENTER();
373 /* Disable all interrupts */
374 LOCK_HIF_DEV(pdev);
375 mboxEnaRegs(pdev).int_status_enable = 0;
376 mboxEnaRegs(pdev).cpu_int_status_enable = 0;
377 mboxEnaRegs(pdev).error_status_enable = 0;
378 mboxEnaRegs(pdev).counter_int_status_enable = 0;
379 UNLOCK_HIF_DEV(pdev);
380
381 /* always synchronous */
382 status = hif_read_write(pdev->HIFDevice,
383 INT_STATUS_ENABLE_ADDRESS,
384 (char *)&mboxEnaRegs(pdev),
385 sizeof(struct MBOX_IRQ_ENABLE_REGISTERS),
386 HIF_WR_SYNC_BYTE_INC, NULL);
387
388 if (status != QDF_STATUS_SUCCESS)
389 hif_err("Updating intr reg: %d", status);
390 }
391
392 /** hif_dev_unmask_interrupts() - Enable the interrupts in the device
393 * @pdev SDIO HIF Object
394 *
395 * Return: NONE
396 */
hif_dev_unmask_interrupts(struct hif_sdio_device * pdev)397 void hif_dev_unmask_interrupts(struct hif_sdio_device *pdev)
398 {
399 QDF_STATUS status = QDF_STATUS_SUCCESS;
400
401 LOCK_HIF_DEV(pdev);
402
403 /* Enable all the interrupts except for the internal
404 * AR6000 CPU interrupt
405 */
406 mboxEnaRegs(pdev).int_status_enable =
407 INT_STATUS_ENABLE_ERROR_SET(0x01) |
408 INT_STATUS_ENABLE_CPU_SET(0x01)
409 | INT_STATUS_ENABLE_COUNTER_SET(0x01);
410
411 /* enable 2 mboxs INT */
412 mboxEnaRegs(pdev).int_status_enable |=
413 INT_STATUS_ENABLE_MBOX_DATA_SET(0x01) |
414 INT_STATUS_ENABLE_MBOX_DATA_SET(0x02);
415
416 /* Set up the CPU Interrupt Status Register, enable
417 * CPU sourced interrupt #0, #1.
418 * #0 is used for report assertion from target
419 * #1 is used for inform host that credit arrived
420 */
421 mboxEnaRegs(pdev).cpu_int_status_enable = 0x03;
422
423 /* Set up the Error Interrupt Status Register */
424 mboxEnaRegs(pdev).error_status_enable =
425 (ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01)
426 | ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01)) >> 16;
427
428 /* Set up the Counter Interrupt Status Register
429 * (only for debug interrupt to catch fatal errors)
430 */
431 mboxEnaRegs(pdev).counter_int_status_enable =
432 (COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK)) >> 24;
433
434 UNLOCK_HIF_DEV(pdev);
435
436 /* always synchronous */
437 status = hif_read_write(pdev->HIFDevice,
438 INT_STATUS_ENABLE_ADDRESS,
439 (char *)&mboxEnaRegs(pdev),
440 sizeof(struct MBOX_IRQ_ENABLE_REGISTERS),
441 HIF_WR_SYNC_BYTE_INC,
442 NULL);
443
444 if (status != QDF_STATUS_SUCCESS)
445 hif_err("Updating intr reg: %d", status);
446 }
447
hif_dev_dump_registers(struct hif_sdio_device * pdev,struct MBOX_IRQ_PROC_REGISTERS * irq_proc,struct MBOX_IRQ_ENABLE_REGISTERS * irq_en,struct MBOX_COUNTER_REGISTERS * mbox_regs)448 void hif_dev_dump_registers(struct hif_sdio_device *pdev,
449 struct MBOX_IRQ_PROC_REGISTERS *irq_proc,
450 struct MBOX_IRQ_ENABLE_REGISTERS *irq_en,
451 struct MBOX_COUNTER_REGISTERS *mbox_regs)
452 {
453 int i = 0;
454
455 hif_debug("Mailbox registers:");
456
457 if (irq_proc) {
458 hif_debug("HostIntStatus: 0x%x ", irq_proc->host_int_status);
459 hif_debug("CPUIntStatus: 0x%x ", irq_proc->cpu_int_status);
460 hif_debug("ErrorIntStatus: 0x%x ", irq_proc->error_int_status);
461 hif_debug("CounterIntStat: 0x%x ",
462 irq_proc->counter_int_status);
463 hif_debug("MboxFrame: 0x%x ", irq_proc->mbox_frame);
464 hif_debug("RxLKAValid: 0x%x ", irq_proc->rx_lookahead_valid);
465 hif_debug("RxLKA0: 0x%x", irq_proc->rx_lookahead[0]);
466 hif_debug("RxLKA1: 0x%x ", irq_proc->rx_lookahead[1]);
467 hif_debug("RxLKA2: 0x%x ", irq_proc->rx_lookahead[2]);
468 hif_debug("RxLKA3: 0x%x", irq_proc->rx_lookahead[3]);
469
470 if (pdev->MailBoxInfo.gmbox_address != 0) {
471 hif_debug("GMBOX-HostIntStatus2: 0x%x ",
472 irq_proc->host_int_status2);
473 hif_debug("GMBOX-RX-Avail: 0x%x ",
474 irq_proc->gmbox_rx_avail);
475 }
476 }
477
478 if (irq_en) {
479 hif_debug("IntStatusEnable: 0x%x",
480 irq_en->int_status_enable);
481 hif_debug("CounterIntStatus: 0x%x",
482 irq_en->counter_int_status_enable);
483 }
484
485 for (i = 0; mbox_regs && i < 4; i++)
486 hif_debug("Counter[%d]: 0x%x", i, mbox_regs->counter[i]);
487 }
488
489 /* under HL SDIO, with Interface Memory support, we have
490 * the following reasons to support 2 mboxs:
491 * a) we need place different buffers in different
492 * mempool, for example, data using Interface Memory,
493 * desc and other using DRAM, they need different SDIO
494 * mbox channels.
495 * b) currently, tx mempool in LL case is separated from
496 * main mempool, the structure (descs at the beginning
497 * of every pool buffer) is different, because they only
498 * need store tx desc from host. To align with LL case,
499 * we also need 2 mbox support just as PCIe LL cases.
500 */
501
502 /**
503 * hif_dev_map_pipe_to_mail_box() - maps pipe id to mailbox.
504 * @pdev: The pointer to the hif device object
505 * @pipeid: pipe index
506 *
507 * Return: mailbox index
508 */
hif_dev_map_pipe_to_mail_box(struct hif_sdio_device * pdev,uint8_t pipeid)509 static uint8_t hif_dev_map_pipe_to_mail_box(struct hif_sdio_device *pdev,
510 uint8_t pipeid)
511 {
512 if (2 == pipeid || 3 == pipeid)
513 return 1;
514 else if (0 == pipeid || 1 == pipeid)
515 return 0;
516
517 hif_err("pipeid=%d invalid", pipeid);
518
519 qdf_assert(0);
520
521 return INVALID_MAILBOX_NUMBER;
522 }
523
524 /**
525 * hif_dev_map_mail_box_to_pipe() - map sdio mailbox to htc pipe.
526 * @pdev: The pointer to the hif device object
527 * @mbox_index: mailbox index
528 * @upload: boolean to decide mailbox index
529 *
530 * Return: Invalid pipe index
531 */
hif_dev_map_mail_box_to_pipe(struct hif_sdio_device * pdev,uint8_t mbox_index,bool upload)532 static uint8_t hif_dev_map_mail_box_to_pipe(struct hif_sdio_device *pdev,
533 uint8_t mbox_index, bool upload)
534 {
535 if (mbox_index == 0)
536 return upload ? 1 : 0;
537 else if (mbox_index == 1)
538 return upload ? 3 : 2;
539
540 hif_err("mbox_index=%d, upload=%d invalid", mbox_index, upload);
541
542 qdf_assert(0);
543
544 return INVALID_MAILBOX_NUMBER; /* invalid pipe id */
545 }
546
547 /**
548 * hif_get_send_address() - Get the transfer pipe address
549 * @pdev: The pointer to the hif device object
550 * @pipe: The pipe identifier
551 * @addr:
552 *
553 * Return 0 for success and non-zero for failure to map
554 */
hif_get_send_address(struct hif_sdio_device * pdev,uint8_t pipe,unsigned long * addr)555 int hif_get_send_address(struct hif_sdio_device *pdev,
556 uint8_t pipe, unsigned long *addr)
557 {
558 uint8_t mbox_index = INVALID_MAILBOX_NUMBER;
559
560 if (!addr)
561 return -EINVAL;
562
563 mbox_index = hif_dev_map_pipe_to_mail_box(pdev, pipe);
564
565 if (mbox_index == INVALID_MAILBOX_NUMBER)
566 return -EINVAL;
567
568 *addr = pdev->MailBoxInfo.mbox_prop[mbox_index].extended_address;
569
570 return 0;
571 }
572
573 /**
574 * hif_fixup_write_param() - Tweak the address and length parameters
575 * @pdev: The pointer to the hif device object
576 * @req:
577 * @length: The length pointer
578 * @addr: The addr pointer
579 *
580 * Return: None
581 */
hif_fixup_write_param(struct hif_sdio_dev * pdev,uint32_t req,uint32_t * length,uint32_t * addr)582 void hif_fixup_write_param(struct hif_sdio_dev *pdev, uint32_t req,
583 uint32_t *length, uint32_t *addr)
584 {
585 struct hif_device_mbox_info mboxinfo;
586 uint32_t taddr = *addr, mboxlen = 0;
587
588 hif_configure_device(NULL, pdev, HIF_DEVICE_GET_FIFO_ADDR,
589 &mboxinfo, sizeof(mboxinfo));
590
591 if (taddr >= 0x800 && taddr < 0xC00) {
592 /* Host control register and CIS Window */
593 mboxlen = 0;
594 } else if (taddr == mboxinfo.mbox_addresses[0] ||
595 taddr == mboxinfo.mbox_addresses[1] ||
596 taddr == mboxinfo.mbox_addresses[2] ||
597 taddr == mboxinfo.mbox_addresses[3]) {
598 mboxlen = HIF_MBOX_WIDTH;
599 } else if (taddr == mboxinfo.mbox_prop[0].extended_address) {
600 mboxlen = mboxinfo.mbox_prop[0].extended_size;
601 } else if (taddr == mboxinfo.mbox_prop[1].extended_address) {
602 mboxlen = mboxinfo.mbox_prop[1].extended_size;
603 } else {
604 hif_err("Invalid write addr: 0x%08x", taddr);
605 return;
606 }
607
608 if (mboxlen != 0) {
609 if (*length > mboxlen) {
610 hif_err("Error (%u > %u)", *length, mboxlen);
611 return;
612 }
613
614 taddr = taddr + (mboxlen - *length);
615 taddr = taddr + ((req & HIF_DUMMY_SPACE_MASK) >> 16);
616 *addr = taddr;
617 }
618 }
619
620 /**
621 * hif_dev_recv_packet() - Receive HTC packet/packet information from device
622 * @pdev : HIF device object
623 * @packet : The HTC packet pointer
624 * @recv_length : The length of information to be received
625 * @mbox_index : The mailbox that contains this information
626 *
627 * Return 0 for success and non zero of error
628 */
hif_dev_recv_packet(struct hif_sdio_device * pdev,HTC_PACKET * packet,uint32_t recv_length,uint32_t mbox_index)629 static QDF_STATUS hif_dev_recv_packet(struct hif_sdio_device *pdev,
630 HTC_PACKET *packet,
631 uint32_t recv_length,
632 uint32_t mbox_index)
633 {
634 QDF_STATUS status;
635 uint32_t padded_length;
636 bool sync = (packet->Completion) ? false : true;
637 uint32_t req = sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX;
638
639 /* adjust the length to be a multiple of block size if appropriate */
640 padded_length = DEV_CALC_RECV_PADDED_LEN(pdev, recv_length);
641
642 if (padded_length > packet->BufferLength) {
643 hif_err("No space for padlen:%d recvlen:%d bufferlen:%d",
644 padded_length,
645 recv_length, packet->BufferLength);
646 if (packet->Completion) {
647 COMPLETE_HTC_PACKET(packet, QDF_STATUS_E_INVAL);
648 return QDF_STATUS_SUCCESS;
649 }
650 return QDF_STATUS_E_INVAL;
651 }
652
653 /* mailbox index is saved in Endpoint member */
654 hif_debug("hdr:0x%x, len:%d, padded length: %d Mbox:0x%x",
655 packet->PktInfo.AsRx.ExpectedHdr, recv_length,
656 padded_length, mbox_index);
657
658 status = hif_read_write(pdev->HIFDevice,
659 pdev->MailBoxInfo.mbox_addresses[mbox_index],
660 packet->pBuffer,
661 padded_length,
662 req, sync ? NULL : packet);
663
664 if (status != QDF_STATUS_SUCCESS && status != QDF_STATUS_E_PENDING)
665 hif_err("Failed %d", status);
666
667 if (sync) {
668 packet->Status = status;
669 if (status == QDF_STATUS_SUCCESS) {
670 HTC_FRAME_HDR *hdr = (HTC_FRAME_HDR *) packet->pBuffer;
671
672 hif_debug("EP:%d,Len:%d,Flg:%d,CB:0x%02X,0x%02X",
673 hdr->EndpointID, hdr->PayloadLen,
674 hdr->Flags, hdr->ControlBytes0,
675 hdr->ControlBytes1);
676 }
677 }
678
679 return status;
680 }
681
hif_dev_issue_recv_packet_bundle(struct hif_sdio_device * pdev,HTC_PACKET_QUEUE * recv_pkt_queue,HTC_PACKET_QUEUE * sync_completion_queue,uint8_t mail_box_index,int * num_packets_fetched,bool partial_bundle)682 static QDF_STATUS hif_dev_issue_recv_packet_bundle
683 (
684 struct hif_sdio_device *pdev,
685 HTC_PACKET_QUEUE *recv_pkt_queue,
686 HTC_PACKET_QUEUE *sync_completion_queue,
687 uint8_t mail_box_index,
688 int *num_packets_fetched,
689 bool partial_bundle
690 )
691 {
692 uint32_t padded_length;
693 int i, total_length = 0;
694 HTC_TARGET *target = NULL;
695 int bundleSpaceRemaining = 0;
696 unsigned char *bundle_buffer = NULL;
697 HTC_PACKET *packet, *packet_rx_bundle;
698 QDF_STATUS status = QDF_STATUS_SUCCESS;
699
700 target = (HTC_TARGET *)pdev->pTarget;
701
702 if ((HTC_PACKET_QUEUE_DEPTH(recv_pkt_queue) -
703 HTC_MAX_MSG_PER_BUNDLE_RX) > 0) {
704 partial_bundle = true;
705 hif_warn("partial bundle detected num: %d, %d",
706 HTC_PACKET_QUEUE_DEPTH(recv_pkt_queue),
707 HTC_MAX_MSG_PER_BUNDLE_RX);
708 }
709
710 bundleSpaceRemaining =
711 HTC_MAX_MSG_PER_BUNDLE_RX * target->TargetCreditSize;
712 packet_rx_bundle = allocate_htc_bundle_packet(target);
713 if (!packet_rx_bundle) {
714 hif_err("packet_rx_bundle is NULL");
715 qdf_sleep(NBUF_ALLOC_FAIL_WAIT_TIME); /* 100 msec sleep */
716 return QDF_STATUS_E_NOMEM;
717 }
718 bundle_buffer = packet_rx_bundle->pBuffer;
719
720 for (i = 0;
721 !HTC_QUEUE_EMPTY(recv_pkt_queue) && i < HTC_MAX_MSG_PER_BUNDLE_RX;
722 i++) {
723 packet = htc_packet_dequeue(recv_pkt_queue);
724 A_ASSERT(packet);
725 if (!packet)
726 break;
727 padded_length =
728 DEV_CALC_RECV_PADDED_LEN(pdev, packet->ActualLength);
729 if (packet->PktInfo.AsRx.HTCRxFlags &
730 HTC_RX_PKT_LAST_BUNDLED_PKT_HAS_ADDTIONAL_BLOCK)
731 padded_length += HIF_BLOCK_SIZE;
732 if ((bundleSpaceRemaining - padded_length) < 0) {
733 /* exceeds what we can transfer, put the packet back */
734 HTC_PACKET_ENQUEUE_TO_HEAD(recv_pkt_queue, packet);
735 break;
736 }
737 bundleSpaceRemaining -= padded_length;
738
739 if (partial_bundle ||
740 HTC_PACKET_QUEUE_DEPTH(recv_pkt_queue) > 0) {
741 packet->PktInfo.AsRx.HTCRxFlags |=
742 HTC_RX_PKT_IGNORE_LOOKAHEAD;
743 }
744 packet->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_PART_OF_BUNDLE;
745
746 if (sync_completion_queue)
747 HTC_PACKET_ENQUEUE(sync_completion_queue, packet);
748
749 total_length += padded_length;
750 }
751 #if DEBUG_BUNDLE
752 qdf_print("Recv bundle count %d, length %d.",
753 sync_completion_queue ?
754 HTC_PACKET_QUEUE_DEPTH(sync_completion_queue) : 0,
755 total_length);
756 #endif
757
758 status = hif_read_write(pdev->HIFDevice,
759 pdev->MailBoxInfo.
760 mbox_addresses[(int)mail_box_index],
761 bundle_buffer, total_length,
762 HIF_RD_SYNC_BLOCK_FIX, NULL);
763
764 if (status != QDF_STATUS_SUCCESS) {
765 hif_err("hif_send Failed status:%d", status);
766 } else {
767 unsigned char *buffer = bundle_buffer;
768 *num_packets_fetched = i;
769 if (sync_completion_queue) {
770 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(
771 sync_completion_queue, packet) {
772 padded_length =
773 DEV_CALC_RECV_PADDED_LEN(pdev,
774 packet->ActualLength);
775 if (packet->PktInfo.AsRx.HTCRxFlags &
776 HTC_RX_PKT_LAST_BUNDLED_PKT_HAS_ADDTIONAL_BLOCK)
777 padded_length +=
778 HIF_BLOCK_SIZE;
779 A_MEMCPY(packet->pBuffer,
780 buffer, padded_length);
781 buffer += padded_length;
782 } HTC_PACKET_QUEUE_ITERATE_END;
783 }
784 }
785 /* free bundle space under Sync mode */
786 free_htc_bundle_packet(target, packet_rx_bundle);
787 return status;
788 }
789
790 #define ISSUE_BUNDLE hif_dev_issue_recv_packet_bundle
791 static
hif_dev_recv_message_pending_handler(struct hif_sdio_device * pdev,uint8_t mail_box_index,uint32_t msg_look_aheads[],int num_look_aheads,bool * async_proc,int * num_pkts_fetched)792 QDF_STATUS hif_dev_recv_message_pending_handler(struct hif_sdio_device *pdev,
793 uint8_t mail_box_index,
794 uint32_t msg_look_aheads[],
795 int num_look_aheads,
796 bool *async_proc,
797 int *num_pkts_fetched)
798 {
799 int pkts_fetched;
800 HTC_PACKET *pkt;
801 HTC_ENDPOINT_ID id;
802 bool partial_bundle;
803 int total_fetched = 0;
804 bool asyncProc = false;
805 QDF_STATUS status = QDF_STATUS_SUCCESS;
806 uint32_t look_aheads[HTC_MAX_MSG_PER_BUNDLE_RX];
807 HTC_PACKET_QUEUE recv_q, sync_comp_q;
808 QDF_STATUS (*rxCompletion)(void *, qdf_nbuf_t, uint8_t);
809
810 hif_debug("NumLookAheads: %d", num_look_aheads);
811
812 if (num_pkts_fetched)
813 *num_pkts_fetched = 0;
814
815 if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pdev)) {
816 /* We use async mode to get the packets if the
817 * device layer supports it. The device layer
818 * interfaces with HIF in which HIF may have
819 * restrictions on how interrupts are processed
820 */
821 asyncProc = true;
822 }
823
824 if (async_proc) {
825 /* indicate to caller how we decided to process this */
826 *async_proc = asyncProc;
827 }
828
829 if (num_look_aheads > HTC_MAX_MSG_PER_BUNDLE_RX) {
830 A_ASSERT(false);
831 return QDF_STATUS_E_PROTO;
832 }
833
834 A_MEMCPY(look_aheads, msg_look_aheads,
835 (sizeof(uint32_t)) * num_look_aheads);
836 while (true) {
837 /* reset packets queues */
838 INIT_HTC_PACKET_QUEUE(&recv_q);
839 INIT_HTC_PACKET_QUEUE(&sync_comp_q);
840 if (num_look_aheads > HTC_MAX_MSG_PER_BUNDLE_RX) {
841 status = QDF_STATUS_E_PROTO;
842 A_ASSERT(false);
843 break;
844 }
845
846 /* first lookahead sets the expected endpoint IDs for
847 * all packets in a bundle
848 */
849 id = ((HTC_FRAME_HDR *)&look_aheads[0])->EndpointID;
850
851 if (id >= ENDPOINT_MAX) {
852 hif_err("Invalid Endpoint in lookahead: %d", id);
853 status = QDF_STATUS_E_PROTO;
854 break;
855 }
856 /* try to allocate as many HTC RX packets indicated
857 * by the lookaheads these packets are stored
858 * in the recvPkt queue
859 */
860 status = hif_dev_alloc_and_prepare_rx_packets(pdev,
861 look_aheads,
862 num_look_aheads,
863 &recv_q);
864 if (QDF_IS_STATUS_ERROR(status))
865 break;
866 total_fetched += HTC_PACKET_QUEUE_DEPTH(&recv_q);
867
868 /* we've got packet buffers for all we can currently fetch,
869 * this count is not valid anymore
870 */
871 num_look_aheads = 0;
872 partial_bundle = false;
873
874 /* now go fetch the list of HTC packets */
875 while (!HTC_QUEUE_EMPTY(&recv_q)) {
876 pkts_fetched = 0;
877 if ((HTC_PACKET_QUEUE_DEPTH(&recv_q) > 1)) {
878 /* there are enough packets to attempt a bundle
879 * transfer and recv bundling is allowed
880 */
881 status = ISSUE_BUNDLE(pdev,
882 &recv_q,
883 asyncProc ? NULL :
884 &sync_comp_q,
885 mail_box_index,
886 &pkts_fetched,
887 partial_bundle);
888 if (QDF_IS_STATUS_ERROR(status)) {
889 hif_dev_free_recv_pkt_queue(
890 &recv_q);
891 break;
892 }
893
894 if (HTC_PACKET_QUEUE_DEPTH(&recv_q) !=
895 0) {
896 /* we couldn't fetch all packets at one,
897 * time this creates a broken
898 * bundle
899 */
900 partial_bundle = true;
901 }
902 }
903
904 /* see if the previous operation fetched any
905 * packets using bundling
906 */
907 if (pkts_fetched == 0) {
908 /* dequeue one packet */
909 pkt = htc_packet_dequeue(&recv_q);
910 A_ASSERT(pkt);
911 if (!pkt)
912 break;
913
914 pkt->Completion = NULL;
915
916 if (HTC_PACKET_QUEUE_DEPTH(&recv_q) >
917 0) {
918 /* lookaheads in all packets except the
919 * last one in must be ignored
920 */
921 pkt->PktInfo.AsRx.HTCRxFlags |=
922 HTC_RX_PKT_IGNORE_LOOKAHEAD;
923 }
924
925 /* go fetch the packet */
926 status =
927 hif_dev_recv_packet(pdev, pkt,
928 pkt->ActualLength,
929 mail_box_index);
930 while (QDF_IS_STATUS_ERROR(status) &&
931 !HTC_QUEUE_EMPTY(&recv_q)) {
932 qdf_nbuf_t nbuf;
933
934 pkt = htc_packet_dequeue(&recv_q);
935 if (!pkt)
936 break;
937 nbuf = pkt->pNetBufContext;
938 if (nbuf)
939 qdf_nbuf_free(nbuf);
940 }
941
942 if (QDF_IS_STATUS_ERROR(status))
943 break;
944 /* sent synchronously, queue this packet for
945 * synchronous completion
946 */
947 HTC_PACKET_ENQUEUE(&sync_comp_q, pkt);
948 }
949 }
950
951 /* synchronous handling */
952 if (pdev->DSRCanYield) {
953 /* for the SYNC case, increment count that tracks
954 * when the DSR should yield
955 */
956 pdev->CurrentDSRRecvCount++;
957 }
958
959 /* in the sync case, all packet buffers are now filled,
960 * we can process each packet, check lookahead , then repeat
961 */
962 rxCompletion = pdev->hif_callbacks.rxCompletionHandler;
963
964 /* unload sync completion queue */
965 while (!HTC_QUEUE_EMPTY(&sync_comp_q)) {
966 uint8_t pipeid;
967 qdf_nbuf_t netbuf;
968
969 pkt = htc_packet_dequeue(&sync_comp_q);
970 A_ASSERT(pkt);
971 if (!pkt)
972 break;
973
974 num_look_aheads = 0;
975 status = hif_dev_process_recv_header(pdev, pkt,
976 look_aheads,
977 &num_look_aheads);
978 if (QDF_IS_STATUS_ERROR(status)) {
979 HTC_PACKET_ENQUEUE_TO_HEAD(&sync_comp_q, pkt);
980 break;
981 }
982
983 netbuf = (qdf_nbuf_t)pkt->pNetBufContext;
984 /* set data length */
985 qdf_nbuf_put_tail(netbuf, pkt->ActualLength);
986
987 if (rxCompletion) {
988 pipeid =
989 hif_dev_map_mail_box_to_pipe(pdev,
990 mail_box_index,
991 true);
992 rxCompletion(pdev->hif_callbacks.Context,
993 netbuf, pipeid);
994 }
995 }
996
997 if (QDF_IS_STATUS_ERROR(status)) {
998 if (!HTC_QUEUE_EMPTY(&sync_comp_q))
999 hif_dev_free_recv_pkt_queue(
1000 &sync_comp_q);
1001 break;
1002 }
1003
1004 if (num_look_aheads == 0) {
1005 /* no more look aheads */
1006 break;
1007 }
1008 /* check whether other OS contexts have queued any WMI
1009 * command/data for WLAN. This check is needed only if WLAN
1010 * Tx and Rx happens in same thread context
1011 */
1012 /* A_CHECK_DRV_TX(); */
1013 }
1014 if (num_pkts_fetched)
1015 *num_pkts_fetched = total_fetched;
1016
1017 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvMessagePendingHandler\n"));
1018 return status;
1019 }
1020
1021 /**
1022 * hif_dev_service_cpu_interrupt() - service fatal interrupts
1023 * synchronously
1024 *
1025 * @pdev: hif sdio device context
1026 *
1027 * Return: QDF_STATUS_SUCCESS for success
1028 */
hif_dev_service_cpu_interrupt(struct hif_sdio_device * pdev)1029 static QDF_STATUS hif_dev_service_cpu_interrupt(struct hif_sdio_device *pdev)
1030 {
1031 QDF_STATUS status;
1032 uint8_t reg_buffer[4];
1033 uint8_t cpu_int_status;
1034
1035 cpu_int_status = mboxProcRegs(pdev).cpu_int_status &
1036 mboxEnaRegs(pdev).cpu_int_status_enable;
1037
1038 hif_err("CPU intr status: 0x%x", (uint32_t)cpu_int_status);
1039
1040 /* Clear the interrupt */
1041 mboxProcRegs(pdev).cpu_int_status &= ~cpu_int_status;
1042
1043 /*set up the register transfer buffer to hit the register
1044 * 4 times , this is done to make the access 4-byte aligned
1045 * to mitigate issues with host bus interconnects that
1046 * restrict bus transfer lengths to be a multiple of 4-bytes
1047 * set W1C value to clear the interrupt, this hits the register
1048 * first
1049 */
1050 reg_buffer[0] = cpu_int_status;
1051 /* the remaining 4 values are set to zero which have no-effect */
1052 reg_buffer[1] = 0;
1053 reg_buffer[2] = 0;
1054 reg_buffer[3] = 0;
1055
1056 status = hif_read_write(pdev->HIFDevice,
1057 CPU_INT_STATUS_ADDRESS,
1058 reg_buffer, 4, HIF_WR_SYNC_BYTE_FIX, NULL);
1059
1060 A_ASSERT(status == QDF_STATUS_SUCCESS);
1061
1062 /* The Interrupt sent to the Host is generated via bit0
1063 * of CPU INT register
1064 */
1065 if (cpu_int_status & 0x1) {
1066 if (pdev->hif_callbacks.fwEventHandler)
1067 /* It calls into HTC which propagates this
1068 * to ol_target_failure()
1069 */
1070 pdev->hif_callbacks.fwEventHandler(
1071 pdev->hif_callbacks.Context,
1072 QDF_STATUS_E_FAILURE);
1073 } else {
1074 hif_err("Unrecognized CPU event");
1075 }
1076
1077 return status;
1078 }
1079
1080 /**
1081 * hif_dev_service_error_interrupt() - service error interrupts
1082 * synchronously
1083 *
1084 * @pdev: hif sdio device context
1085 *
1086 * Return: QDF_STATUS_SUCCESS for success
1087 */
hif_dev_service_error_interrupt(struct hif_sdio_device * pdev)1088 static QDF_STATUS hif_dev_service_error_interrupt(struct hif_sdio_device *pdev)
1089 {
1090 QDF_STATUS status;
1091 uint8_t reg_buffer[4];
1092 uint8_t error_int_status = 0;
1093
1094 error_int_status = mboxProcRegs(pdev).error_int_status & 0x0F;
1095 hif_err("Err intr status: 0x%x", error_int_status);
1096
1097 if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status))
1098 hif_err("Error : Wakeup");
1099
1100 if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status))
1101 hif_err("Error : Rx Underflow");
1102
1103 if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status))
1104 hif_err("Error : Tx Overflow");
1105
1106 /* Clear the interrupt */
1107 mboxProcRegs(pdev).error_int_status &= ~error_int_status;
1108
1109 /* set up the register transfer buffer to hit the register
1110 * 4 times , this is done to make the access 4-byte
1111 * aligned to mitigate issues with host bus interconnects that
1112 * restrict bus transfer lengths to be a multiple of 4-bytes
1113 */
1114
1115 /* set W1C value to clear the interrupt */
1116 reg_buffer[0] = error_int_status;
1117 /* the remaining 4 values are set to zero which have no-effect */
1118 reg_buffer[1] = 0;
1119 reg_buffer[2] = 0;
1120 reg_buffer[3] = 0;
1121
1122 status = hif_read_write(pdev->HIFDevice,
1123 ERROR_INT_STATUS_ADDRESS,
1124 reg_buffer, 4, HIF_WR_SYNC_BYTE_FIX, NULL);
1125
1126 A_ASSERT(status == QDF_STATUS_SUCCESS);
1127 return status;
1128 }
1129
1130 /**
1131 * hif_dev_service_debug_interrupt() - service debug interrupts
1132 * synchronously
1133 *
1134 * @pdev: hif sdio device context
1135 *
1136 * Return: QDF_STATUS_SUCCESS for success
1137 */
hif_dev_service_debug_interrupt(struct hif_sdio_device * pdev)1138 static QDF_STATUS hif_dev_service_debug_interrupt(struct hif_sdio_device *pdev)
1139 {
1140 uint32_t dummy;
1141 QDF_STATUS status;
1142
1143 /* Send a target failure event to the application */
1144 hif_err("Target debug interrupt");
1145
1146 /* clear the interrupt , the debug error interrupt is counter 0
1147 * read counter to clear interrupt
1148 */
1149 status = hif_read_write(pdev->HIFDevice,
1150 COUNT_DEC_ADDRESS,
1151 (uint8_t *)&dummy,
1152 4, HIF_RD_SYNC_BYTE_INC, NULL);
1153
1154 A_ASSERT(status == QDF_STATUS_SUCCESS);
1155 return status;
1156 }
1157
1158 /**
1159 * hif_dev_service_counter_interrupt() - service counter interrupts
1160 * synchronously
1161 * @pdev: hif sdio device context
1162 *
1163 * Return: QDF_STATUS_SUCCESS for success
1164 */
1165 static
hif_dev_service_counter_interrupt(struct hif_sdio_device * pdev)1166 QDF_STATUS hif_dev_service_counter_interrupt(struct hif_sdio_device *pdev)
1167 {
1168 uint8_t counter_int_status;
1169
1170 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n"));
1171
1172 counter_int_status = mboxProcRegs(pdev).counter_int_status &
1173 mboxEnaRegs(pdev).counter_int_status_enable;
1174
1175 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
1176 ("Valid interrupt source in COUNTER_INT_STATUS: 0x%x\n",
1177 counter_int_status));
1178
1179 /* Check if the debug interrupt is pending
1180 * NOTE: other modules like GMBOX may use the counter interrupt
1181 * for credit flow control on other counters, we only need to
1182 * check for the debug assertion counter interrupt
1183 */
1184 if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK)
1185 return hif_dev_service_debug_interrupt(pdev);
1186
1187 return QDF_STATUS_SUCCESS;
1188 }
1189
1190 #define RX_LOOAHEAD_GET(pdev, i) \
1191 mboxProcRegs(pdev).rx_lookahead[MAILBOX_LOOKAHEAD_SIZE_IN_WORD * i]
1192 /**
1193 * hif_dev_process_pending_irqs() - process pending interrupts
1194 * @pdev: hif sdio device context
1195 * @done: pending irq completion status
1196 * @async_processing: sync/async processing flag
1197 *
1198 * Return: QDF_STATUS_SUCCESS for success
1199 */
hif_dev_process_pending_irqs(struct hif_sdio_device * pdev,bool * done,bool * async_processing)1200 QDF_STATUS hif_dev_process_pending_irqs(struct hif_sdio_device *pdev,
1201 bool *done,
1202 bool *async_processing)
1203 {
1204 QDF_STATUS status = QDF_STATUS_SUCCESS;
1205 uint8_t host_int_status = 0;
1206 uint32_t l_ahead[MAILBOX_USED_COUNT];
1207 int i;
1208
1209 qdf_mem_zero(&l_ahead, sizeof(l_ahead));
1210 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
1211 ("+ProcessPendingIRQs: (dev: 0x%lX)\n",
1212 (unsigned long)pdev));
1213
1214 /* NOTE: the HIF implementation guarantees that the context
1215 * of this call allows us to perform SYNCHRONOUS I/O,
1216 * that is we can block, sleep or call any API that
1217 * can block or switch thread/task ontexts.
1218 * This is a fully schedulable context.
1219 */
1220 do {
1221 if (mboxEnaRegs(pdev).int_status_enable == 0) {
1222 /* interrupt enables have been cleared, do not try
1223 * to process any pending interrupts that
1224 * may result in more bus transactions.
1225 * The target may be unresponsive at this point.
1226 */
1227 break;
1228 }
1229 status = hif_read_write(pdev->HIFDevice,
1230 HOST_INT_STATUS_ADDRESS,
1231 (uint8_t *)&mboxProcRegs(pdev),
1232 sizeof(mboxProcRegs(pdev)),
1233 HIF_RD_SYNC_BYTE_INC, NULL);
1234
1235 if (QDF_IS_STATUS_ERROR(status))
1236 break;
1237
1238 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
1239 hif_dev_dump_registers(pdev,
1240 &mboxProcRegs(pdev),
1241 &mboxEnaRegs(pdev),
1242 &mboxCountRegs(pdev));
1243 }
1244
1245 /* Update only those registers that are enabled */
1246 host_int_status = mboxProcRegs(pdev).host_int_status
1247 & mboxEnaRegs(pdev).int_status_enable;
1248
1249 /* only look at mailbox status if the HIF layer did not
1250 * provide this function, on some HIF interfaces reading
1251 * the RX lookahead is not valid to do
1252 */
1253 for (i = 0; i < MAILBOX_USED_COUNT; i++) {
1254 l_ahead[i] = 0;
1255 if (host_int_status & (1 << i)) {
1256 /* mask out pending mailbox value, we use
1257 * "lookAhead" as the real flag for
1258 * mailbox processing below
1259 */
1260 host_int_status &= ~(1 << i);
1261 if (mboxProcRegs(pdev).
1262 rx_lookahead_valid & (1 << i)) {
1263 /* mailbox has a message and the
1264 * look ahead is valid
1265 */
1266 l_ahead[i] = RX_LOOAHEAD_GET(pdev, i);
1267 }
1268 }
1269 } /*end of for loop */
1270 } while (false);
1271
1272 do {
1273 bool bLookAheadValid = false;
1274 /* did the interrupt status fetches succeed? */
1275 if (QDF_IS_STATUS_ERROR(status))
1276 break;
1277
1278 for (i = 0; i < MAILBOX_USED_COUNT; i++) {
1279 if (l_ahead[i] != 0) {
1280 bLookAheadValid = true;
1281 break;
1282 }
1283 }
1284
1285 if ((host_int_status == 0) && !bLookAheadValid) {
1286 /* nothing to process, the caller can use this
1287 * to break out of a loop
1288 */
1289 *done = true;
1290 break;
1291 }
1292
1293 if (bLookAheadValid) {
1294 for (i = 0; i < MAILBOX_USED_COUNT; i++) {
1295 int fetched = 0;
1296
1297 if (l_ahead[i] == 0)
1298 continue;
1299 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
1300 ("mbox[%d],lookahead:0x%X\n",
1301 i, l_ahead[i]));
1302 /* Mailbox Interrupt, the HTC layer may issue
1303 * async requests to empty the mailbox...
1304 * When emptying the recv mailbox we use the
1305 * async handler from the completion routine of
1306 * routine of the callers read request.
1307 * This can improve performance by reducing
1308 * the context switching when we rapidly
1309 * pull packets
1310 */
1311 status = hif_dev_recv_message_pending_handler(
1312 pdev, i,
1313 &l_ahead
1314 [i], 1,
1315 async_processing,
1316 &fetched);
1317 if (QDF_IS_STATUS_ERROR(status))
1318 break;
1319
1320 if (!fetched) {
1321 /* HTC could not pull any messages out
1322 * due to lack of resources force DSR
1323 * handle to ack the interrupt
1324 */
1325 *async_processing = false;
1326 pdev->RecheckIRQStatusCnt = 0;
1327 }
1328 }
1329 }
1330
1331 /* now handle the rest of them */
1332 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
1333 ("Valid source for OTHER interrupts: 0x%x\n",
1334 host_int_status));
1335
1336 if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
1337 /* CPU Interrupt */
1338 status = hif_dev_service_cpu_interrupt(pdev);
1339 if (QDF_IS_STATUS_ERROR(status))
1340 break;
1341 }
1342
1343 if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
1344 /* Error Interrupt */
1345 status = hif_dev_service_error_interrupt(pdev);
1346 if (QDF_IS_STATUS_ERROR(status))
1347 break;
1348 }
1349
1350 if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
1351 /* Counter Interrupt */
1352 status = hif_dev_service_counter_interrupt(pdev);
1353 if (QDF_IS_STATUS_ERROR(status))
1354 break;
1355 }
1356
1357 } while (false);
1358
1359 /* an optimization to bypass reading the IRQ status registers
1360 * unnecessarily which can re-wake the target, if upper layers
1361 * determine that we are in a low-throughput mode, we can
1362 * rely on taking another interrupt rather than re-checking
1363 * the status registers which can re-wake the target.
1364 *
1365 * NOTE : for host interfaces that use the special
1366 * GetPendingEventsFunc, this optimization cannot be used due to
1367 * possible side-effects. For example, SPI requires the host
1368 * to drain all messages from the mailbox before exiting
1369 * the ISR routine.
1370 */
1371 if (!(*async_processing) && (pdev->RecheckIRQStatusCnt == 0)) {
1372 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
1373 ("Bypass IRQ Status re-check, forcing done\n"));
1374 *done = true;
1375 }
1376
1377 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
1378 ("-ProcessPendingIRQs: (done:%d, async:%d) status=%d\n",
1379 *done, *async_processing, status));
1380
1381 return status;
1382 }
1383
1384 #define DEV_CHECK_RECV_YIELD(pdev) \
1385 ((pdev)->CurrentDSRRecvCount >= \
1386 (pdev)->HifIRQYieldParams.recv_packet_yield_count)
1387 /**
1388 * hif_dev_dsr_handler() - Synchronous interrupt handler
1389 *
1390 * @context: hif send context
1391 *
1392 * Return: 0 for success and non-zero for failure
1393 */
hif_dev_dsr_handler(void * context)1394 QDF_STATUS hif_dev_dsr_handler(void *context)
1395 {
1396 struct hif_sdio_device *pdev = (struct hif_sdio_device *)context;
1397 QDF_STATUS status = QDF_STATUS_SUCCESS;
1398 bool done = false;
1399 bool async_proc = false;
1400
1401 /* reset the recv counter that tracks when we need
1402 * to yield from the DSR
1403 */
1404 pdev->CurrentDSRRecvCount = 0;
1405 /* reset counter used to flag a re-scan of IRQ
1406 * status registers on the target
1407 */
1408 pdev->RecheckIRQStatusCnt = 0;
1409
1410 while (!done) {
1411 status = hif_dev_process_pending_irqs(pdev, &done, &async_proc);
1412 if (QDF_IS_STATUS_ERROR(status))
1413 break;
1414
1415 if (pdev->HifIRQProcessingMode == HIF_DEVICE_IRQ_SYNC_ONLY) {
1416 /* the HIF layer does not allow async IRQ processing,
1417 * override the asyncProc flag
1418 */
1419 async_proc = false;
1420 /* this will cause us to re-enter ProcessPendingIRQ()
1421 * and re-read interrupt status registers.
1422 * This has a nice side effect of blocking us until all
1423 * async read requests are completed. This behavior is
1424 * required as we do not allow ASYNC processing
1425 * in interrupt handlers (like Windows CE)
1426 */
1427
1428 if (pdev->DSRCanYield && DEV_CHECK_RECV_YIELD(pdev))
1429 /* ProcessPendingIRQs() pulled enough recv
1430 * messages to satisfy the yield count, stop
1431 * checking for more messages and return
1432 */
1433 break;
1434 }
1435
1436 if (async_proc) {
1437 /* the function does some async I/O for performance,
1438 * we need to exit the ISR immediately, the check below
1439 * will prevent the interrupt from being
1440 * Ack'd while we handle it asynchronously
1441 */
1442 break;
1443 }
1444 }
1445
1446 if (QDF_IS_STATUS_SUCCESS(status) && !async_proc) {
1447 /* Ack the interrupt only if :
1448 * 1. we did not get any errors in processing interrupts
1449 * 2. there are no outstanding async processing requests
1450 */
1451 if (pdev->DSRCanYield) {
1452 /* if the DSR can yield do not ACK the interrupt, there
1453 * could be more pending messages. The HIF layer
1454 * must ACK the interrupt on behalf of HTC
1455 */
1456 hif_info("Yield (RX count: %d)",
1457 pdev->CurrentDSRRecvCount);
1458 } else {
1459 hif_ack_interrupt(pdev->HIFDevice);
1460 }
1461 }
1462
1463 return status;
1464 }
1465
1466 /**
1467 * hif_read_write() - queue a read/write request
1468 * @device: pointer to hif device structure
1469 * @address: address to read
1470 * @buffer: buffer to hold read/write data
1471 * @length: length to read/write
1472 * @request: read/write/sync/async request
1473 * @context: pointer to hold calling context
1474 *
1475 * Return: 0 on success, error number otherwise.
1476 */
1477 QDF_STATUS
hif_read_write(struct hif_sdio_dev * device,unsigned long address,char * buffer,uint32_t length,uint32_t request,void * context)1478 hif_read_write(struct hif_sdio_dev *device,
1479 unsigned long address,
1480 char *buffer, uint32_t length,
1481 uint32_t request, void *context)
1482 {
1483 QDF_STATUS status = QDF_STATUS_SUCCESS;
1484 struct bus_request *busrequest;
1485
1486 AR_DEBUG_ASSERT(device);
1487 AR_DEBUG_ASSERT(device->func);
1488 hif_debug("device 0x%pK addr 0x%lX buffer 0x%pK",
1489 device, address, buffer);
1490 hif_debug("len %d req 0x%X context 0x%pK",
1491 length, request, context);
1492
1493 /*sdio r/w action is not needed when suspend, so just return */
1494 if ((device->is_suspend) &&
1495 (device->power_config == HIF_DEVICE_POWER_CUT)) {
1496 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("skip io when suspending\n"));
1497 return QDF_STATUS_SUCCESS;
1498 }
1499 do {
1500 if ((request & HIF_ASYNCHRONOUS) ||
1501 (request & HIF_SYNCHRONOUS)) {
1502 /* serialize all requests through the async thread */
1503 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
1504 ("%s: Execution mode: %s\n", __func__,
1505 (request & HIF_ASYNCHRONOUS) ? "Async"
1506 : "Synch"));
1507 busrequest = hif_allocate_bus_request(device);
1508 if (!busrequest) {
1509 hif_err("bus requests unavail");
1510 hif_err("%s, addr:0x%lX, len:%d",
1511 request & HIF_SDIO_READ ? "READ" :
1512 "WRITE", address, length);
1513 return QDF_STATUS_E_FAILURE;
1514 }
1515 busrequest->address = address;
1516 busrequest->buffer = buffer;
1517 busrequest->length = length;
1518 busrequest->request = request;
1519 busrequest->context = context;
1520
1521 add_to_async_list(device, busrequest);
1522
1523 if (request & HIF_SYNCHRONOUS) {
1524 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
1525 ("%s: queued sync req: 0x%lX\n",
1526 __func__,
1527 (unsigned long)busrequest));
1528
1529 /* wait for completion */
1530 up(&device->sem_async);
1531 if (down_interruptible(&busrequest->sem_req) ==
1532 0) {
1533 QDF_STATUS status = busrequest->status;
1534
1535 hif_debug("sync freeing 0x%lX:0x%X",
1536 (unsigned long)busrequest,
1537 busrequest->status);
1538 hif_debug("freeing req: 0x%X",
1539 (unsigned int)request);
1540 hif_free_bus_request(device,
1541 busrequest);
1542 return status;
1543 } else {
1544 /* interrupted, exit */
1545 return QDF_STATUS_E_FAILURE;
1546 }
1547 } else {
1548 hif_debug("queued async req: 0x%lX",
1549 (unsigned long)busrequest);
1550 up(&device->sem_async);
1551 return QDF_STATUS_E_PENDING;
1552 }
1553 } else {
1554 hif_err("Invalid execution mode: 0x%08x",
1555 (unsigned int)request);
1556 status = QDF_STATUS_E_INVAL;
1557 break;
1558 }
1559 } while (0);
1560
1561 return status;
1562 }
1563
1564 /**
1565 * hif_sdio_func_enable() - Handle device enabling as per device
1566 * @ol_sc: HIF device object
1567 * @func: function pointer
1568 *
1569 * Return QDF_STATUS
1570 */
hif_sdio_func_enable(struct hif_softc * ol_sc,struct sdio_func * func)1571 static QDF_STATUS hif_sdio_func_enable(struct hif_softc *ol_sc,
1572 struct sdio_func *func)
1573 {
1574 struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
1575
1576 if (device->is_disabled) {
1577 int ret = 0;
1578
1579 sdio_claim_host(func);
1580
1581 ret = hif_sdio_quirk_async_intr(ol_sc, func);
1582 if (ret) {
1583 hif_err("Error setting async intr:%d", ret);
1584 sdio_release_host(func);
1585 return QDF_STATUS_E_FAILURE;
1586 }
1587
1588 func->enable_timeout = 100;
1589 ret = sdio_enable_func(func);
1590 if (ret) {
1591 hif_err("Unable to enable function: %d", ret);
1592 sdio_release_host(func);
1593 return QDF_STATUS_E_FAILURE;
1594 }
1595
1596 ret = sdio_set_block_size(func, HIF_BLOCK_SIZE);
1597 if (ret) {
1598 hif_err("Unable to set block size 0x%X : %d",
1599 HIF_BLOCK_SIZE, ret);
1600 sdio_release_host(func);
1601 return QDF_STATUS_E_FAILURE;
1602 }
1603
1604 ret = hif_sdio_quirk_mod_strength(ol_sc, func);
1605 if (ret) {
1606 hif_err("Error setting mod strength : %d", ret);
1607 sdio_release_host(func);
1608 return QDF_STATUS_E_FAILURE;
1609 }
1610
1611 sdio_release_host(func);
1612 }
1613
1614 return QDF_STATUS_SUCCESS;
1615 }
1616
1617 /**
1618 * __hif_read_write() - sdio read/write wrapper
1619 * @device: pointer to hif device structure
1620 * @address: address to read
1621 * @buffer: buffer to hold read/write data
1622 * @length: length to read/write
1623 * @request: read/write/sync/async request
1624 * @context: pointer to hold calling context
1625 *
1626 * Return: 0 on success, error number otherwise.
1627 */
1628 static QDF_STATUS
__hif_read_write(struct hif_sdio_dev * device,uint32_t address,char * buffer,uint32_t length,uint32_t request,void * context)1629 __hif_read_write(struct hif_sdio_dev *device,
1630 uint32_t address, char *buffer,
1631 uint32_t length, uint32_t request, void *context)
1632 {
1633 uint8_t opcode;
1634 QDF_STATUS status = QDF_STATUS_SUCCESS;
1635 int ret = A_OK;
1636 uint8_t *tbuffer;
1637 bool bounced = false;
1638
1639 if (!device) {
1640 hif_err("Device null!");
1641 return QDF_STATUS_E_INVAL;
1642 }
1643
1644 if (!device->func) {
1645 hif_err("func null!");
1646 return QDF_STATUS_E_INVAL;
1647 }
1648
1649 hif_debug("addr:0X%06X, len:%08d, %s, %s",
1650 address, length,
1651 request & HIF_SDIO_READ ? "Read " : "Write",
1652 request & HIF_ASYNCHRONOUS ? "Async" : "Sync ");
1653
1654 do {
1655 if (request & HIF_EXTENDED_IO) {
1656 //HIF_INFO_HI("%s: Command type: CMD53\n", __func__);
1657 } else {
1658 hif_err("Invalid command type: 0x%08x\n", request);
1659 status = QDF_STATUS_E_INVAL;
1660 break;
1661 }
1662
1663 if (request & HIF_BLOCK_BASIS) {
1664 /* round to whole block length size */
1665 length =
1666 (length / HIF_BLOCK_SIZE) *
1667 HIF_BLOCK_SIZE;
1668 hif_debug("Block mode (BlockLen: %d)", length);
1669 } else if (request & HIF_BYTE_BASIS) {
1670 hif_debug("Byte mode (BlockLen: %d)", length);
1671 } else {
1672 hif_err("Invalid data mode: 0x%08x", request);
1673 status = QDF_STATUS_E_INVAL;
1674 break;
1675 }
1676 if (request & HIF_SDIO_WRITE) {
1677 hif_fixup_write_param(device, request,
1678 &length, &address);
1679
1680 hif_debug("addr:%08X, len:0x%08X, dummy:0x%04X",
1681 address, length,
1682 (request & HIF_DUMMY_SPACE_MASK) >> 16);
1683 }
1684
1685 if (request & HIF_FIXED_ADDRESS) {
1686 opcode = CMD53_FIXED_ADDRESS;
1687 hif_debug("Addr mode: fixed 0x%X", address);
1688 } else if (request & HIF_INCREMENTAL_ADDRESS) {
1689 opcode = CMD53_INCR_ADDRESS;
1690 hif_debug("Address mode: Incremental 0x%X", address);
1691 } else {
1692 hif_err("Invalid address mode: 0x%08x", request);
1693 status = QDF_STATUS_E_INVAL;
1694 break;
1695 }
1696
1697 if (request & HIF_SDIO_WRITE) {
1698 #if HIF_USE_DMA_BOUNCE_BUFFER
1699 if (BUFFER_NEEDS_BOUNCE(buffer)) {
1700 AR_DEBUG_ASSERT(device->dma_buffer);
1701 tbuffer = device->dma_buffer;
1702 /* copy the write data to the dma buffer */
1703 AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
1704 if (length > HIF_DMA_BUFFER_SIZE) {
1705 hif_err("Invalid write len: %d",
1706 length);
1707 status = QDF_STATUS_E_INVAL;
1708 break;
1709 }
1710 memcpy(tbuffer, buffer, length);
1711 bounced = true;
1712 } else {
1713 tbuffer = buffer;
1714 }
1715 #else
1716 tbuffer = buffer;
1717 #endif
1718 if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
1719 ret = sdio_writesb(device->func, address,
1720 tbuffer, length);
1721 hif_debug("r=%d addr:0x%X, len:%d, 0x%X",
1722 ret, address, length,
1723 *(int *)tbuffer);
1724 } else if (tbuffer) {
1725 ret = sdio_memcpy_toio(device->func, address,
1726 tbuffer, length);
1727 hif_debug("r=%d addr:0x%X, len:%d, 0x%X",
1728 ret, address, length,
1729 *(int *)tbuffer);
1730 }
1731 } else if (request & HIF_SDIO_READ) {
1732 #if HIF_USE_DMA_BOUNCE_BUFFER
1733 if (BUFFER_NEEDS_BOUNCE(buffer)) {
1734 AR_DEBUG_ASSERT(device->dma_buffer);
1735 AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
1736 if (length > HIF_DMA_BUFFER_SIZE) {
1737 hif_err("Invalid read len: %d", length);
1738 status = QDF_STATUS_E_INVAL;
1739 break;
1740 }
1741 tbuffer = device->dma_buffer;
1742 bounced = true;
1743 } else {
1744 tbuffer = buffer;
1745 }
1746 #else
1747 tbuffer = buffer;
1748 #endif
1749 if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
1750 ret = sdio_readsb(device->func, tbuffer,
1751 address, length);
1752 hif_debug("r=%d addr:0x%X, len:%d, 0x%X",
1753 ret, address, length,
1754 *(int *)tbuffer);
1755 } else if (tbuffer) {
1756 ret = sdio_memcpy_fromio(device->func,
1757 tbuffer, address,
1758 length);
1759 hif_debug("r=%d addr:0x%X, len:%d, 0x%X",
1760 ret, address, length,
1761 *(int *)tbuffer);
1762 }
1763 #if HIF_USE_DMA_BOUNCE_BUFFER
1764 if (bounced && tbuffer)
1765 memcpy(buffer, tbuffer, length);
1766 #endif
1767 } else {
1768 hif_err("Invalid dir: 0x%08x", request);
1769 status = QDF_STATUS_E_INVAL;
1770 return status;
1771 }
1772
1773 if (ret) {
1774 hif_err("SDIO bus operation failed!");
1775 hif_err("MMC stack returned : %d", ret);
1776 hif_err("addr:0X%06X, len:%08d, %s, %s",
1777 address, length,
1778 request & HIF_SDIO_READ ? "Read " : "Write",
1779 request & HIF_ASYNCHRONOUS ?
1780 "Async" : "Sync");
1781 status = QDF_STATUS_E_FAILURE;
1782 }
1783 } while (false);
1784
1785 return status;
1786 }
1787
1788 /**
1789 * async_task() - thread function to serialize all bus requests
1790 * @param: pointer to hif device
1791 *
1792 * thread function to serialize all requests, both sync and async
1793 * Return: 0 on success, error number otherwise.
1794 */
async_task(void * param)1795 static int async_task(void *param)
1796 {
1797 struct hif_sdio_dev *device;
1798 struct bus_request *request;
1799 QDF_STATUS status;
1800 bool claimed = false;
1801
1802 device = (struct hif_sdio_dev *)param;
1803 set_current_state(TASK_INTERRUPTIBLE);
1804 while (!device->async_shutdown) {
1805 /* wait for work */
1806 if (down_interruptible(&device->sem_async) != 0) {
1807 /* interrupted, exit */
1808 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
1809 ("%s: async task interrupted\n",
1810 __func__));
1811 break;
1812 }
1813 if (device->async_shutdown) {
1814 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
1815 ("%s: async task stopping\n",
1816 __func__));
1817 break;
1818 }
1819 /* we want to hold the host over multiple cmds
1820 * if possible, but holding the host blocks
1821 * card interrupts
1822 */
1823 qdf_spin_lock_irqsave(&device->asynclock);
1824 /* pull the request to work on */
1825 while (device->asyncreq) {
1826 request = device->asyncreq;
1827 if (request->inusenext)
1828 device->asyncreq = request->inusenext;
1829 else
1830 device->asyncreq = NULL;
1831 qdf_spin_unlock_irqrestore(&device->asynclock);
1832 hif_debug("processing req: 0x%lX",
1833 (unsigned long)request);
1834
1835 if (!claimed) {
1836 sdio_claim_host(device->func);
1837 claimed = true;
1838 }
1839 if (request->scatter_req) {
1840 A_ASSERT(device->scatter_enabled);
1841 /* pass the request to scatter routine which
1842 * executes it synchronously, note, no need
1843 * to free the request since scatter requests
1844 * are maintained on a separate list
1845 */
1846 status = do_hif_read_write_scatter(device,
1847 request);
1848 } else {
1849 /* call hif_read_write in sync mode */
1850 status =
1851 __hif_read_write(device,
1852 request->address,
1853 request->buffer,
1854 request->length,
1855 request->
1856 request &
1857 ~HIF_SYNCHRONOUS,
1858 NULL);
1859 if (request->request & HIF_ASYNCHRONOUS) {
1860 void *context = request->context;
1861
1862 hif_free_bus_request(device, request);
1863 device->htc_callbacks.
1864 rw_compl_handler(context, status);
1865 } else {
1866 hif_debug("upping req: 0x%lX",
1867 (unsigned long)request);
1868 request->status = status;
1869 up(&request->sem_req);
1870 }
1871 }
1872 qdf_spin_lock_irqsave(&device->asynclock);
1873 }
1874 qdf_spin_unlock_irqrestore(&device->asynclock);
1875 if (claimed) {
1876 sdio_release_host(device->func);
1877 claimed = false;
1878 }
1879 }
1880
1881 kthread_complete_and_exit(&device->async_completion, 0);
1882
1883 return 0;
1884 }
1885
1886 /**
1887 * hif_disable_func() - Disable SDIO function
1888 *
1889 * @device: HIF device pointer
1890 * @func: SDIO function pointer
1891 * @reset: If this is called from resume or probe
1892 *
1893 * Return: 0 in case of success, else error value
1894 */
hif_disable_func(struct hif_sdio_dev * device,struct sdio_func * func,bool reset)1895 QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
1896 struct sdio_func *func,
1897 bool reset)
1898 {
1899 QDF_STATUS status = QDF_STATUS_SUCCESS;
1900
1901 HIF_ENTER();
1902 if (!IS_ERR(device->async_task)) {
1903 init_completion(&device->async_completion);
1904 device->async_shutdown = 1;
1905 up(&device->sem_async);
1906 wait_for_completion(&device->async_completion);
1907 device->async_task = NULL;
1908 sema_init(&device->sem_async, 0);
1909 }
1910
1911 status = hif_sdio_func_disable(device, func, reset);
1912 if (status == QDF_STATUS_SUCCESS)
1913 device->is_disabled = true;
1914
1915 cleanup_hif_scatter_resources(device);
1916
1917 HIF_EXIT();
1918
1919 return status;
1920 }
1921
1922 /**
1923 * hif_enable_func() - Enable SDIO function
1924 *
1925 * @ol_sc: HIF object pointer
1926 * @device: HIF device pointer
1927 * @func: SDIO function pointer
1928 * @resume: If this is called from resume or probe
1929 *
1930 * Return: 0 in case of success, else error value
1931 */
hif_enable_func(struct hif_softc * ol_sc,struct hif_sdio_dev * device,struct sdio_func * func,bool resume)1932 QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
1933 struct sdio_func *func, bool resume)
1934 {
1935 QDF_STATUS ret = QDF_STATUS_SUCCESS;
1936
1937 HIF_ENTER();
1938
1939 if (!device) {
1940 hif_err("HIF device is NULL");
1941 return QDF_STATUS_E_INVAL;
1942 }
1943
1944 if (hif_sdio_func_enable(ol_sc, func))
1945 return QDF_STATUS_E_FAILURE;
1946
1947 /* create async I/O thread */
1948 if (!device->async_task && device->is_disabled) {
1949 device->async_shutdown = 0;
1950 device->async_task = kthread_create(async_task,
1951 (void *)device,
1952 "AR6K Async");
1953 if (IS_ERR(device->async_task)) {
1954 hif_err("Error creating async task");
1955 return QDF_STATUS_E_FAILURE;
1956 }
1957 device->is_disabled = false;
1958 wake_up_process(device->async_task);
1959 }
1960
1961 if (!resume)
1962 ret = hif_sdio_probe(ol_sc, func, device);
1963
1964 HIF_EXIT();
1965
1966 return ret;
1967 }
1968 #endif /* CONFIG_SDIO_TRANSFER_MAILBOX */
1969