ar6k_events.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. //------------------------------------------------------------------------------
  2. // <copyright file="ar6k_events.c" company="Atheros">
  3. // Copyright (c) 2007-2008 Atheros Corporation. All rights reserved.
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License version 2 as
  7. // published by the Free Software Foundation;
  8. //
  9. // Software distributed under the License is distributed on an "AS
  10. // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11. // implied. See the License for the specific language governing
  12. // rights and limitations under the License.
  13. //
  14. //
  15. //------------------------------------------------------------------------------
  16. //==============================================================================
  17. // AR6K Driver layer event handling (i.e. interrupts, message polling)
  18. //
  19. // Author(s): ="Atheros"
  20. //==============================================================================
  21. #include "a_config.h"
  22. #include "athdefs.h"
  23. #include "a_types.h"
  24. #include "AR6002/hw/mbox_host_reg.h"
  25. #include "AR6002/hw/rtc_reg.h"
  26. #include "a_osapi.h"
  27. #include "a_debug.h"
  28. #include "hif.h"
  29. #include "htc_packet.h"
  30. #include "ar6k.h"
  31. extern void AR6KFreeIOPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket);
  32. extern HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev);
  33. static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev);
  34. #define DELAY_PER_INTERVAL_MS 10 /* 10 MS delay per polling interval */
  35. /* completion routine for ALL HIF layer async I/O */
  36. A_STATUS DevRWCompletionHandler(void *context, A_STATUS status)
  37. {
  38. HTC_PACKET *pPacket = (HTC_PACKET *)context;
  39. COMPLETE_HTC_PACKET(pPacket,status);
  40. return A_OK;
  41. }
  42. /* mailbox recv message polling */
  43. A_STATUS DevPollMboxMsgRecv(AR6K_DEVICE *pDev,
  44. A_UINT32 *pLookAhead,
  45. int TimeoutMS)
  46. {
  47. A_STATUS status = A_OK;
  48. int timeout = TimeoutMS/DELAY_PER_INTERVAL_MS;
  49. AR_DEBUG_ASSERT(timeout > 0);
  50. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+DevPollMboxMsgRecv \n"));
  51. while (TRUE) {
  52. if (pDev->GetPendingEventsFunc != NULL)
  53. {
  54. HIF_PENDING_EVENTS_INFO events;
  55. /* the HIF layer uses a special mechanism to get events, do this
  56. * synchronously */
  57. status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
  58. &events,
  59. NULL);
  60. if (A_FAILED(status))
  61. {
  62. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get pending events \n"));
  63. break;
  64. }
  65. if (events.Events & HIF_RECV_MSG_AVAIL)
  66. {
  67. /* there is a message available, the lookahead should be valid now */
  68. *pLookAhead = events.LookAhead;
  69. break;
  70. }
  71. }
  72. else
  73. {
  74. /* this is the standard HIF way.... */
  75. /* load the register table */
  76. status = HIFReadWrite(pDev->HIFDevice,
  77. HOST_INT_STATUS_ADDRESS,
  78. (A_UINT8 *)&pDev->IrqProcRegisters,
  79. AR6K_IRQ_PROC_REGS_SIZE,
  80. HIF_RD_SYNC_BYTE_INC,
  81. NULL);
  82. if (A_FAILED(status))
  83. {
  84. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to read register table \n"));
  85. break;
  86. }
  87. /* check for MBOX data and valid lookahead */
  88. if (pDev->IrqProcRegisters.host_int_status & (1 << HTC_MAILBOX))
  89. {
  90. if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX))
  91. {
  92. /* mailbox has a message and the look ahead is valid */
  93. *pLookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
  94. break;
  95. }
  96. }
  97. }
  98. timeout--;
  99. if (timeout <= 0)
  100. {
  101. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Timeout waiting for recv message \n"));
  102. status = A_ERROR;
  103. /* check if the target asserted */
  104. if ( pDev->IrqProcRegisters.counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
  105. /* target signaled an assert, process this pending interrupt
  106. * this will call the target failure handler */
  107. DevServiceDebugInterrupt(pDev);
  108. }
  109. break;
  110. }
  111. /* delay a little */
  112. A_MDELAY(DELAY_PER_INTERVAL_MS);
  113. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Retry Mbox Poll : %d \n",timeout));
  114. }
  115. AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-DevPollMboxMsgRecv \n"));
  116. return status;
  117. }
  118. static A_STATUS DevServiceCPUInterrupt(AR6K_DEVICE *pDev)
  119. {
  120. A_STATUS status;
  121. A_UINT8 cpu_int_status;
  122. A_UINT8 regBuffer[4];
  123. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("CPU Interrupt\n"));
  124. cpu_int_status = pDev->IrqProcRegisters.cpu_int_status &
  125. pDev->IrqEnableRegisters.cpu_int_status_enable;
  126. AR_DEBUG_ASSERT(cpu_int_status);
  127. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  128. ("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
  129. cpu_int_status));
  130. /* Clear the interrupt */
  131. pDev->IrqProcRegisters.cpu_int_status &= ~cpu_int_status; /* W1C */
  132. /* set up the register transfer buffer to hit the register 4 times , this is done
  133. * to make the access 4-byte aligned to mitigate issues with host bus interconnects that
  134. * restrict bus transfer lengths to be a multiple of 4-bytes */
  135. /* set W1C value to clear the interrupt, this hits the register first */
  136. regBuffer[0] = cpu_int_status;
  137. /* the remaining 4 values are set to zero which have no-effect */
  138. regBuffer[1] = 0;
  139. regBuffer[2] = 0;
  140. regBuffer[3] = 0;
  141. status = HIFReadWrite(pDev->HIFDevice,
  142. CPU_INT_STATUS_ADDRESS,
  143. regBuffer,
  144. 4,
  145. HIF_WR_SYNC_BYTE_FIX,
  146. NULL);
  147. AR_DEBUG_ASSERT(status == A_OK);
  148. return status;
  149. }
  150. static A_STATUS DevServiceErrorInterrupt(AR6K_DEVICE *pDev)
  151. {
  152. A_STATUS status;
  153. A_UINT8 error_int_status;
  154. A_UINT8 regBuffer[4];
  155. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error Interrupt\n"));
  156. error_int_status = pDev->IrqProcRegisters.error_int_status & 0x0F;
  157. AR_DEBUG_ASSERT(error_int_status);
  158. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  159. ("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
  160. error_int_status));
  161. if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) {
  162. /* Wakeup */
  163. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n"));
  164. }
  165. if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) {
  166. /* Rx Underflow */
  167. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n"));
  168. if (pDev->TargetFailureCallback != NULL) {
  169. pDev->TargetFailureCallback(pDev->HTCContext, AR6K_TARGET_RX_ERROR);
  170. }
  171. }
  172. if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) {
  173. /* Tx Overflow */
  174. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n"));
  175. if (pDev->TargetFailureCallback != NULL) {
  176. pDev->TargetFailureCallback(pDev->HTCContext, AR6K_TARGET_TX_ERROR);
  177. }
  178. }
  179. /* Clear the interrupt */
  180. pDev->IrqProcRegisters.error_int_status &= ~error_int_status; /* W1C */
  181. /* set up the register transfer buffer to hit the register 4 times , this is done
  182. * to make the access 4-byte aligned to mitigate issues with host bus interconnects that
  183. * restrict bus transfer lengths to be a multiple of 4-bytes */
  184. /* set W1C value to clear the interrupt, this hits the register first */
  185. regBuffer[0] = error_int_status;
  186. /* the remaining 4 values are set to zero which have no-effect */
  187. regBuffer[1] = 0;
  188. regBuffer[2] = 0;
  189. regBuffer[3] = 0;
  190. status = HIFReadWrite(pDev->HIFDevice,
  191. ERROR_INT_STATUS_ADDRESS,
  192. regBuffer,
  193. 4,
  194. HIF_WR_SYNC_BYTE_FIX,
  195. NULL);
  196. AR_DEBUG_ASSERT(status == A_OK);
  197. return status;
  198. }
  199. static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev)
  200. {
  201. A_UINT32 dummy;
  202. A_STATUS status;
  203. /* Send a target failure event to the application */
  204. AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n"));
  205. if (pDev->TargetFailureCallback != NULL) {
  206. pDev->TargetFailureCallback(pDev->HTCContext, AR6K_TARGET_ASSERT);
  207. }
  208. /* clear the interrupt , the debug error interrupt is
  209. * counter 0 */
  210. /* read counter to clear interrupt */
  211. status = HIFReadWrite(pDev->HIFDevice,
  212. COUNT_DEC_ADDRESS,
  213. (A_UINT8 *)&dummy,
  214. 4,
  215. HIF_RD_SYNC_BYTE_INC,
  216. NULL);
  217. AR_DEBUG_ASSERT(status == A_OK);
  218. return status;
  219. }
  220. static A_STATUS DevServiceCounterInterrupt(AR6K_DEVICE *pDev)
  221. {
  222. A_UINT8 counter_int_status;
  223. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n"));
  224. counter_int_status = pDev->IrqProcRegisters.counter_int_status &
  225. pDev->IrqEnableRegisters.counter_int_status_enable;
  226. AR_DEBUG_ASSERT(counter_int_status);
  227. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  228. ("Valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
  229. counter_int_status));
  230. /* Check if the debug interrupt is pending */
  231. if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
  232. return DevServiceDebugInterrupt(pDev);
  233. }
  234. return A_OK;
  235. }
  236. /* callback when our fetch to get interrupt status registers completes */
  237. static void DevGetEventAsyncHandler(void *Context, HTC_PACKET *pPacket)
  238. {
  239. AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
  240. A_UINT32 lookAhead = 0;
  241. A_BOOL otherInts = FALSE;
  242. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGetEventAsyncHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
  243. do {
  244. if (A_FAILED(pPacket->Status)) {
  245. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
  246. (" GetEvents I/O request failed, status:%d \n", pPacket->Status));
  247. /* bail out, don't unmask HIF interrupt */
  248. break;
  249. }
  250. if (pDev->GetPendingEventsFunc != NULL) {
  251. /* the HIF layer collected the information for us */
  252. HIF_PENDING_EVENTS_INFO *pEvents = (HIF_PENDING_EVENTS_INFO *)pPacket->pBuffer;
  253. if (pEvents->Events & HIF_RECV_MSG_AVAIL) {
  254. lookAhead = pEvents->LookAhead;
  255. if (0 == lookAhead) {
  256. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler1, lookAhead is zero! \n"));
  257. }
  258. }
  259. if (pEvents->Events & HIF_OTHER_EVENTS) {
  260. otherInts = TRUE;
  261. }
  262. } else {
  263. /* standard interrupt table handling.... */
  264. AR6K_IRQ_PROC_REGISTERS *pReg = (AR6K_IRQ_PROC_REGISTERS *)pPacket->pBuffer;
  265. A_UINT8 host_int_status;
  266. host_int_status = pReg->host_int_status & pDev->IrqEnableRegisters.int_status_enable;
  267. if (host_int_status & (1 << HTC_MAILBOX)) {
  268. host_int_status &= ~(1 << HTC_MAILBOX);
  269. if (pReg->rx_lookahead_valid & (1 << HTC_MAILBOX)) {
  270. /* mailbox has a message and the look ahead is valid */
  271. lookAhead = pReg->rx_lookahead[HTC_MAILBOX];
  272. if (0 == lookAhead) {
  273. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler2, lookAhead is zero! \n"));
  274. }
  275. }
  276. }
  277. if (host_int_status) {
  278. /* there are other interrupts to handle */
  279. otherInts = TRUE;
  280. }
  281. }
  282. if (otherInts || (lookAhead == 0)) {
  283. /* if there are other interrupts to process, we cannot do this in the async handler so
  284. * ack the interrupt which will cause our sync handler to run again
  285. * if however there are no more messages, we can now ack the interrupt */
  286. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  287. (" Acking interrupt from DevGetEventAsyncHandler (otherints:%d, lookahead:0x%X)\n",
  288. otherInts, lookAhead));
  289. HIFAckInterrupt(pDev->HIFDevice);
  290. } else {
  291. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  292. (" DevGetEventAsyncHandler : detected another message, lookahead :0x%X \n",
  293. lookAhead));
  294. /* lookahead is non-zero and there are no other interrupts to service,
  295. * go get the next message */
  296. pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, NULL);
  297. }
  298. } while (FALSE);
  299. /* free this IO packet */
  300. AR6KFreeIOPacket(pDev,pPacket);
  301. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGetEventAsyncHandler \n"));
  302. }
  303. /* called by the HTC layer when it wants us to check if the device has any more pending
  304. * recv messages, this starts off a series of async requests to read interrupt registers */
  305. A_STATUS DevCheckPendingRecvMsgsAsync(void *context)
  306. {
  307. AR6K_DEVICE *pDev = (AR6K_DEVICE *)context;
  308. A_STATUS status = A_OK;
  309. HTC_PACKET *pIOPacket;
  310. /* this is called in an ASYNC only context, we may NOT block, sleep or call any apis that can
  311. * cause us to switch contexts */
  312. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevCheckPendingRecvMsgsAsync: (dev: 0x%X)\n", (A_UINT32)pDev));
  313. do {
  314. if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
  315. /* break the async processing chain right here, no need to continue.
  316. * The DevDsrHandler() will handle things in a loop when things are driven
  317. * synchronously */
  318. break;
  319. }
  320. /* first allocate one of our HTC packets we created for async I/O
  321. * we reuse HTC packet definitions so that we can use the completion mechanism
  322. * in DevRWCompletionHandler() */
  323. pIOPacket = AR6KAllocIOPacket(pDev);
  324. if (NULL == pIOPacket) {
  325. /* there should be only 1 asynchronous request out at a time to read these registers
  326. * so this should actually never happen */
  327. status = A_NO_MEMORY;
  328. AR_DEBUG_ASSERT(FALSE);
  329. break;
  330. }
  331. /* stick in our completion routine when the I/O operation completes */
  332. pIOPacket->Completion = DevGetEventAsyncHandler;
  333. pIOPacket->pContext = pDev;
  334. if (pDev->GetPendingEventsFunc) {
  335. /* HIF layer has it's own mechanism, pass the IO to it.. */
  336. status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
  337. (HIF_PENDING_EVENTS_INFO *)pIOPacket->pBuffer,
  338. pIOPacket);
  339. } else {
  340. /* standard way, read the interrupt register table asynchronously again */
  341. status = HIFReadWrite(pDev->HIFDevice,
  342. HOST_INT_STATUS_ADDRESS,
  343. pIOPacket->pBuffer,
  344. AR6K_IRQ_PROC_REGS_SIZE,
  345. HIF_RD_ASYNC_BYTE_INC,
  346. pIOPacket);
  347. }
  348. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Async IO issued to get interrupt status...\n"));
  349. } while (FALSE);
  350. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevCheckPendingRecvMsgsAsync \n"));
  351. return status;
  352. }
  353. /* process pending interrupts synchronously */
  354. static A_STATUS ProcessPendingIRQs(AR6K_DEVICE *pDev, A_BOOL *pDone, A_BOOL *pASyncProcessing)
  355. {
  356. A_STATUS status = A_OK;
  357. A_UINT8 host_int_status = 0;
  358. A_UINT32 lookAhead = 0;
  359. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%X)\n", (A_UINT32)pDev));
  360. /*** NOTE: the HIF implementation guarantees that the context of this call allows
  361. * us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
  362. * can block or switch thread/task ontexts.
  363. * This is a fully schedulable context.
  364. * */
  365. do {
  366. if (pDev->IrqEnableRegisters.int_status_enable == 0) {
  367. /* interrupt enables have been cleared, do not try to process any pending interrupts that
  368. * may result in more bus transactions. The target may be unresponsive at this
  369. * point. */
  370. break;
  371. }
  372. if (pDev->GetPendingEventsFunc != NULL) {
  373. HIF_PENDING_EVENTS_INFO events;
  374. /* the HIF layer uses a special mechanism to get events
  375. * get this synchronously */
  376. status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
  377. &events,
  378. NULL);
  379. if (A_FAILED(status)) {
  380. break;
  381. }
  382. if (events.Events & HIF_RECV_MSG_AVAIL) {
  383. lookAhead = events.LookAhead;
  384. if (0 == lookAhead) {
  385. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
  386. }
  387. }
  388. if (!(events.Events & HIF_OTHER_EVENTS) ||
  389. !(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
  390. /* no need to read the register table, no other interesting interrupts.
  391. * Some interfaces (like SPI) can shadow interrupt sources without
  392. * requiring the host to do a full table read */
  393. break;
  394. }
  395. /* otherwise fall through and read the register table */
  396. }
  397. /*
  398. * Read the first 28 bytes of the HTC register table. This will yield us
  399. * the value of different int status registers and the lookahead
  400. * registers.
  401. * length = sizeof(int_status) + sizeof(cpu_int_status) +
  402. * sizeof(error_int_status) + sizeof(counter_int_status) +
  403. * sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
  404. * sizeof(hole) + sizeof(rx_lookahead) +
  405. * sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
  406. * sizeof(error_status_enable) +
  407. * sizeof(counter_int_status_enable);
  408. *
  409. */
  410. status = HIFReadWrite(pDev->HIFDevice,
  411. HOST_INT_STATUS_ADDRESS,
  412. (A_UINT8 *)&pDev->IrqProcRegisters,
  413. AR6K_IRQ_PROC_REGS_SIZE,
  414. HIF_RD_SYNC_BYTE_INC,
  415. NULL);
  416. if (A_FAILED(status)) {
  417. break;
  418. }
  419. if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
  420. DevDumpRegisters(&pDev->IrqProcRegisters,
  421. &pDev->IrqEnableRegisters);
  422. }
  423. /* Update only those registers that are enabled */
  424. host_int_status = pDev->IrqProcRegisters.host_int_status &
  425. pDev->IrqEnableRegisters.int_status_enable;
  426. if (NULL == pDev->GetPendingEventsFunc) {
  427. /* only look at mailbox status if the HIF layer did not provide this function,
  428. * on some HIF interfaces reading the RX lookahead is not valid to do */
  429. if (host_int_status & (1 << HTC_MAILBOX)) {
  430. /* mask out pending mailbox value, we use "lookAhead" as the real flag for
  431. * mailbox processing below */
  432. host_int_status &= ~(1 << HTC_MAILBOX);
  433. if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
  434. /* mailbox has a message and the look ahead is valid */
  435. lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
  436. if (0 == lookAhead) {
  437. AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
  438. }
  439. }
  440. }
  441. } else {
  442. /* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
  443. host_int_status &= ~(1 << HTC_MAILBOX);
  444. }
  445. } while (FALSE);
  446. do {
  447. /* did the interrupt status fetches succeed? */
  448. if (A_FAILED(status)) {
  449. break;
  450. }
  451. if ((0 == host_int_status) && (0 == lookAhead)) {
  452. /* nothing to process, the caller can use this to break out of a loop */
  453. *pDone = TRUE;
  454. break;
  455. }
  456. if (lookAhead != 0) {
  457. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
  458. /* Mailbox Interrupt, the HTC layer may issue async requests to empty the
  459. * mailbox...
  460. * When emptying the recv mailbox we use the async handler above called from the
  461. * completion routine of the callers read request. This can improve performance
  462. * by reducing context switching when we rapidly pull packets */
  463. status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, pASyncProcessing);
  464. if (A_FAILED(status)) {
  465. break;
  466. }
  467. /* if sync processing of Rx packets is enabled and lookahead of last packet is 0, then
  468. * we can avoid extra CMD53 16-byte read above by setting pDone = TRUE */
  469. if ((lookAhead == 0) && (*pASyncProcessing == FALSE)) {
  470. *pDone = TRUE;
  471. }
  472. }
  473. /* now handle the rest of them */
  474. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
  475. (" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
  476. host_int_status));
  477. if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
  478. /* CPU Interrupt */
  479. status = DevServiceCPUInterrupt(pDev);
  480. if (A_FAILED(status)){
  481. break;
  482. }
  483. }
  484. if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
  485. /* Error Interrupt */
  486. status = DevServiceErrorInterrupt(pDev);
  487. if (A_FAILED(status)){
  488. break;
  489. }
  490. }
  491. if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
  492. /* Counter Interrupt */
  493. status = DevServiceCounterInterrupt(pDev);
  494. if (A_FAILED(status)){
  495. break;
  496. }
  497. }
  498. } while (FALSE);
  499. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
  500. *pDone, *pASyncProcessing, status));
  501. return status;
  502. }
  503. /* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/
  504. A_STATUS DevDsrHandler(void *context)
  505. {
  506. AR6K_DEVICE *pDev = (AR6K_DEVICE *)context;
  507. A_STATUS status = A_OK;
  508. A_BOOL done = FALSE;
  509. A_BOOL asyncProc = FALSE;
  510. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
  511. while (!done) {
  512. status = ProcessPendingIRQs(pDev, &done, &asyncProc);
  513. if (A_FAILED(status)) {
  514. break;
  515. }
  516. if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
  517. /* the HIF layer does not allow async IRQ processing, override the asyncProc flag */
  518. asyncProc = FALSE;
  519. /* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers.
  520. * this has a nice side effect of blocking us until all async read requests are completed.
  521. * This behavior is required on some HIF implementations that do not allow ASYNC
  522. * processing in interrupt handlers (like Windows CE) */
  523. }
  524. if (asyncProc) {
  525. /* the function performed some async I/O for performance, we
  526. need to exit the ISR immediately, the check below will prevent the interrupt from being
  527. Ack'd while we handle it asynchronously */
  528. break;
  529. }
  530. }
  531. if (A_SUCCESS(status) && !asyncProc) {
  532. /* Ack the interrupt only if :
  533. * 1. we did not get any errors in processing interrupts
  534. * 2. there are no outstanding async processing requests */
  535. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n"));
  536. HIFAckInterrupt(pDev->HIFDevice);
  537. }
  538. AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n"));
  539. return status;
  540. }