PageRenderTime 1106ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/ath6kl/htc2/AR6000/ar6k_events.c

https://github.com/Mengqi/linux-2.6
C | 783 lines | 471 code | 141 blank | 171 comment | 105 complexity | 36b64b5f2a213895c7ebe4b05e274b85 MD5 | raw file
  1. //------------------------------------------------------------------------------
  2. // <copyright file="ar6k_events.c" company="Atheros">
  3. // Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
  4. //
  5. //
  6. // Permission to use, copy, modify, and/or distribute this software for any
  7. // purpose with or without fee is hereby granted, provided that the above
  8. // copyright notice and this permission notice appear in all copies.
  9. //
  10. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. //
  18. //
  19. //------------------------------------------------------------------------------
  20. //==============================================================================
  21. // AR6K Driver layer event handling (i.e. interrupts, message polling)
  22. //
  23. // Author(s): ="Atheros"
  24. //==============================================================================
  25. #include "a_config.h"
  26. #include "athdefs.h"
  27. #include "hw/mbox_host_reg.h"
  28. #include "a_osapi.h"
  29. #include "../htc_debug.h"
  30. #include "hif.h"
  31. #include "htc_packet.h"
  32. #include "ar6k.h"
  33. extern void AR6KFreeIOPacket(struct ar6k_device *pDev, struct htc_packet *pPacket);
  34. extern struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev);
  35. static int DevServiceDebugInterrupt(struct ar6k_device *pDev);
  36. #define DELAY_PER_INTERVAL_MS 10 /* 10 MS delay per polling interval */
  37. /* completion routine for ALL HIF layer async I/O */
  38. int DevRWCompletionHandler(void *context, int status)
  39. {
  40. struct htc_packet *pPacket = (struct htc_packet *)context;
  41. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
  42. ("+DevRWCompletionHandler (Pkt:0x%lX) , Status: %d \n",
  43. (unsigned long)pPacket,
  44. status));
  45. COMPLETE_HTC_PACKET(pPacket,status);
  46. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
  47. ("-DevRWCompletionHandler\n"));
  48. return 0;
  49. }
  50. /* mailbox recv message polling */
  51. int DevPollMboxMsgRecv(struct ar6k_device *pDev,
  52. u32 *pLookAhead,
  53. int TimeoutMS)
  54. {
  55. int status = 0;
  56. int timeout = TimeoutMS/DELAY_PER_INTERVAL_MS;
  57. A_ASSERT(timeout > 0);
  58. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+DevPollMboxMsgRecv \n"));
  59. while (true) {
  60. if (pDev->GetPendingEventsFunc != NULL) {
  61. struct hif_pending_events_info events;
  62. #ifdef THREAD_X
  63. events.Polling =1;
  64. #endif
  65. /* the HIF layer uses a special mechanism to get events, do this
  66. * synchronously */
  67. status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
  68. &events,
  69. NULL);
  70. if (status)
  71. {
  72. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get pending events \n"));
  73. break;
  74. }
  75. if (events.Events & HIF_RECV_MSG_AVAIL)
  76. {
  77. /* there is a message available, the lookahead should be valid now */
  78. *pLookAhead = events.LookAhead;
  79. break;
  80. }
  81. } else {
  82. /* this is the standard HIF way.... */
  83. /* load the register table */
  84. status = HIFReadWrite(pDev->HIFDevice,
  85. HOST_INT_STATUS_ADDRESS,
  86. (u8 *)&pDev->IrqProcRegisters,
  87. AR6K_IRQ_PROC_REGS_SIZE,
  88. HIF_RD_SYNC_BYTE_INC,
  89. NULL);
  90. if (status){
  91. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to read register table \n"));
  92. break;
  93. }
  94. /* check for MBOX data and valid lookahead */
  95. if (pDev->IrqProcRegisters.host_int_status & (1 << HTC_MAILBOX)) {
  96. if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX))
  97. {
  98. /* mailbox has a message and the look ahead is valid */
  99. *pLookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
  100. break;
  101. }
  102. }
  103. }
  104. timeout--;
  105. if (timeout <= 0) {
  106. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Timeout waiting for recv message \n"));
  107. status = A_ERROR;
  108. /* check if the target asserted */
  109. if ( pDev->IrqProcRegisters.counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
  110. /* target signaled an assert, process this pending interrupt
  111. * this will call the target failure handler */
  112. DevServiceDebugInterrupt(pDev);
  113. }
  114. break;
  115. }
  116. /* delay a little */
  117. A_MDELAY(DELAY_PER_INTERVAL_MS);
  118. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Retry Mbox Poll : %d \n",timeout));
  119. }
  120. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-DevPollMboxMsgRecv \n"));
  121. return status;
  122. }
  123. static int DevServiceCPUInterrupt(struct ar6k_device *pDev)
  124. {
  125. int status;
  126. u8 cpu_int_status;
  127. u8 regBuffer[4];
  128. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("CPU Interrupt\n"));
  129. cpu_int_status = pDev->IrqProcRegisters.cpu_int_status &
  130. pDev->IrqEnableRegisters.cpu_int_status_enable;
  131. A_ASSERT(cpu_int_status);
  132. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  133. ("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
  134. cpu_int_status));
  135. /* Clear the interrupt */
  136. pDev->IrqProcRegisters.cpu_int_status &= ~cpu_int_status; /* W1C */
  137. /* set up the register transfer buffer to hit the register 4 times , this is done
  138. * to make the access 4-byte aligned to mitigate issues with host bus interconnects that
  139. * restrict bus transfer lengths to be a multiple of 4-bytes */
  140. /* set W1C value to clear the interrupt, this hits the register first */
  141. regBuffer[0] = cpu_int_status;
  142. /* the remaining 4 values are set to zero which have no-effect */
  143. regBuffer[1] = 0;
  144. regBuffer[2] = 0;
  145. regBuffer[3] = 0;
  146. status = HIFReadWrite(pDev->HIFDevice,
  147. CPU_INT_STATUS_ADDRESS,
  148. regBuffer,
  149. 4,
  150. HIF_WR_SYNC_BYTE_FIX,
  151. NULL);
  152. A_ASSERT(status == 0);
  153. return status;
  154. }
  155. static int DevServiceErrorInterrupt(struct ar6k_device *pDev)
  156. {
  157. int status;
  158. u8 error_int_status;
  159. u8 regBuffer[4];
  160. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error Interrupt\n"));
  161. error_int_status = pDev->IrqProcRegisters.error_int_status & 0x0F;
  162. A_ASSERT(error_int_status);
  163. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  164. ("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
  165. error_int_status));
  166. if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) {
  167. /* Wakeup */
  168. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n"));
  169. }
  170. if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) {
  171. /* Rx Underflow */
  172. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n"));
  173. }
  174. if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) {
  175. /* Tx Overflow */
  176. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n"));
  177. }
  178. /* Clear the interrupt */
  179. pDev->IrqProcRegisters.error_int_status &= ~error_int_status; /* W1C */
  180. /* set up the register transfer buffer to hit the register 4 times , this is done
  181. * to make the access 4-byte aligned to mitigate issues with host bus interconnects that
  182. * restrict bus transfer lengths to be a multiple of 4-bytes */
  183. /* set W1C value to clear the interrupt, this hits the register first */
  184. regBuffer[0] = error_int_status;
  185. /* the remaining 4 values are set to zero which have no-effect */
  186. regBuffer[1] = 0;
  187. regBuffer[2] = 0;
  188. regBuffer[3] = 0;
  189. status = HIFReadWrite(pDev->HIFDevice,
  190. ERROR_INT_STATUS_ADDRESS,
  191. regBuffer,
  192. 4,
  193. HIF_WR_SYNC_BYTE_FIX,
  194. NULL);
  195. A_ASSERT(status == 0);
  196. return status;
  197. }
  198. static int DevServiceDebugInterrupt(struct ar6k_device *pDev)
  199. {
  200. u32 dummy;
  201. int status;
  202. /* Send a target failure event to the application */
  203. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n"));
  204. if (pDev->TargetFailureCallback != NULL) {
  205. pDev->TargetFailureCallback(pDev->HTCContext);
  206. }
  207. if (pDev->GMboxEnabled) {
  208. DevNotifyGMboxTargetFailure(pDev);
  209. }
  210. /* clear the interrupt , the debug error interrupt is
  211. * counter 0 */
  212. /* read counter to clear interrupt */
  213. status = HIFReadWrite(pDev->HIFDevice,
  214. COUNT_DEC_ADDRESS,
  215. (u8 *)&dummy,
  216. 4,
  217. HIF_RD_SYNC_BYTE_INC,
  218. NULL);
  219. A_ASSERT(status == 0);
  220. return status;
  221. }
  222. static int DevServiceCounterInterrupt(struct ar6k_device *pDev)
  223. {
  224. u8 counter_int_status;
  225. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n"));
  226. counter_int_status = pDev->IrqProcRegisters.counter_int_status &
  227. pDev->IrqEnableRegisters.counter_int_status_enable;
  228. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  229. ("Valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
  230. counter_int_status));
  231. /* Check if the debug interrupt is pending
  232. * NOTE: other modules like GMBOX may use the counter interrupt for
  233. * credit flow control on other counters, we only need to check for the debug assertion
  234. * counter interrupt */
  235. if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
  236. return DevServiceDebugInterrupt(pDev);
  237. }
  238. return 0;
  239. }
  240. /* callback when our fetch to get interrupt status registers completes */
  241. static void DevGetEventAsyncHandler(void *Context, struct htc_packet *pPacket)
  242. {
  243. struct ar6k_device *pDev = (struct ar6k_device *)Context;
  244. u32 lookAhead = 0;
  245. bool otherInts = false;
  246. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGetEventAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
  247. do {
  248. if (pPacket->Status) {
  249. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  250. (" GetEvents I/O request failed, status:%d \n", pPacket->Status));
  251. /* bail out, don't unmask HIF interrupt */
  252. break;
  253. }
  254. if (pDev->GetPendingEventsFunc != NULL) {
  255. /* the HIF layer collected the information for us */
  256. struct hif_pending_events_info *pEvents = (struct hif_pending_events_info *)pPacket->pBuffer;
  257. if (pEvents->Events & HIF_RECV_MSG_AVAIL) {
  258. lookAhead = pEvents->LookAhead;
  259. if (0 == lookAhead) {
  260. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler1, lookAhead is zero! \n"));
  261. }
  262. }
  263. if (pEvents->Events & HIF_OTHER_EVENTS) {
  264. otherInts = true;
  265. }
  266. } else {
  267. /* standard interrupt table handling.... */
  268. struct ar6k_irq_proc_registers *pReg = (struct ar6k_irq_proc_registers *)pPacket->pBuffer;
  269. u8 host_int_status;
  270. host_int_status = pReg->host_int_status & pDev->IrqEnableRegisters.int_status_enable;
  271. if (host_int_status & (1 << HTC_MAILBOX)) {
  272. host_int_status &= ~(1 << HTC_MAILBOX);
  273. if (pReg->rx_lookahead_valid & (1 << HTC_MAILBOX)) {
  274. /* mailbox has a message and the look ahead is valid */
  275. lookAhead = pReg->rx_lookahead[HTC_MAILBOX];
  276. if (0 == lookAhead) {
  277. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler2, lookAhead is zero! \n"));
  278. }
  279. }
  280. }
  281. if (host_int_status) {
  282. /* there are other interrupts to handle */
  283. otherInts = true;
  284. }
  285. }
  286. if (otherInts || (lookAhead == 0)) {
  287. /* if there are other interrupts to process, we cannot do this in the async handler so
  288. * ack the interrupt which will cause our sync handler to run again
  289. * if however there are no more messages, we can now ack the interrupt */
  290. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  291. (" Acking interrupt from DevGetEventAsyncHandler (otherints:%d, lookahead:0x%X)\n",
  292. otherInts, lookAhead));
  293. HIFAckInterrupt(pDev->HIFDevice);
  294. } else {
  295. int fetched = 0;
  296. int status;
  297. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  298. (" DevGetEventAsyncHandler : detected another message, lookahead :0x%X \n",
  299. lookAhead));
  300. /* lookahead is non-zero and there are no other interrupts to service,
  301. * go get the next message */
  302. status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, 1, NULL, &fetched);
  303. if (!status && !fetched) {
  304. /* HTC layer could not pull out messages due to lack of resources, stop IRQ processing */
  305. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("MessagePendingCallback did not pull any messages, force-ack \n"));
  306. DevAsyncIrqProcessComplete(pDev);
  307. }
  308. }
  309. } while (false);
  310. /* free this IO packet */
  311. AR6KFreeIOPacket(pDev,pPacket);
  312. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGetEventAsyncHandler \n"));
  313. }
  314. /* called by the HTC layer when it wants us to check if the device has any more pending
  315. * recv messages, this starts off a series of async requests to read interrupt registers */
  316. int DevCheckPendingRecvMsgsAsync(void *context)
  317. {
  318. struct ar6k_device *pDev = (struct ar6k_device *)context;
  319. int status = 0;
  320. struct htc_packet *pIOPacket;
  321. /* this is called in an ASYNC only context, we may NOT block, sleep or call any apis that can
  322. * cause us to switch contexts */
  323. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevCheckPendingRecvMsgsAsync: (dev: 0x%lX)\n", (unsigned long)pDev));
  324. do {
  325. if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
  326. /* break the async processing chain right here, no need to continue.
  327. * The DevDsrHandler() will handle things in a loop when things are driven
  328. * synchronously */
  329. break;
  330. }
  331. /* an optimization to bypass reading the IRQ status registers unecessarily which can re-wake
  332. * the target, if upper layers determine that we are in a low-throughput mode, we can
  333. * rely on taking another interrupt rather than re-checking the status registers which can
  334. * re-wake the target */
  335. if (pDev->RecheckIRQStatusCnt == 0) {
  336. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Bypassing IRQ Status re-check, re-acking HIF interrupts\n"));
  337. /* ack interrupt */
  338. HIFAckInterrupt(pDev->HIFDevice);
  339. break;
  340. }
  341. /* first allocate one of our HTC packets we created for async I/O
  342. * we reuse HTC packet definitions so that we can use the completion mechanism
  343. * in DevRWCompletionHandler() */
  344. pIOPacket = AR6KAllocIOPacket(pDev);
  345. if (NULL == pIOPacket) {
  346. /* there should be only 1 asynchronous request out at a time to read these registers
  347. * so this should actually never happen */
  348. status = A_NO_MEMORY;
  349. A_ASSERT(false);
  350. break;
  351. }
  352. /* stick in our completion routine when the I/O operation completes */
  353. pIOPacket->Completion = DevGetEventAsyncHandler;
  354. pIOPacket->pContext = pDev;
  355. if (pDev->GetPendingEventsFunc) {
  356. /* HIF layer has it's own mechanism, pass the IO to it.. */
  357. status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
  358. (struct hif_pending_events_info *)pIOPacket->pBuffer,
  359. pIOPacket);
  360. } else {
  361. /* standard way, read the interrupt register table asynchronously again */
  362. status = HIFReadWrite(pDev->HIFDevice,
  363. HOST_INT_STATUS_ADDRESS,
  364. pIOPacket->pBuffer,
  365. AR6K_IRQ_PROC_REGS_SIZE,
  366. HIF_RD_ASYNC_BYTE_INC,
  367. pIOPacket);
  368. }
  369. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Async IO issued to get interrupt status...\n"));
  370. } while (false);
  371. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevCheckPendingRecvMsgsAsync \n"));
  372. return status;
  373. }
  374. void DevAsyncIrqProcessComplete(struct ar6k_device *pDev)
  375. {
  376. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("DevAsyncIrqProcessComplete - forcing HIF IRQ ACK \n"));
  377. HIFAckInterrupt(pDev->HIFDevice);
  378. }
  379. /* process pending interrupts synchronously */
  380. static int ProcessPendingIRQs(struct ar6k_device *pDev, bool *pDone, bool *pASyncProcessing)
  381. {
  382. int status = 0;
  383. u8 host_int_status = 0;
  384. u32 lookAhead = 0;
  385. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%lX)\n", (unsigned long)pDev));
  386. /*** NOTE: the HIF implementation guarantees that the context of this call allows
  387. * us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
  388. * can block or switch thread/task ontexts.
  389. * This is a fully schedulable context.
  390. * */
  391. do {
  392. if (pDev->IrqEnableRegisters.int_status_enable == 0) {
  393. /* interrupt enables have been cleared, do not try to process any pending interrupts that
  394. * may result in more bus transactions. The target may be unresponsive at this
  395. * point. */
  396. break;
  397. }
  398. if (pDev->GetPendingEventsFunc != NULL) {
  399. struct hif_pending_events_info events;
  400. #ifdef THREAD_X
  401. events.Polling= 0;
  402. #endif
  403. /* the HIF layer uses a special mechanism to get events
  404. * get this synchronously */
  405. status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
  406. &events,
  407. NULL);
  408. if (status) {
  409. break;
  410. }
  411. if (events.Events & HIF_RECV_MSG_AVAIL) {
  412. lookAhead = events.LookAhead;
  413. if (0 == lookAhead) {
  414. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
  415. }
  416. }
  417. if (!(events.Events & HIF_OTHER_EVENTS) ||
  418. !(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
  419. /* no need to read the register table, no other interesting interrupts.
  420. * Some interfaces (like SPI) can shadow interrupt sources without
  421. * requiring the host to do a full table read */
  422. break;
  423. }
  424. /* otherwise fall through and read the register table */
  425. }
  426. /*
  427. * Read the first 28 bytes of the HTC register table. This will yield us
  428. * the value of different int status registers and the lookahead
  429. * registers.
  430. * length = sizeof(int_status) + sizeof(cpu_int_status) +
  431. * sizeof(error_int_status) + sizeof(counter_int_status) +
  432. * sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
  433. * sizeof(hole) + sizeof(rx_lookahead) +
  434. * sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
  435. * sizeof(error_status_enable) +
  436. * sizeof(counter_int_status_enable);
  437. *
  438. */
  439. #ifdef CONFIG_MMC_SDHCI_S3C
  440. pDev->IrqProcRegisters.host_int_status = 0;
  441. pDev->IrqProcRegisters.rx_lookahead_valid = 0;
  442. pDev->IrqProcRegisters.host_int_status2 = 0;
  443. pDev->IrqProcRegisters.rx_lookahead[0] = 0;
  444. pDev->IrqProcRegisters.rx_lookahead[1] = 0xaaa5555;
  445. #endif /* CONFIG_MMC_SDHCI_S3C */
  446. status = HIFReadWrite(pDev->HIFDevice,
  447. HOST_INT_STATUS_ADDRESS,
  448. (u8 *)&pDev->IrqProcRegisters,
  449. AR6K_IRQ_PROC_REGS_SIZE,
  450. HIF_RD_SYNC_BYTE_INC,
  451. NULL);
  452. if (status) {
  453. break;
  454. }
  455. #ifdef ATH_DEBUG_MODULE
  456. if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
  457. DevDumpRegisters(pDev,
  458. &pDev->IrqProcRegisters,
  459. &pDev->IrqEnableRegisters);
  460. }
  461. #endif
  462. /* Update only those registers that are enabled */
  463. host_int_status = pDev->IrqProcRegisters.host_int_status &
  464. pDev->IrqEnableRegisters.int_status_enable;
  465. if (NULL == pDev->GetPendingEventsFunc) {
  466. /* only look at mailbox status if the HIF layer did not provide this function,
  467. * on some HIF interfaces reading the RX lookahead is not valid to do */
  468. if (host_int_status & (1 << HTC_MAILBOX)) {
  469. /* mask out pending mailbox value, we use "lookAhead" as the real flag for
  470. * mailbox processing below */
  471. host_int_status &= ~(1 << HTC_MAILBOX);
  472. if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
  473. /* mailbox has a message and the look ahead is valid */
  474. lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
  475. if (0 == lookAhead) {
  476. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
  477. }
  478. }
  479. }
  480. } else {
  481. /* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
  482. host_int_status &= ~(1 << HTC_MAILBOX);
  483. }
  484. if (pDev->GMboxEnabled) {
  485. /*call GMBOX layer to process any interrupts of interest */
  486. status = DevCheckGMboxInterrupts(pDev);
  487. }
  488. } while (false);
  489. do {
  490. /* did the interrupt status fetches succeed? */
  491. if (status) {
  492. break;
  493. }
  494. if ((0 == host_int_status) && (0 == lookAhead)) {
  495. /* nothing to process, the caller can use this to break out of a loop */
  496. *pDone = true;
  497. break;
  498. }
  499. if (lookAhead != 0) {
  500. int fetched = 0;
  501. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
  502. /* Mailbox Interrupt, the HTC layer may issue async requests to empty the
  503. * mailbox...
  504. * When emptying the recv mailbox we use the async handler above called from the
  505. * completion routine of the callers read request. This can improve performance
  506. * by reducing context switching when we rapidly pull packets */
  507. status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, 1, pASyncProcessing, &fetched);
  508. if (status) {
  509. break;
  510. }
  511. if (!fetched) {
  512. /* HTC could not pull any messages out due to lack of resources */
  513. /* force DSR handler to ack the interrupt */
  514. *pASyncProcessing = false;
  515. pDev->RecheckIRQStatusCnt = 0;
  516. }
  517. }
  518. /* now handle the rest of them */
  519. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  520. (" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
  521. host_int_status));
  522. if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
  523. /* CPU Interrupt */
  524. status = DevServiceCPUInterrupt(pDev);
  525. if (status){
  526. break;
  527. }
  528. }
  529. if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
  530. /* Error Interrupt */
  531. status = DevServiceErrorInterrupt(pDev);
  532. if (status){
  533. break;
  534. }
  535. }
  536. if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
  537. /* Counter Interrupt */
  538. status = DevServiceCounterInterrupt(pDev);
  539. if (status){
  540. break;
  541. }
  542. }
  543. } while (false);
  544. /* an optimization to bypass reading the IRQ status registers unecessarily which can re-wake
  545. * the target, if upper layers determine that we are in a low-throughput mode, we can
  546. * rely on taking another interrupt rather than re-checking the status registers which can
  547. * re-wake the target.
  548. *
  549. * NOTE : for host interfaces that use the special GetPendingEventsFunc, this optimization cannot
  550. * be used due to possible side-effects. For example, SPI requires the host to drain all
  551. * messages from the mailbox before exiting the ISR routine. */
  552. if (!(*pASyncProcessing) && (pDev->RecheckIRQStatusCnt == 0) && (pDev->GetPendingEventsFunc == NULL)) {
  553. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Bypassing IRQ Status re-check, forcing done \n"));
  554. *pDone = true;
  555. }
  556. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
  557. *pDone, *pASyncProcessing, status));
  558. return status;
  559. }
  560. /* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/
  561. int DevDsrHandler(void *context)
  562. {
  563. struct ar6k_device *pDev = (struct ar6k_device *)context;
  564. int status = 0;
  565. bool done = false;
  566. bool asyncProc = false;
  567. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
  568. /* reset the recv counter that tracks when we need to yield from the DSR */
  569. pDev->CurrentDSRRecvCount = 0;
  570. /* reset counter used to flag a re-scan of IRQ status registers on the target */
  571. pDev->RecheckIRQStatusCnt = 0;
  572. while (!done) {
  573. status = ProcessPendingIRQs(pDev, &done, &asyncProc);
  574. if (status) {
  575. break;
  576. }
  577. if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
  578. /* the HIF layer does not allow async IRQ processing, override the asyncProc flag */
  579. asyncProc = false;
  580. /* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers.
  581. * this has a nice side effect of blocking us until all async read requests are completed.
  582. * This behavior is required on some HIF implementations that do not allow ASYNC
  583. * processing in interrupt handlers (like Windows CE) */
  584. if (pDev->DSRCanYield && DEV_CHECK_RECV_YIELD(pDev)) {
  585. /* ProcessPendingIRQs() pulled enough recv messages to satisfy the yield count, stop
  586. * checking for more messages and return */
  587. break;
  588. }
  589. }
  590. if (asyncProc) {
  591. /* the function performed some async I/O for performance, we
  592. need to exit the ISR immediately, the check below will prevent the interrupt from being
  593. Ack'd while we handle it asynchronously */
  594. break;
  595. }
  596. }
  597. if (!status && !asyncProc) {
  598. /* Ack the interrupt only if :
  599. * 1. we did not get any errors in processing interrupts
  600. * 2. there are no outstanding async processing requests */
  601. if (pDev->DSRCanYield) {
  602. /* if the DSR can yield do not ACK the interrupt, there could be more pending messages.
  603. * The HIF layer must ACK the interrupt on behalf of HTC */
  604. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Yield in effect (cur RX count: %d) \n", pDev->CurrentDSRRecvCount));
  605. } else {
  606. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n"));
  607. HIFAckInterrupt(pDev->HIFDevice);
  608. }
  609. }
  610. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n"));
  611. return status;
  612. }
  613. #ifdef ATH_DEBUG_MODULE
  614. void DumpAR6KDevState(struct ar6k_device *pDev)
  615. {
  616. int status;
  617. struct ar6k_irq_enable_registers regs;
  618. struct ar6k_irq_proc_registers procRegs;
  619. LOCK_AR6K(pDev);
  620. /* copy into our temp area */
  621. memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
  622. UNLOCK_AR6K(pDev);
  623. /* load the register table from the device */
  624. status = HIFReadWrite(pDev->HIFDevice,
  625. HOST_INT_STATUS_ADDRESS,
  626. (u8 *)&procRegs,
  627. AR6K_IRQ_PROC_REGS_SIZE,
  628. HIF_RD_SYNC_BYTE_INC,
  629. NULL);
  630. if (status) {
  631. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  632. ("DumpAR6KDevState : Failed to read register table (%d) \n",status));
  633. return;
  634. }
  635. DevDumpRegisters(pDev,&procRegs,&regs);
  636. if (pDev->GMboxInfo.pStateDumpCallback != NULL) {
  637. pDev->GMboxInfo.pStateDumpCallback(pDev->GMboxInfo.pProtocolContext);
  638. }
  639. /* dump any bus state at the HIF layer */
  640. HIFConfigureDevice(pDev->HIFDevice,HIF_DEVICE_DEBUG_BUS_STATE,NULL,0);
  641. }
  642. #endif