iwl-agn-ict.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /******************************************************************************
  2. *
  3. * GPL LICENSE SUMMARY
  4. *
  5. * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of version 2 of the GNU General Public License as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  19. * USA
  20. *
  21. * The full GNU General Public License is included in this distribution
  22. * in the file called LICENSE.GPL.
  23. *
  24. * Contact Information:
  25. * Intel Linux Wireless <ilw@linux.intel.com>
  26. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  27. *****************************************************************************/
  28. #include <linux/kernel.h>
  29. #include <linux/module.h>
  30. #include <linux/etherdevice.h>
  31. #include <linux/sched.h>
  32. #include <linux/gfp.h>
  33. #include <net/mac80211.h>
  34. #include "iwl-dev.h"
  35. #include "iwl-core.h"
  36. #include "iwl-agn.h"
  37. #include "iwl-helpers.h"
  38. #define ICT_COUNT (PAGE_SIZE/sizeof(u32))
  39. /* Free dram table */
  40. void iwl_free_isr_ict(struct iwl_priv *priv)
  41. {
  42. if (priv->_agn.ict_tbl_vir) {
  43. dma_free_coherent(priv->bus.dev,
  44. (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
  45. priv->_agn.ict_tbl_vir,
  46. priv->_agn.ict_tbl_dma);
  47. priv->_agn.ict_tbl_vir = NULL;
  48. memset(&priv->_agn.ict_tbl_dma, 0,
  49. sizeof(priv->_agn.ict_tbl_dma));
  50. memset(&priv->_agn.aligned_ict_tbl_dma, 0,
  51. sizeof(priv->_agn.aligned_ict_tbl_dma));
  52. }
  53. }
  54. /* allocate dram shared table it is a PAGE_SIZE aligned
  55. * also reset all data related to ICT table interrupt.
  56. */
  57. int iwl_alloc_isr_ict(struct iwl_priv *priv)
  58. {
  59. /* allocate shrared data table */
  60. priv->_agn.ict_tbl_vir =
  61. dma_alloc_coherent(priv->bus.dev,
  62. (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
  63. &priv->_agn.ict_tbl_dma, GFP_KERNEL);
  64. if (!priv->_agn.ict_tbl_vir)
  65. return -ENOMEM;
  66. /* align table to PAGE_SIZE boundary */
  67. priv->_agn.aligned_ict_tbl_dma = ALIGN(priv->_agn.ict_tbl_dma, PAGE_SIZE);
  68. IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
  69. (unsigned long long)priv->_agn.ict_tbl_dma,
  70. (unsigned long long)priv->_agn.aligned_ict_tbl_dma,
  71. (int)(priv->_agn.aligned_ict_tbl_dma - priv->_agn.ict_tbl_dma));
  72. priv->_agn.ict_tbl = priv->_agn.ict_tbl_vir +
  73. (priv->_agn.aligned_ict_tbl_dma - priv->_agn.ict_tbl_dma);
  74. IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
  75. priv->_agn.ict_tbl, priv->_agn.ict_tbl_vir,
  76. (int)(priv->_agn.aligned_ict_tbl_dma - priv->_agn.ict_tbl_dma));
  77. /* reset table and index to all 0 */
  78. memset(priv->_agn.ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
  79. priv->_agn.ict_index = 0;
  80. /* add periodic RX interrupt */
  81. priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
  82. return 0;
  83. }
  84. /* Device is going up inform it about using ICT interrupt table,
  85. * also we need to tell the driver to start using ICT interrupt.
  86. */
  87. int iwl_reset_ict(struct iwl_priv *priv)
  88. {
  89. u32 val;
  90. unsigned long flags;
  91. if (!priv->_agn.ict_tbl_vir)
  92. return 0;
  93. spin_lock_irqsave(&priv->lock, flags);
  94. iwl_disable_interrupts(priv);
  95. memset(&priv->_agn.ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
  96. val = priv->_agn.aligned_ict_tbl_dma >> PAGE_SHIFT;
  97. val |= CSR_DRAM_INT_TBL_ENABLE;
  98. val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
  99. IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
  100. "aligned dma address %Lx\n",
  101. val, (unsigned long long)priv->_agn.aligned_ict_tbl_dma);
  102. iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
  103. priv->_agn.use_ict = true;
  104. priv->_agn.ict_index = 0;
  105. iwl_write32(priv, CSR_INT, priv->inta_mask);
  106. iwl_enable_interrupts(priv);
  107. spin_unlock_irqrestore(&priv->lock, flags);
  108. return 0;
  109. }
  110. /* Device is going down disable ict interrupt usage */
  111. void iwl_disable_ict(struct iwl_priv *priv)
  112. {
  113. unsigned long flags;
  114. spin_lock_irqsave(&priv->lock, flags);
  115. priv->_agn.use_ict = false;
  116. spin_unlock_irqrestore(&priv->lock, flags);
  117. }
  118. static irqreturn_t iwl_isr(int irq, void *data)
  119. {
  120. struct iwl_priv *priv = data;
  121. u32 inta, inta_mask;
  122. unsigned long flags;
  123. #ifdef CONFIG_IWLWIFI_DEBUG
  124. u32 inta_fh;
  125. #endif
  126. if (!priv)
  127. return IRQ_NONE;
  128. spin_lock_irqsave(&priv->lock, flags);
  129. /* Disable (but don't clear!) interrupts here to avoid
  130. * back-to-back ISRs and sporadic interrupts from our NIC.
  131. * If we have something to service, the tasklet will re-enable ints.
  132. * If we *don't* have something, we'll re-enable before leaving here. */
  133. inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
  134. iwl_write32(priv, CSR_INT_MASK, 0x00000000);
  135. /* Discover which interrupts are active/pending */
  136. inta = iwl_read32(priv, CSR_INT);
  137. /* Ignore interrupt if there's nothing in NIC to service.
  138. * This may be due to IRQ shared with another device,
  139. * or due to sporadic interrupts thrown from our NIC. */
  140. if (!inta) {
  141. IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
  142. goto none;
  143. }
  144. if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
  145. /* Hardware disappeared. It might have already raised
  146. * an interrupt */
  147. IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
  148. goto unplugged;
  149. }
  150. #ifdef CONFIG_IWLWIFI_DEBUG
  151. if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
  152. inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
  153. IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
  154. "fh 0x%08x\n", inta, inta_mask, inta_fh);
  155. }
  156. #endif
  157. priv->_agn.inta |= inta;
  158. /* iwl_irq_tasklet() will service interrupts and re-enable them */
  159. if (likely(inta))
  160. tasklet_schedule(&priv->irq_tasklet);
  161. else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
  162. iwl_enable_interrupts(priv);
  163. unplugged:
  164. spin_unlock_irqrestore(&priv->lock, flags);
  165. return IRQ_HANDLED;
  166. none:
  167. /* re-enable interrupts here since we don't have anything to service. */
  168. /* only Re-enable if disabled by irq and no schedules tasklet. */
  169. if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
  170. iwl_enable_interrupts(priv);
  171. spin_unlock_irqrestore(&priv->lock, flags);
  172. return IRQ_NONE;
  173. }
  174. /* interrupt handler using ict table, with this interrupt driver will
  175. * stop using INTA register to get device's interrupt, reading this register
  176. * is expensive, device will write interrupts in ICT dram table, increment
  177. * index then will fire interrupt to driver, driver will OR all ICT table
  178. * entries from current index up to table entry with 0 value. the result is
  179. * the interrupt we need to service, driver will set the entries back to 0 and
  180. * set index.
  181. */
  182. irqreturn_t iwl_isr_ict(int irq, void *data)
  183. {
  184. struct iwl_priv *priv = data;
  185. u32 inta, inta_mask;
  186. u32 val = 0;
  187. unsigned long flags;
  188. if (!priv)
  189. return IRQ_NONE;
  190. /* dram interrupt table not set yet,
  191. * use legacy interrupt.
  192. */
  193. if (!priv->_agn.use_ict)
  194. return iwl_isr(irq, data);
  195. spin_lock_irqsave(&priv->lock, flags);
  196. /* Disable (but don't clear!) interrupts here to avoid
  197. * back-to-back ISRs and sporadic interrupts from our NIC.
  198. * If we have something to service, the tasklet will re-enable ints.
  199. * If we *don't* have something, we'll re-enable before leaving here.
  200. */
  201. inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
  202. iwl_write32(priv, CSR_INT_MASK, 0x00000000);
  203. /* Ignore interrupt if there's nothing in NIC to service.
  204. * This may be due to IRQ shared with another device,
  205. * or due to sporadic interrupts thrown from our NIC. */
  206. if (!priv->_agn.ict_tbl[priv->_agn.ict_index]) {
  207. IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
  208. goto none;
  209. }
  210. /* read all entries that not 0 start with ict_index */
  211. while (priv->_agn.ict_tbl[priv->_agn.ict_index]) {
  212. val |= le32_to_cpu(priv->_agn.ict_tbl[priv->_agn.ict_index]);
  213. IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
  214. priv->_agn.ict_index,
  215. le32_to_cpu(priv->_agn.ict_tbl[priv->_agn.ict_index]));
  216. priv->_agn.ict_tbl[priv->_agn.ict_index] = 0;
  217. priv->_agn.ict_index = iwl_queue_inc_wrap(priv->_agn.ict_index,
  218. ICT_COUNT);
  219. }
  220. /* We should not get this value, just ignore it. */
  221. if (val == 0xffffffff)
  222. val = 0;
  223. /*
  224. * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
  225. * (bit 15 before shifting it to 31) to clear when using interrupt
  226. * coalescing. fortunately, bits 18 and 19 stay set when this happens
  227. * so we use them to decide on the real state of the Rx bit.
  228. * In order words, bit 15 is set if bit 18 or bit 19 are set.
  229. */
  230. if (val & 0xC0000)
  231. val |= 0x8000;
  232. inta = (0xff & val) | ((0xff00 & val) << 16);
  233. IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
  234. inta, inta_mask, val);
  235. inta &= priv->inta_mask;
  236. priv->_agn.inta |= inta;
  237. /* iwl_irq_tasklet() will service interrupts and re-enable them */
  238. if (likely(inta))
  239. tasklet_schedule(&priv->irq_tasklet);
  240. else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta) {
  241. /* Allow interrupt if was disabled by this handler and
  242. * no tasklet was schedules, We should not enable interrupt,
  243. * tasklet will enable it.
  244. */
  245. iwl_enable_interrupts(priv);
  246. }
  247. spin_unlock_irqrestore(&priv->lock, flags);
  248. return IRQ_HANDLED;
  249. none:
  250. /* re-enable interrupts here since we don't have anything to service.
  251. * only Re-enable if disabled by irq.
  252. */
  253. if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
  254. iwl_enable_interrupts(priv);
  255. spin_unlock_irqrestore(&priv->lock, flags);
  256. return IRQ_NONE;
  257. }