qcu.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /*
  2. * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
  3. * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. *
  17. */
  18. /********************************************\
  19. Queue Control Unit, DFS Control Unit Functions
  20. \********************************************/
  21. #include "ath5k.h"
  22. #include "reg.h"
  23. #include "debug.h"
  24. #include "base.h"
  25. /******************\
  26. * Helper functions *
  27. \******************/
  28. /*
  29. * Get number of pending frames
  30. * for a specific queue [5211+]
  31. */
  32. u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
  33. {
  34. u32 pending;
  35. AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
  36. /* Return if queue is declared inactive */
  37. if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
  38. return false;
  39. /* XXX: How about AR5K_CFG_TXCNT ? */
  40. if (ah->ah_version == AR5K_AR5210)
  41. return false;
  42. pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
  43. pending &= AR5K_QCU_STS_FRMPENDCNT;
  44. /* It's possible to have no frames pending even if TXE
  45. * is set. To indicate that q has not stopped return
  46. * true */
  47. if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
  48. return true;
  49. return pending;
  50. }
  51. /*
  52. * Set a transmit queue inactive
  53. */
  54. void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
  55. {
  56. if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
  57. return;
  58. /* This queue will be skipped in further operations */
  59. ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
  60. /*For SIMR setup*/
  61. AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
  62. }
  63. /*
  64. * Make sure cw is a power of 2 minus 1 and smaller than 1024
  65. */
  66. static u16 ath5k_cw_validate(u16 cw_req)
  67. {
  68. u32 cw = 1;
  69. cw_req = min(cw_req, (u16)1023);
  70. while (cw < cw_req)
  71. cw = (cw << 1) | 1;
  72. return cw;
  73. }
  74. /*
  75. * Get properties for a transmit queue
  76. */
  77. int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
  78. struct ath5k_txq_info *queue_info)
  79. {
  80. memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
  81. return 0;
  82. }
  83. /*
  84. * Set properties for a transmit queue
  85. */
  86. int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
  87. const struct ath5k_txq_info *qinfo)
  88. {
  89. struct ath5k_txq_info *qi;
  90. AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
  91. qi = &ah->ah_txq[queue];
  92. if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
  93. return -EIO;
  94. /* copy and validate values */
  95. qi->tqi_type = qinfo->tqi_type;
  96. qi->tqi_subtype = qinfo->tqi_subtype;
  97. qi->tqi_flags = qinfo->tqi_flags;
  98. /*
  99. * According to the docs: Although the AIFS field is 8 bit wide,
  100. * the maximum supported value is 0xFC. Setting it higher than that
  101. * will cause the DCU to hang.
  102. */
  103. qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
  104. qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
  105. qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
  106. qi->tqi_cbr_period = qinfo->tqi_cbr_period;
  107. qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
  108. qi->tqi_burst_time = qinfo->tqi_burst_time;
  109. qi->tqi_ready_time = qinfo->tqi_ready_time;
  110. /*XXX: Is this supported on 5210 ?*/
  111. /*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
  112. if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
  113. ((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
  114. (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
  115. qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
  116. qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
  117. return 0;
  118. }
  119. /*
  120. * Initialize a transmit queue
  121. */
  122. int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
  123. struct ath5k_txq_info *queue_info)
  124. {
  125. unsigned int queue;
  126. int ret;
  127. /*
  128. * Get queue by type
  129. */
  130. /*5210 only has 2 queues*/
  131. if (ah->ah_version == AR5K_AR5210) {
  132. switch (queue_type) {
  133. case AR5K_TX_QUEUE_DATA:
  134. queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
  135. break;
  136. case AR5K_TX_QUEUE_BEACON:
  137. case AR5K_TX_QUEUE_CAB:
  138. queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
  139. break;
  140. default:
  141. return -EINVAL;
  142. }
  143. } else {
  144. switch (queue_type) {
  145. case AR5K_TX_QUEUE_DATA:
  146. for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
  147. ah->ah_txq[queue].tqi_type !=
  148. AR5K_TX_QUEUE_INACTIVE; queue++) {
  149. if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
  150. return -EINVAL;
  151. }
  152. break;
  153. case AR5K_TX_QUEUE_UAPSD:
  154. queue = AR5K_TX_QUEUE_ID_UAPSD;
  155. break;
  156. case AR5K_TX_QUEUE_BEACON:
  157. queue = AR5K_TX_QUEUE_ID_BEACON;
  158. break;
  159. case AR5K_TX_QUEUE_CAB:
  160. queue = AR5K_TX_QUEUE_ID_CAB;
  161. break;
  162. case AR5K_TX_QUEUE_XR_DATA:
  163. if (ah->ah_version != AR5K_AR5212)
  164. ATH5K_ERR(ah->ah_sc,
  165. "XR data queues only supported in"
  166. " 5212!\n");
  167. queue = AR5K_TX_QUEUE_ID_XR_DATA;
  168. break;
  169. default:
  170. return -EINVAL;
  171. }
  172. }
  173. /*
  174. * Setup internal queue structure
  175. */
  176. memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
  177. ah->ah_txq[queue].tqi_type = queue_type;
  178. if (queue_info != NULL) {
  179. queue_info->tqi_type = queue_type;
  180. ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
  181. if (ret)
  182. return ret;
  183. }
  184. /*
  185. * We use ah_txq_status to hold a temp value for
  186. * the Secondary interrupt mask registers on 5211+
  187. * check out ath5k_hw_reset_tx_queue
  188. */
  189. AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
  190. return queue;
  191. }
  192. /*******************************\
  193. * Single QCU/DCU initialization *
  194. \*******************************/
  195. /*
  196. * Set DFS properties for a transmit queue on DCU
  197. */
  198. int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
  199. {
  200. u32 retry_lg, retry_sh;
  201. struct ath5k_txq_info *tq = &ah->ah_txq[queue];
  202. AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
  203. tq = &ah->ah_txq[queue];
  204. if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
  205. return 0;
  206. if (ah->ah_version == AR5K_AR5210) {
  207. /* Only handle data queues, others will be ignored */
  208. if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
  209. return 0;
  210. /* Set Slot time */
  211. ath5k_hw_reg_write(ah, ah->ah_turbo ?
  212. AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
  213. AR5K_SLOT_TIME);
  214. /* Set ACK_CTS timeout */
  215. ath5k_hw_reg_write(ah, ah->ah_turbo ?
  216. AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
  217. AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
  218. /* Set Transmit Latency */
  219. ath5k_hw_reg_write(ah, ah->ah_turbo ?
  220. AR5K_INIT_TRANSMIT_LATENCY_TURBO :
  221. AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
  222. /* Set IFS0 */
  223. if (ah->ah_turbo) {
  224. ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
  225. tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
  226. AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
  227. AR5K_IFS0);
  228. } else {
  229. ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
  230. tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
  231. AR5K_IFS0_DIFS_S) |
  232. AR5K_INIT_SIFS, AR5K_IFS0);
  233. }
  234. /* Set IFS1 */
  235. ath5k_hw_reg_write(ah, ah->ah_turbo ?
  236. AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
  237. AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
  238. /* Set AR5K_PHY_SETTLING */
  239. ath5k_hw_reg_write(ah, ah->ah_turbo ?
  240. (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
  241. | 0x38 :
  242. (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
  243. | 0x1C,
  244. AR5K_PHY_SETTLING);
  245. /* Set Frame Control Register */
  246. ath5k_hw_reg_write(ah, ah->ah_turbo ?
  247. (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
  248. AR5K_PHY_TURBO_SHORT | 0x2020) :
  249. (AR5K_PHY_FRAME_CTL_INI | 0x1020),
  250. AR5K_PHY_FRAME_CTL_5210);
  251. }
  252. /*
  253. * Calculate and set retry limits
  254. */
  255. if (ah->ah_software_retry) {
  256. /* XXX Need to test this */
  257. retry_lg = ah->ah_limit_tx_retries;
  258. retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
  259. AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
  260. } else {
  261. retry_lg = AR5K_INIT_LG_RETRY;
  262. retry_sh = AR5K_INIT_SH_RETRY;
  263. }
  264. /*No QCU/DCU [5210]*/
  265. if (ah->ah_version == AR5K_AR5210) {
  266. ath5k_hw_reg_write(ah,
  267. (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
  268. | AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
  269. AR5K_NODCU_RETRY_LMT_SLG_RETRY)
  270. | AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
  271. AR5K_NODCU_RETRY_LMT_SSH_RETRY)
  272. | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
  273. | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
  274. AR5K_NODCU_RETRY_LMT);
  275. } else {
  276. /*QCU/DCU [5211+]*/
  277. ath5k_hw_reg_write(ah,
  278. AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
  279. AR5K_DCU_RETRY_LMT_SLG_RETRY) |
  280. AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
  281. AR5K_DCU_RETRY_LMT_SSH_RETRY) |
  282. AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
  283. AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
  284. AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
  285. /*===Rest is also for QCU/DCU only [5211+]===*/
  286. /*
  287. * Set contention window (cw_min/cw_max)
  288. * and arbitrated interframe space (aifs)...
  289. */
  290. ath5k_hw_reg_write(ah,
  291. AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
  292. AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
  293. AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
  294. AR5K_QUEUE_DFS_LOCAL_IFS(queue));
  295. /*
  296. * Set misc registers
  297. */
  298. /* Enable DCU early termination for this queue */
  299. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
  300. AR5K_QCU_MISC_DCU_EARLY);
  301. /* Enable DCU to wait for next fragment from QCU */
  302. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
  303. AR5K_DCU_MISC_FRAG_WAIT);
  304. /* On Maui and Spirit use the global seqnum on DCU */
  305. if (ah->ah_mac_version < AR5K_SREV_AR5211)
  306. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
  307. AR5K_DCU_MISC_SEQNUM_CTL);
  308. if (tq->tqi_cbr_period) {
  309. ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
  310. AR5K_QCU_CBRCFG_INTVAL) |
  311. AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
  312. AR5K_QCU_CBRCFG_ORN_THRES),
  313. AR5K_QUEUE_CBRCFG(queue));
  314. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
  315. AR5K_QCU_MISC_FRSHED_CBR);
  316. if (tq->tqi_cbr_overflow_limit)
  317. AR5K_REG_ENABLE_BITS(ah,
  318. AR5K_QUEUE_MISC(queue),
  319. AR5K_QCU_MISC_CBR_THRES_ENABLE);
  320. }
  321. if (tq->tqi_ready_time &&
  322. (tq->tqi_type != AR5K_TX_QUEUE_CAB))
  323. ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
  324. AR5K_QCU_RDYTIMECFG_INTVAL) |
  325. AR5K_QCU_RDYTIMECFG_ENABLE,
  326. AR5K_QUEUE_RDYTIMECFG(queue));
  327. if (tq->tqi_burst_time) {
  328. ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
  329. AR5K_DCU_CHAN_TIME_DUR) |
  330. AR5K_DCU_CHAN_TIME_ENABLE,
  331. AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
  332. if (tq->tqi_flags
  333. & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
  334. AR5K_REG_ENABLE_BITS(ah,
  335. AR5K_QUEUE_MISC(queue),
  336. AR5K_QCU_MISC_RDY_VEOL_POLICY);
  337. }
  338. if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
  339. ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
  340. AR5K_QUEUE_DFS_MISC(queue));
  341. if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
  342. ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
  343. AR5K_QUEUE_DFS_MISC(queue));
  344. /*
  345. * Set registers by queue type
  346. */
  347. switch (tq->tqi_type) {
  348. case AR5K_TX_QUEUE_BEACON:
  349. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
  350. AR5K_QCU_MISC_FRSHED_DBA_GT |
  351. AR5K_QCU_MISC_CBREXP_BCN_DIS |
  352. AR5K_QCU_MISC_BCN_ENABLE);
  353. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
  354. (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
  355. AR5K_DCU_MISC_ARBLOCK_CTL_S) |
  356. AR5K_DCU_MISC_ARBLOCK_IGNORE |
  357. AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
  358. AR5K_DCU_MISC_BCN_ENABLE);
  359. break;
  360. case AR5K_TX_QUEUE_CAB:
  361. /* XXX: use BCN_SENT_GT, if we can figure out how */
  362. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
  363. AR5K_QCU_MISC_FRSHED_DBA_GT |
  364. AR5K_QCU_MISC_CBREXP_DIS |
  365. AR5K_QCU_MISC_CBREXP_BCN_DIS);
  366. ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
  367. (AR5K_TUNE_SW_BEACON_RESP -
  368. AR5K_TUNE_DMA_BEACON_RESP) -
  369. AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
  370. AR5K_QCU_RDYTIMECFG_ENABLE,
  371. AR5K_QUEUE_RDYTIMECFG(queue));
  372. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
  373. (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
  374. AR5K_DCU_MISC_ARBLOCK_CTL_S));
  375. break;
  376. case AR5K_TX_QUEUE_UAPSD:
  377. AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
  378. AR5K_QCU_MISC_CBREXP_DIS);
  379. break;
  380. case AR5K_TX_QUEUE_DATA:
  381. default:
  382. break;
  383. }
  384. /* TODO: Handle frame compression */
  385. /*
  386. * Enable interrupts for this tx queue
  387. * in the secondary interrupt mask registers
  388. */
  389. if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
  390. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
  391. if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
  392. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
  393. if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
  394. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
  395. if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
  396. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
  397. if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
  398. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
  399. if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
  400. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
  401. if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
  402. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
  403. if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
  404. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
  405. if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
  406. AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
  407. /* Update secondary interrupt mask registers */
  408. /* Filter out inactive queues */
  409. ah->ah_txq_imr_txok &= ah->ah_txq_status;
  410. ah->ah_txq_imr_txerr &= ah->ah_txq_status;
  411. ah->ah_txq_imr_txurn &= ah->ah_txq_status;
  412. ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
  413. ah->ah_txq_imr_txeol &= ah->ah_txq_status;
  414. ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
  415. ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
  416. ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
  417. ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
  418. ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
  419. AR5K_SIMR0_QCU_TXOK) |
  420. AR5K_REG_SM(ah->ah_txq_imr_txdesc,
  421. AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
  422. ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
  423. AR5K_SIMR1_QCU_TXERR) |
  424. AR5K_REG_SM(ah->ah_txq_imr_txeol,
  425. AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
  426. /* Update simr2 but don't overwrite rest simr2 settings */
  427. AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
  428. AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
  429. AR5K_REG_SM(ah->ah_txq_imr_txurn,
  430. AR5K_SIMR2_QCU_TXURN));
  431. ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
  432. AR5K_SIMR3_QCBRORN) |
  433. AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
  434. AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
  435. ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
  436. AR5K_SIMR4_QTRIG), AR5K_SIMR4);
  437. /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
  438. ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
  439. AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
  440. /* No queue has TXNOFRM enabled, disable the interrupt
  441. * by setting AR5K_TXNOFRM to zero */
  442. if (ah->ah_txq_imr_nofrm == 0)
  443. ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
  444. /* Set QCU mask for this DCU to save power */
  445. AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
  446. }
  447. return 0;
  448. }
  449. /**************************\
  450. * Global QCU/DCU functions *
  451. \**************************/
  452. /*
  453. * Set slot time on DCU
  454. */
  455. int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
  456. {
  457. u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
  458. if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
  459. return -EINVAL;
  460. if (ah->ah_version == AR5K_AR5210)
  461. ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
  462. else
  463. ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
  464. return 0;
  465. }
  466. int ath5k_hw_init_queues(struct ath5k_hw *ah)
  467. {
  468. int i, ret;
  469. /* TODO: HW Compression support for data queues */
  470. /* TODO: Burst prefetch for data queues */
  471. /*
  472. * Reset queues and start beacon timers at the end of the reset routine
  473. * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
  474. * Note: If we want we can assign multiple qcus on one dcu.
  475. */
  476. for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
  477. ret = ath5k_hw_reset_tx_queue(ah, i);
  478. if (ret) {
  479. ATH5K_ERR(ah->ah_sc,
  480. "failed to reset TX queue #%d\n", i);
  481. return ret;
  482. }
  483. }
  484. return 0;
  485. }