iPXE
ath5k_qcu.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
00003  * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
00004  *
00005  * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
00006  *
00007  * Permission to use, copy, modify, and distribute this software for any
00008  * purpose with or without fee is hereby granted, provided that the above
00009  * copyright notice and this permission notice appear in all copies.
00010  *
00011  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00012  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00013  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00014  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00015  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00016  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00017  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00018  *
00019  */
00020 
00021 FILE_LICENCE ( MIT );
00022 
00023 /********************************************\
00024 Queue Control Unit, DFS Control Unit Functions
00025 \********************************************/
00026 
00027 #include "ath5k.h"
00028 #include "reg.h"
00029 #include "base.h"
00030 
00031 /*
00032  * Set properties for a transmit queue
00033  */
00034 int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah,
00035                                 const struct ath5k_txq_info *queue_info)
00036 {
00037         if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
00038                 return -EIO;
00039 
00040         memcpy(&ah->ah_txq, queue_info, sizeof(struct ath5k_txq_info));
00041 
00042         /*XXX: Is this supported on 5210 ?*/
00043         if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
00044                         ((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
00045                         (queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
00046                         queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
00047                 ah->ah_txq.tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
00048 
00049         return 0;
00050 }
00051 
00052 /*
00053  * Initialize a transmit queue
00054  */
00055 int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
00056                 struct ath5k_txq_info *queue_info)
00057 {
00058         int ret;
00059 
00060         /*
00061          * Setup internal queue structure
00062          */
00063         memset(&ah->ah_txq, 0, sizeof(struct ath5k_txq_info));
00064         ah->ah_txq.tqi_type = queue_type;
00065 
00066         if (queue_info != NULL) {
00067                 queue_info->tqi_type = queue_type;
00068                 ret = ath5k_hw_set_tx_queueprops(ah, queue_info);
00069                 if (ret)
00070                         return ret;
00071         }
00072 
00073         /*
00074          * We use ah_txq_status to hold a temp value for
00075          * the Secondary interrupt mask registers on 5211+
00076          * check out ath5k_hw_reset_tx_queue
00077          */
00078         AR5K_Q_ENABLE_BITS(ah->ah_txq_status, 0);
00079 
00080         return 0;
00081 }
00082 
00083 /*
00084  * Set a transmit queue inactive
00085  */
00086 void ath5k_hw_release_tx_queue(struct ath5k_hw *ah)
00087 {
00088         /* This queue will be skipped in further operations */
00089         ah->ah_txq.tqi_type = AR5K_TX_QUEUE_INACTIVE;
00090         /*For SIMR setup*/
00091         AR5K_Q_DISABLE_BITS(ah->ah_txq_status, 0);
00092 }
00093 
00094 /*
00095  * Set DFS properties for a transmit queue on DCU
00096  */
00097 int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah)
00098 {
00099         u32 cw_min, cw_max, retry_lg, retry_sh;
00100         struct ath5k_txq_info *tq = &ah->ah_txq;
00101         const int queue = 0;
00102 
00103         tq = &ah->ah_txq;
00104 
00105         if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
00106                 return 0;
00107 
00108         if (ah->ah_version == AR5K_AR5210) {
00109                 /* Only handle data queues, others will be ignored */
00110                 if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
00111                         return 0;
00112 
00113                 /* Set Slot time */
00114                 ath5k_hw_reg_write(ah, ah->ah_turbo ?
00115                         AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
00116                         AR5K_SLOT_TIME);
00117                 /* Set ACK_CTS timeout */
00118                 ath5k_hw_reg_write(ah, ah->ah_turbo ?
00119                         AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
00120                         AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
00121                 /* Set Transmit Latency */
00122                 ath5k_hw_reg_write(ah, ah->ah_turbo ?
00123                         AR5K_INIT_TRANSMIT_LATENCY_TURBO :
00124                         AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
00125 
00126                 /* Set IFS0 */
00127                 if (ah->ah_turbo) {
00128                          ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
00129                                 (ah->ah_aifs + tq->tqi_aifs) *
00130                                 AR5K_INIT_SLOT_TIME_TURBO) <<
00131                                 AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
00132                                 AR5K_IFS0);
00133                 } else {
00134                         ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
00135                                 (ah->ah_aifs + tq->tqi_aifs) *
00136                                 AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
00137                                 AR5K_INIT_SIFS, AR5K_IFS0);
00138                 }
00139 
00140                 /* Set IFS1 */
00141                 ath5k_hw_reg_write(ah, ah->ah_turbo ?
00142                         AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
00143                         AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
00144                 /* Set AR5K_PHY_SETTLING */
00145                 ath5k_hw_reg_write(ah, ah->ah_turbo ?
00146                         (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
00147                         | 0x38 :
00148                         (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
00149                         | 0x1C,
00150                         AR5K_PHY_SETTLING);
00151                 /* Set Frame Control Register */
00152                 ath5k_hw_reg_write(ah, ah->ah_turbo ?
00153                         (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
00154                         AR5K_PHY_TURBO_SHORT | 0x2020) :
00155                         (AR5K_PHY_FRAME_CTL_INI | 0x1020),
00156                         AR5K_PHY_FRAME_CTL_5210);
00157         }
00158 
00159         /*
00160          * Calculate cwmin/max by channel mode
00161          */
00162         cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
00163         cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
00164         ah->ah_aifs = AR5K_TUNE_AIFS;
00165         /*XR is only supported on 5212*/
00166         if (IS_CHAN_XR(ah->ah_current_channel) &&
00167                         ah->ah_version == AR5K_AR5212) {
00168                 cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
00169                 cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
00170                 ah->ah_aifs = AR5K_TUNE_AIFS_XR;
00171         /*B mode is not supported on 5210*/
00172         } else if (IS_CHAN_B(ah->ah_current_channel) &&
00173                         ah->ah_version != AR5K_AR5210) {
00174                 cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
00175                 cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
00176                 ah->ah_aifs = AR5K_TUNE_AIFS_11B;
00177         }
00178 
00179         cw_min = 1;
00180         while (cw_min < ah->ah_cw_min)
00181                 cw_min = (cw_min << 1) | 1;
00182 
00183         cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
00184                 ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
00185         cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
00186                 ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
00187 
00188         /*
00189          * Calculate and set retry limits
00190          */
00191         if (ah->ah_software_retry) {
00192                 /* XXX Need to test this */
00193                 retry_lg = ah->ah_limit_tx_retries;
00194                 retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
00195                         AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
00196         } else {
00197                 retry_lg = AR5K_INIT_LG_RETRY;
00198                 retry_sh = AR5K_INIT_SH_RETRY;
00199         }
00200 
00201         /*No QCU/DCU [5210]*/
00202         if (ah->ah_version == AR5K_AR5210) {
00203                 ath5k_hw_reg_write(ah,
00204                         (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
00205                         | AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
00206                                 AR5K_NODCU_RETRY_LMT_SLG_RETRY)
00207                         | AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
00208                                 AR5K_NODCU_RETRY_LMT_SSH_RETRY)
00209                         | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
00210                         | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
00211                         AR5K_NODCU_RETRY_LMT);
00212         } else {
00213                 /*QCU/DCU [5211+]*/
00214                 ath5k_hw_reg_write(ah,
00215                         AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
00216                                 AR5K_DCU_RETRY_LMT_SLG_RETRY) |
00217                         AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
00218                                 AR5K_DCU_RETRY_LMT_SSH_RETRY) |
00219                         AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
00220                         AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
00221                         AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
00222 
00223         /*===Rest is also for QCU/DCU only [5211+]===*/
00224 
00225                 /*
00226                  * Set initial content window (cw_min/cw_max)
00227                  * and arbitrated interframe space (aifs)...
00228                  */
00229                 ath5k_hw_reg_write(ah,
00230                         AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
00231                         AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
00232                         AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
00233                                 AR5K_DCU_LCL_IFS_AIFS),
00234                         AR5K_QUEUE_DFS_LOCAL_IFS(queue));
00235 
00236                 /*
00237                  * Set misc registers
00238                  */
00239                 /* Enable DCU early termination for this queue */
00240                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
00241                                         AR5K_QCU_MISC_DCU_EARLY);
00242 
00243                 /* Enable DCU to wait for next fragment from QCU */
00244                 AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
00245                                         AR5K_DCU_MISC_FRAG_WAIT);
00246 
00247                 /* On Maui and Spirit use the global seqnum on DCU */
00248                 if (ah->ah_mac_version < AR5K_SREV_AR5211)
00249                         AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
00250                                                 AR5K_DCU_MISC_SEQNUM_CTL);
00251 
00252                 if (tq->tqi_cbr_period) {
00253                         ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
00254                                 AR5K_QCU_CBRCFG_INTVAL) |
00255                                 AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
00256                                 AR5K_QCU_CBRCFG_ORN_THRES),
00257                                 AR5K_QUEUE_CBRCFG(queue));
00258                         AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
00259                                 AR5K_QCU_MISC_FRSHED_CBR);
00260                         if (tq->tqi_cbr_overflow_limit)
00261                                 AR5K_REG_ENABLE_BITS(ah,
00262                                         AR5K_QUEUE_MISC(queue),
00263                                         AR5K_QCU_MISC_CBR_THRES_ENABLE);
00264                 }
00265 
00266                 if (tq->tqi_ready_time &&
00267                 (tq->tqi_type != AR5K_TX_QUEUE_CAB))
00268                         ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
00269                                 AR5K_QCU_RDYTIMECFG_INTVAL) |
00270                                 AR5K_QCU_RDYTIMECFG_ENABLE,
00271                                 AR5K_QUEUE_RDYTIMECFG(queue));
00272 
00273                 if (tq->tqi_burst_time) {
00274                         ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
00275                                 AR5K_DCU_CHAN_TIME_DUR) |
00276                                 AR5K_DCU_CHAN_TIME_ENABLE,
00277                                 AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
00278 
00279                         if (tq->tqi_flags
00280                         & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
00281                                 AR5K_REG_ENABLE_BITS(ah,
00282                                         AR5K_QUEUE_MISC(queue),
00283                                         AR5K_QCU_MISC_RDY_VEOL_POLICY);
00284                 }
00285 
00286                 if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
00287                         ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
00288                                 AR5K_QUEUE_DFS_MISC(queue));
00289 
00290                 if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
00291                         ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
00292                                 AR5K_QUEUE_DFS_MISC(queue));
00293 
00294                 /* TODO: Handle frame compression */
00295 
00296                 /*
00297                  * Enable interrupts for this tx queue
00298                  * in the secondary interrupt mask registers
00299                  */
00300                 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
00301                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
00302 
00303                 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
00304                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
00305 
00306                 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
00307                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
00308 
00309                 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
00310                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
00311 
00312                 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
00313                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
00314 
00315                 if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
00316                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
00317 
00318                 if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
00319                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
00320 
00321                 if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
00322                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
00323 
00324                 if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
00325                         AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
00326 
00327                 /* Update secondary interrupt mask registers */
00328 
00329                 /* Filter out inactive queues */
00330                 ah->ah_txq_imr_txok &= ah->ah_txq_status;
00331                 ah->ah_txq_imr_txerr &= ah->ah_txq_status;
00332                 ah->ah_txq_imr_txurn &= ah->ah_txq_status;
00333                 ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
00334                 ah->ah_txq_imr_txeol &= ah->ah_txq_status;
00335                 ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
00336                 ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
00337                 ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
00338                 ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
00339 
00340                 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
00341                         AR5K_SIMR0_QCU_TXOK) |
00342                         AR5K_REG_SM(ah->ah_txq_imr_txdesc,
00343                         AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
00344                 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
00345                         AR5K_SIMR1_QCU_TXERR) |
00346                         AR5K_REG_SM(ah->ah_txq_imr_txeol,
00347                         AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
00348                 /* Update simr2 but don't overwrite rest simr2 settings */
00349                 AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
00350                 AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
00351                         AR5K_REG_SM(ah->ah_txq_imr_txurn,
00352                         AR5K_SIMR2_QCU_TXURN));
00353                 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
00354                         AR5K_SIMR3_QCBRORN) |
00355                         AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
00356                         AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
00357                 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
00358                         AR5K_SIMR4_QTRIG), AR5K_SIMR4);
00359                 /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
00360                 ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
00361                         AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
00362                 /* No queue has TXNOFRM enabled, disable the interrupt
00363                  * by setting AR5K_TXNOFRM to zero */
00364                 if (ah->ah_txq_imr_nofrm == 0)
00365                         ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
00366 
00367                 /* Set QCU mask for this DCU to save power */
00368                 AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
00369         }
00370 
00371         return 0;
00372 }
00373 
00374 /*
00375  * Set slot time on DCU
00376  */
00377 int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
00378 {
00379         if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
00380                 return -EINVAL;
00381 
00382         if (ah->ah_version == AR5K_AR5210)
00383                 ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
00384                                 ah->ah_turbo), AR5K_SLOT_TIME);
00385         else
00386                 ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
00387 
00388         return 0;
00389 }
00390