root/drivers/net/wireless/ath/ath5k/qcu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath5k_hw_num_tx_pending
  2. ath5k_hw_release_tx_queue
  3. ath5k_cw_validate
  4. ath5k_hw_get_tx_queueprops
  5. ath5k_hw_set_tx_queueprops
  6. ath5k_hw_setup_tx_queue
  7. ath5k_hw_set_tx_retry_limits
  8. ath5k_hw_reset_tx_queue
  9. ath5k_hw_set_ifs_intervals
  10. ath5k_hw_init_queues

   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 /********************************************\
  20 Queue Control Unit, DCF Control Unit Functions
  21 \********************************************/
  22 
  23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  24 
  25 #include "ath5k.h"
  26 #include "reg.h"
  27 #include "debug.h"
  28 #include <linux/log2.h>
  29 
  30 /**
  31  * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions
  32  *
  33  * Here we setup parameters for the 12 available TX queues. Note that
  34  * on the various registers we can usually only map the first 10 of them so
  35  * basically we have 10 queues to play with. Each queue has a matching
  36  * QCU that controls when the queue will get triggered and multiple QCUs
  37  * can be mapped to a single DCU that controls the various DFS parameters
  38  * for the various queues. In our setup we have a 1:1 mapping between QCUs
  39  * and DCUs allowing us to have different DFS settings for each queue.
  40  *
  41  * When a frame goes into a TX queue, QCU decides when it'll trigger a
  42  * transmission based on various criteria (such as how many data we have inside
  43  * it's buffer or -if it's a beacon queue- if it's time to fire up the queue
  44  * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler
  45  * (arbitrator) decides the priority of each QCU based on it's configuration
  46  * (e.g. beacons are always transmitted when they leave DCU bypassing all other
  47  * frames from other queues waiting to be transmitted). After a frame leaves
  48  * the DCU it goes to PCU for further processing and then to PHY for
  49  * the actual transmission.
  50  */
  51 
  52 
  53 /******************\
  54 * Helper functions *
  55 \******************/
  56 
  57 /**
  58  * ath5k_hw_num_tx_pending() - Get number of pending frames for a  given queue
  59  * @ah: The &struct ath5k_hw
  60  * @queue: One of enum ath5k_tx_queue_id
  61  */
  62 u32
  63 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
  64 {
  65         u32 pending;
  66         AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
  67 
  68         /* Return if queue is declared inactive */
  69         if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
  70                 return false;
  71 
  72         /* XXX: How about AR5K_CFG_TXCNT ? */
  73         if (ah->ah_version == AR5K_AR5210)
  74                 return false;
  75 
  76         pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
  77         pending &= AR5K_QCU_STS_FRMPENDCNT;
  78 
  79         /* It's possible to have no frames pending even if TXE
  80          * is set. To indicate that q has not stopped return
  81          * true */
  82         if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
  83                 return true;
  84 
  85         return pending;
  86 }
  87 
  88 /**
  89  * ath5k_hw_release_tx_queue() - Set a transmit queue inactive
  90  * @ah: The &struct ath5k_hw
  91  * @queue: One of enum ath5k_tx_queue_id
  92  */
  93 void
  94 ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
  95 {
  96         if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
  97                 return;
  98 
  99         /* This queue will be skipped in further operations */
 100         ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
 101         /*For SIMR setup*/
 102         AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
 103 }
 104 
 105 /**
 106  * ath5k_cw_validate() - Make sure the given cw is valid
 107  * @cw_req: The contention window value to check
 108  *
 109  * Make sure cw is a power of 2 minus 1 and smaller than 1024
 110  */
 111 static u16
 112 ath5k_cw_validate(u16 cw_req)
 113 {
 114         cw_req = min(cw_req, (u16)1023);
 115 
 116         /* Check if cw_req + 1 a power of 2 */
 117         if (is_power_of_2(cw_req + 1))
 118                 return cw_req;
 119 
 120         /* Check if cw_req is a power of 2 */
 121         if (is_power_of_2(cw_req))
 122                 return cw_req - 1;
 123 
 124         /* If none of the above is correct
 125          * find the closest power of 2 */
 126         cw_req = (u16) roundup_pow_of_two(cw_req) - 1;
 127 
 128         return cw_req;
 129 }
 130 
 131 /**
 132  * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue
 133  * @ah: The &struct ath5k_hw
 134  * @queue: One of enum ath5k_tx_queue_id
 135  * @queue_info: The &struct ath5k_txq_info to fill
 136  */
 137 int
 138 ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
 139                 struct ath5k_txq_info *queue_info)
 140 {
 141         memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
 142         return 0;
 143 }
 144 
 145 /**
 146  * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue
 147  * @ah: The &struct ath5k_hw
 148  * @queue: One of enum ath5k_tx_queue_id
 149  * @qinfo: The &struct ath5k_txq_info to use
 150  *
 151  * Returns 0 on success or -EIO if queue is inactive
 152  */
 153 int
 154 ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
 155                                 const struct ath5k_txq_info *qinfo)
 156 {
 157         struct ath5k_txq_info *qi;
 158 
 159         AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 160 
 161         qi = &ah->ah_txq[queue];
 162 
 163         if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
 164                 return -EIO;
 165 
 166         /* copy and validate values */
 167         qi->tqi_type = qinfo->tqi_type;
 168         qi->tqi_subtype = qinfo->tqi_subtype;
 169         qi->tqi_flags = qinfo->tqi_flags;
 170         /*
 171          * According to the docs: Although the AIFS field is 8 bit wide,
 172          * the maximum supported value is 0xFC. Setting it higher than that
 173          * will cause the DCU to hang.
 174          */
 175         qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
 176         qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
 177         qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
 178         qi->tqi_cbr_period = qinfo->tqi_cbr_period;
 179         qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
 180         qi->tqi_burst_time = qinfo->tqi_burst_time;
 181         qi->tqi_ready_time = qinfo->tqi_ready_time;
 182 
 183         /*XXX: Is this supported on 5210 ?*/
 184         /*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
 185         if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
 186                 ((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
 187                  (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
 188              qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
 189                 qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
 190 
 191         return 0;
 192 }
 193 
 194 /**
 195  * ath5k_hw_setup_tx_queue() - Initialize a transmit queue
 196  * @ah: The &struct ath5k_hw
 197  * @queue_type: One of enum ath5k_tx_queue
 198  * @queue_info: The &struct ath5k_txq_info to use
 199  *
 200  * Returns 0 on success, -EINVAL on invalid arguments
 201  */
 202 int
 203 ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
 204                 struct ath5k_txq_info *queue_info)
 205 {
 206         unsigned int queue;
 207         int ret;
 208 
 209         /*
 210          * Get queue by type
 211          */
 212         /* 5210 only has 2 queues */
 213         if (ah->ah_capabilities.cap_queues.q_tx_num == 2) {
 214                 switch (queue_type) {
 215                 case AR5K_TX_QUEUE_DATA:
 216                         queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
 217                         break;
 218                 case AR5K_TX_QUEUE_BEACON:
 219                 case AR5K_TX_QUEUE_CAB:
 220                         queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
 221                         break;
 222                 default:
 223                         return -EINVAL;
 224                 }
 225         } else {
 226                 switch (queue_type) {
 227                 case AR5K_TX_QUEUE_DATA:
 228                         queue = queue_info->tqi_subtype;
 229                         break;
 230                 case AR5K_TX_QUEUE_UAPSD:
 231                         queue = AR5K_TX_QUEUE_ID_UAPSD;
 232                         break;
 233                 case AR5K_TX_QUEUE_BEACON:
 234                         queue = AR5K_TX_QUEUE_ID_BEACON;
 235                         break;
 236                 case AR5K_TX_QUEUE_CAB:
 237                         queue = AR5K_TX_QUEUE_ID_CAB;
 238                         break;
 239                 default:
 240                         return -EINVAL;
 241                 }
 242         }
 243 
 244         /*
 245          * Setup internal queue structure
 246          */
 247         memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
 248         ah->ah_txq[queue].tqi_type = queue_type;
 249 
 250         if (queue_info != NULL) {
 251                 queue_info->tqi_type = queue_type;
 252                 ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
 253                 if (ret)
 254                         return ret;
 255         }
 256 
 257         /*
 258          * We use ah_txq_status to hold a temp value for
 259          * the Secondary interrupt mask registers on 5211+
 260          * check out ath5k_hw_reset_tx_queue
 261          */
 262         AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
 263 
 264         return queue;
 265 }
 266 
 267 
 268 /*******************************\
 269 * Single QCU/DCU initialization *
 270 \*******************************/
 271 
 272 /**
 273  * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU
 274  * @ah: The &struct ath5k_hw
 275  * @queue: One of enum ath5k_tx_queue_id
 276  *
 277  * This function is used when initializing a queue, to set
 278  * retry limits based on ah->ah_retry_* and the chipset used.
 279  */
 280 void
 281 ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
 282                                   unsigned int queue)
 283 {
 284         /* Single data queue on AR5210 */
 285         if (ah->ah_version == AR5K_AR5210) {
 286                 struct ath5k_txq_info *tq = &ah->ah_txq[queue];
 287 
 288                 if (queue > 0)
 289                         return;
 290 
 291                 ath5k_hw_reg_write(ah,
 292                         (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
 293                         | AR5K_REG_SM(ah->ah_retry_long,
 294                                       AR5K_NODCU_RETRY_LMT_SLG_RETRY)
 295                         | AR5K_REG_SM(ah->ah_retry_short,
 296                                       AR5K_NODCU_RETRY_LMT_SSH_RETRY)
 297                         | AR5K_REG_SM(ah->ah_retry_long,
 298                                       AR5K_NODCU_RETRY_LMT_LG_RETRY)
 299                         | AR5K_REG_SM(ah->ah_retry_short,
 300                                       AR5K_NODCU_RETRY_LMT_SH_RETRY),
 301                         AR5K_NODCU_RETRY_LMT);
 302         /* DCU on AR5211+ */
 303         } else {
 304                 ath5k_hw_reg_write(ah,
 305                         AR5K_REG_SM(ah->ah_retry_long,
 306                                     AR5K_DCU_RETRY_LMT_RTS)
 307                         | AR5K_REG_SM(ah->ah_retry_long,
 308                                       AR5K_DCU_RETRY_LMT_STA_RTS)
 309                         | AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short),
 310                                       AR5K_DCU_RETRY_LMT_STA_DATA),
 311                         AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
 312         }
 313 }
 314 
 315 /**
 316  * ath5k_hw_reset_tx_queue() - Initialize a single hw queue
 317  * @ah: The &struct ath5k_hw
 318  * @queue: One of enum ath5k_tx_queue_id
 319  *
 320  * Set DCF properties for the given transmit queue on DCU
 321  * and configures all queue-specific parameters.
 322  */
 323 int
 324 ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 325 {
 326         struct ath5k_txq_info *tq = &ah->ah_txq[queue];
 327 
 328         AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 329 
 330         /* Skip if queue inactive or if we are on AR5210
 331          * that doesn't have QCU/DCU */
 332         if ((ah->ah_version == AR5K_AR5210) ||
 333         (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE))
 334                 return 0;
 335 
 336         /*
 337          * Set contention window (cw_min/cw_max)
 338          * and arbitrated interframe space (aifs)...
 339          */
 340         ath5k_hw_reg_write(ah,
 341                 AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
 342                 AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
 343                 AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
 344                 AR5K_QUEUE_DFS_LOCAL_IFS(queue));
 345 
 346         /*
 347          * Set tx retry limits for this queue
 348          */
 349         ath5k_hw_set_tx_retry_limits(ah, queue);
 350 
 351 
 352         /*
 353          * Set misc registers
 354          */
 355 
 356         /* Enable DCU to wait for next fragment from QCU */
 357         AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
 358                                 AR5K_DCU_MISC_FRAG_WAIT);
 359 
 360         /* On Maui and Spirit use the global seqnum on DCU */
 361         if (ah->ah_mac_version < AR5K_SREV_AR5211)
 362                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
 363                                         AR5K_DCU_MISC_SEQNUM_CTL);
 364 
 365         /* Constant bit rate period */
 366         if (tq->tqi_cbr_period) {
 367                 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
 368                                         AR5K_QCU_CBRCFG_INTVAL) |
 369                                         AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
 370                                         AR5K_QCU_CBRCFG_ORN_THRES),
 371                                         AR5K_QUEUE_CBRCFG(queue));
 372 
 373                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
 374                                         AR5K_QCU_MISC_FRSHED_CBR);
 375 
 376                 if (tq->tqi_cbr_overflow_limit)
 377                         AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
 378                                         AR5K_QCU_MISC_CBR_THRES_ENABLE);
 379         }
 380 
 381         /* Ready time interval */
 382         if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB))
 383                 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
 384                                         AR5K_QCU_RDYTIMECFG_INTVAL) |
 385                                         AR5K_QCU_RDYTIMECFG_ENABLE,
 386                                         AR5K_QUEUE_RDYTIMECFG(queue));
 387 
 388         if (tq->tqi_burst_time) {
 389                 ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
 390                                         AR5K_DCU_CHAN_TIME_DUR) |
 391                                         AR5K_DCU_CHAN_TIME_ENABLE,
 392                                         AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
 393 
 394                 if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
 395                         AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
 396                                         AR5K_QCU_MISC_RDY_VEOL_POLICY);
 397         }
 398 
 399         /* Enable/disable Post frame backoff */
 400         if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
 401                 ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
 402                                         AR5K_QUEUE_DFS_MISC(queue));
 403 
 404         /* Enable/disable fragmentation burst backoff */
 405         if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
 406                 ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
 407                                         AR5K_QUEUE_DFS_MISC(queue));
 408 
 409         /*
 410          * Set registers by queue type
 411          */
 412         switch (tq->tqi_type) {
 413         case AR5K_TX_QUEUE_BEACON:
 414                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
 415                                 AR5K_QCU_MISC_FRSHED_DBA_GT |
 416                                 AR5K_QCU_MISC_CBREXP_BCN_DIS |
 417                                 AR5K_QCU_MISC_BCN_ENABLE);
 418 
 419                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
 420                                 (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
 421                                 AR5K_DCU_MISC_ARBLOCK_CTL_S) |
 422                                 AR5K_DCU_MISC_ARBLOCK_IGNORE |
 423                                 AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
 424                                 AR5K_DCU_MISC_BCN_ENABLE);
 425                 break;
 426 
 427         case AR5K_TX_QUEUE_CAB:
 428                 /* XXX: use BCN_SENT_GT, if we can figure out how */
 429                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
 430                                         AR5K_QCU_MISC_FRSHED_DBA_GT |
 431                                         AR5K_QCU_MISC_CBREXP_DIS |
 432                                         AR5K_QCU_MISC_CBREXP_BCN_DIS);
 433 
 434                 ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
 435                                         (AR5K_TUNE_SW_BEACON_RESP -
 436                                         AR5K_TUNE_DMA_BEACON_RESP) -
 437                                 AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
 438                                         AR5K_QCU_RDYTIMECFG_ENABLE,
 439                                         AR5K_QUEUE_RDYTIMECFG(queue));
 440 
 441                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
 442                                         (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
 443                                         AR5K_DCU_MISC_ARBLOCK_CTL_S));
 444                 break;
 445 
 446         case AR5K_TX_QUEUE_UAPSD:
 447                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
 448                                         AR5K_QCU_MISC_CBREXP_DIS);
 449                 break;
 450 
 451         case AR5K_TX_QUEUE_DATA:
 452         default:
 453                         break;
 454         }
 455 
 456         /* TODO: Handle frame compression */
 457 
 458         /*
 459          * Enable interrupts for this tx queue
 460          * in the secondary interrupt mask registers
 461          */
 462         if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
 463                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
 464 
 465         if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
 466                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
 467 
 468         if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
 469                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
 470 
 471         if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
 472                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
 473 
 474         if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
 475                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
 476 
 477         if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
 478                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
 479 
 480         if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
 481                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
 482 
 483         if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
 484                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
 485 
 486         if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
 487                 AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
 488 
 489         /* Update secondary interrupt mask registers */
 490 
 491         /* Filter out inactive queues */
 492         ah->ah_txq_imr_txok &= ah->ah_txq_status;
 493         ah->ah_txq_imr_txerr &= ah->ah_txq_status;
 494         ah->ah_txq_imr_txurn &= ah->ah_txq_status;
 495         ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
 496         ah->ah_txq_imr_txeol &= ah->ah_txq_status;
 497         ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
 498         ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
 499         ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
 500         ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
 501 
 502         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
 503                                         AR5K_SIMR0_QCU_TXOK) |
 504                                         AR5K_REG_SM(ah->ah_txq_imr_txdesc,
 505                                         AR5K_SIMR0_QCU_TXDESC),
 506                                         AR5K_SIMR0);
 507 
 508         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
 509                                         AR5K_SIMR1_QCU_TXERR) |
 510                                         AR5K_REG_SM(ah->ah_txq_imr_txeol,
 511                                         AR5K_SIMR1_QCU_TXEOL),
 512                                         AR5K_SIMR1);
 513 
 514         /* Update SIMR2 but don't overwrite rest simr2 settings */
 515         AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
 516         AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
 517                                 AR5K_REG_SM(ah->ah_txq_imr_txurn,
 518                                 AR5K_SIMR2_QCU_TXURN));
 519 
 520         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
 521                                 AR5K_SIMR3_QCBRORN) |
 522                                 AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
 523                                 AR5K_SIMR3_QCBRURN),
 524                                 AR5K_SIMR3);
 525 
 526         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
 527                                 AR5K_SIMR4_QTRIG), AR5K_SIMR4);
 528 
 529         /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
 530         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
 531                                 AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
 532 
 533         /* No queue has TXNOFRM enabled, disable the interrupt
 534          * by setting AR5K_TXNOFRM to zero */
 535         if (ah->ah_txq_imr_nofrm == 0)
 536                 ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
 537 
 538         /* Set QCU mask for this DCU to save power */
 539         AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
 540 
 541         return 0;
 542 }
 543 
 544 
 545 /**************************\
 546 * Global QCU/DCU functions *
 547 \**************************/
 548 
 549 /**
 550  * ath5k_hw_set_ifs_intervals()  - Set global inter-frame spaces on DCU
 551  * @ah: The &struct ath5k_hw
 552  * @slot_time: Slot time in us
 553  *
 554  * Sets the global IFS intervals on DCU (also works on AR5210) for
 555  * the given slot time and the current bwmode.
 556  */
 557 int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
 558 {
 559         struct ieee80211_channel *channel = ah->ah_current_channel;
 560         enum nl80211_band band;
 561         struct ieee80211_supported_band *sband;
 562         struct ieee80211_rate *rate;
 563         u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
 564         u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
 565         u32 rate_flags, i;
 566 
 567         if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
 568                 return -EINVAL;
 569 
 570         sifs = ath5k_hw_get_default_sifs(ah);
 571         sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
 572 
 573         /* EIFS
 574          * Txtime of ack at lowest rate + SIFS + DIFS
 575          * (DIFS = SIFS + 2 * Slot time)
 576          *
 577          * Note: HAL has some predefined values for EIFS
 578          * Turbo:   (37 + 2 * 6)
 579          * Default: (74 + 2 * 9)
 580          * Half:    (149 + 2 * 13)
 581          * Quarter: (298 + 2 * 21)
 582          *
 583          * (74 + 2 * 6) for AR5210 default and turbo !
 584          *
 585          * According to the formula we have
 586          * ack_tx_time = 25 for turbo and
 587          * ack_tx_time = 42.5 * clock multiplier
 588          * for default/half/quarter.
 589          *
 590          * This can't be right, 42 is what we would get
 591          * from ath5k_hw_get_frame_dur_for_bwmode or
 592          * ieee80211_generic_frame_duration for zero frame
 593          * length and without SIFS !
 594          *
 595          * Also we have different lowest rate for 802.11a
 596          */
 597         if (channel->band == NL80211_BAND_5GHZ)
 598                 band = NL80211_BAND_5GHZ;
 599         else
 600                 band = NL80211_BAND_2GHZ;
 601 
 602         switch (ah->ah_bwmode) {
 603         case AR5K_BWMODE_5MHZ:
 604                 rate_flags = IEEE80211_RATE_SUPPORTS_5MHZ;
 605                 break;
 606         case AR5K_BWMODE_10MHZ:
 607                 rate_flags = IEEE80211_RATE_SUPPORTS_10MHZ;
 608                 break;
 609         default:
 610                 rate_flags = 0;
 611                 break;
 612         }
 613         sband = &ah->sbands[band];
 614         rate = NULL;
 615         for (i = 0; i < sband->n_bitrates; i++) {
 616                 if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
 617                         continue;
 618                 rate = &sband->bitrates[i];
 619                 break;
 620         }
 621         if (WARN_ON(!rate))
 622                 return -EINVAL;
 623 
 624         ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false);
 625 
 626         /* ack_tx_time includes an SIFS already */
 627         eifs = ack_tx_time + sifs + 2 * slot_time;
 628         eifs_clock = ath5k_hw_htoclock(ah, eifs);
 629 
 630         /* Set IFS settings on AR5210 */
 631         if (ah->ah_version == AR5K_AR5210) {
 632                 u32 pifs, pifs_clock, difs, difs_clock;
 633 
 634                 /* Set slot time */
 635                 ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
 636 
 637                 /* Set EIFS */
 638                 eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS);
 639 
 640                 /* PIFS = Slot time + SIFS */
 641                 pifs = slot_time + sifs;
 642                 pifs_clock = ath5k_hw_htoclock(ah, pifs);
 643                 pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS);
 644 
 645                 /* DIFS = SIFS + 2 * Slot time */
 646                 difs = sifs + 2 * slot_time;
 647                 difs_clock = ath5k_hw_htoclock(ah, difs);
 648 
 649                 /* Set SIFS/DIFS */
 650                 ath5k_hw_reg_write(ah, (difs_clock <<
 651                                 AR5K_IFS0_DIFS_S) | sifs_clock,
 652                                 AR5K_IFS0);
 653 
 654                 /* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */
 655                 ath5k_hw_reg_write(ah, pifs_clock | eifs_clock |
 656                                 (AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S),
 657                                 AR5K_IFS1);
 658 
 659                 return 0;
 660         }
 661 
 662         /* Set IFS slot time */
 663         ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
 664 
 665         /* Set EIFS interval */
 666         ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS);
 667 
 668         /* Set SIFS interval in usecs */
 669         AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
 670                                 AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC,
 671                                 sifs);
 672 
 673         /* Set SIFS interval in clock cycles */
 674         ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS);
 675 
 676         return 0;
 677 }
 678 
 679 
 680 /**
 681  * ath5k_hw_init_queues() - Initialize tx queues
 682  * @ah: The &struct ath5k_hw
 683  *
 684  * Initializes all tx queues based on information on
 685  * ah->ah_txq* set by the driver
 686  */
 687 int
 688 ath5k_hw_init_queues(struct ath5k_hw *ah)
 689 {
 690         int i, ret;
 691 
 692         /* TODO: HW Compression support for data queues */
 693         /* TODO: Burst prefetch for data queues */
 694 
 695         /*
 696          * Reset queues and start beacon timers at the end of the reset routine
 697          * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
 698          * Note: If we want we can assign multiple qcus on one dcu.
 699          */
 700         if (ah->ah_version != AR5K_AR5210)
 701                 for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
 702                         ret = ath5k_hw_reset_tx_queue(ah, i);
 703                         if (ret) {
 704                                 ATH5K_ERR(ah,
 705                                         "failed to reset TX queue #%d\n", i);
 706                                 return ret;
 707                         }
 708                 }
 709         else
 710                 /* No QCU/DCU on AR5210, just set tx
 711                  * retry limits. We set IFS parameters
 712                  * on ath5k_hw_set_ifs_intervals */
 713                 ath5k_hw_set_tx_retry_limits(ah, 0);
 714 
 715         /* Set the turbo flag when operating on 40MHz */
 716         if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
 717                 AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
 718                                 AR5K_DCU_GBL_IFS_MISC_TURBO_MODE);
 719 
 720         /* If we didn't set IFS timings through
 721          * ath5k_hw_set_coverage_class make sure
 722          * we set them here */
 723         if (!ah->ah_coverage_class) {
 724                 unsigned int slot_time = ath5k_hw_get_default_slottime(ah);
 725                 ath5k_hw_set_ifs_intervals(ah, slot_time);
 726         }
 727 
 728         return 0;
 729 }

/* [<][>][^][v][top][bottom][index][help] */