iPXE
ath5k_dma.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 * DMA and interrupt masking functions *
00025 \*************************************/
00026 
00027 /*
00028  * dma.c - DMA and interrupt masking functions
00029  *
00030  * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
00031  * handle queue setup for 5210 chipset (rest are handled on qcu.c).
00032  * Also we setup interrupt mask register (IMR) and read the various iterrupt
00033  * status registers (ISR).
00034  *
00035  * TODO: Handle SISR on 5211+ and introduce a function to return the queue
00036  * number that resulted the interrupt.
00037  */
00038 
00039 #include <unistd.h>
00040 
00041 #include "ath5k.h"
00042 #include "reg.h"
00043 #include "base.h"
00044 
00045 /*********\
00046 * Receive *
00047 \*********/
00048 
00049 /**
00050  * ath5k_hw_start_rx_dma - Start DMA receive
00051  *
00052  * @ah: The &struct ath5k_hw
00053  */
00054 void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
00055 {
00056         ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
00057         ath5k_hw_reg_read(ah, AR5K_CR);
00058 }
00059 
00060 /**
00061  * ath5k_hw_stop_rx_dma - Stop DMA receive
00062  *
00063  * @ah: The &struct ath5k_hw
00064  */
00065 int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
00066 {
00067         unsigned int i;
00068 
00069         ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
00070 
00071         /*
00072          * It may take some time to disable the DMA receive unit
00073          */
00074         for (i = 1000; i > 0 &&
00075                         (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
00076                         i--)
00077                 udelay(10);
00078 
00079         return i ? 0 : -EBUSY;
00080 }
00081 
00082 /**
00083  * ath5k_hw_get_rxdp - Get RX Descriptor's address
00084  *
00085  * @ah: The &struct ath5k_hw
00086  *
00087  * XXX: Is RXDP read and clear ?
00088  */
00089 u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
00090 {
00091         return ath5k_hw_reg_read(ah, AR5K_RXDP);
00092 }
00093 
00094 /**
00095  * ath5k_hw_set_rxdp - Set RX Descriptor's address
00096  *
00097  * @ah: The &struct ath5k_hw
00098  * @phys_addr: RX descriptor address
00099  *
00100  * XXX: Should we check if rx is enabled before setting rxdp ?
00101  */
00102 void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
00103 {
00104         ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
00105 }
00106 
00107 
00108 /**********\
00109 * Transmit *
00110 \**********/
00111 
00112 /**
00113  * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
00114  *
00115  * @ah: The &struct ath5k_hw
00116  * @queue: The hw queue number
00117  *
00118  * Start DMA transmit for a specific queue and since 5210 doesn't have
00119  * QCU/DCU, set up queue parameters for 5210 here based on queue type (one
00120  * queue for normal data and one queue for beacons). For queue setup
00121  * on newer chips check out qcu.c. Returns -EINVAL if queue number is out
00122  * of range or if queue is already disabled.
00123  *
00124  * NOTE: Must be called after setting up tx control descriptor for that
00125  * queue (see below).
00126  */
00127 int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
00128 {
00129         u32 tx_queue;
00130 
00131         /* Return if queue is declared inactive */
00132         if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
00133                 return -EIO;
00134 
00135         if (ah->ah_version == AR5K_AR5210) {
00136                 tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
00137 
00138                 /* Assume always a data queue */
00139                 tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
00140 
00141                 /* Start queue */
00142                 ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
00143                 ath5k_hw_reg_read(ah, AR5K_CR);
00144         } else {
00145                 /* Return if queue is disabled */
00146                 if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
00147                         return -EIO;
00148 
00149                 /* Start queue */
00150                 AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
00151         }
00152 
00153         return 0;
00154 }
00155 
00156 /**
00157  * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
00158  *
00159  * @ah: The &struct ath5k_hw
00160  * @queue: The hw queue number
00161  *
00162  * Stop DMA transmit on a specific hw queue and drain queue so we don't
00163  * have any pending frames. Returns -EBUSY if we still have pending frames,
00164  * -EINVAL if queue number is out of range.
00165  *
00166  */
00167 int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
00168 {
00169         unsigned int i = 40;
00170         u32 tx_queue, pending;
00171 
00172         /* Return if queue is declared inactive */
00173         if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
00174                 return -EIO;
00175 
00176         if (ah->ah_version == AR5K_AR5210) {
00177                 tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
00178 
00179                 /* Assume a data queue */
00180                 tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
00181 
00182                 /* Stop queue */
00183                 ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
00184                 ath5k_hw_reg_read(ah, AR5K_CR);
00185         } else {
00186                 /*
00187                  * Schedule TX disable and wait until queue is empty
00188                  */
00189                 AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
00190 
00191                 /*Check for pending frames*/
00192                 do {
00193                         pending = ath5k_hw_reg_read(ah,
00194                                 AR5K_QUEUE_STATUS(queue)) &
00195                                 AR5K_QCU_STS_FRMPENDCNT;
00196                         udelay(100);
00197                 } while (--i && pending);
00198 
00199                 /* For 2413+ order PCU to drop packets using
00200                  * QUIET mechanism */
00201                 if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && pending) {
00202                         /* Set periodicity and duration */
00203                         ath5k_hw_reg_write(ah,
00204                                 AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
00205                                 AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
00206                                 AR5K_QUIET_CTL2);
00207 
00208                         /* Enable quiet period for current TSF */
00209                         ath5k_hw_reg_write(ah,
00210                                 AR5K_QUIET_CTL1_QT_EN |
00211                                 AR5K_REG_SM(ath5k_hw_reg_read(ah,
00212                                                 AR5K_TSF_L32_5211) >> 10,
00213                                                 AR5K_QUIET_CTL1_NEXT_QT_TSF),
00214                                 AR5K_QUIET_CTL1);
00215 
00216                         /* Force channel idle high */
00217                         AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
00218                                         AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
00219 
00220                         /* Wait a while and disable mechanism */
00221                         udelay(200);
00222                         AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
00223                                                 AR5K_QUIET_CTL1_QT_EN);
00224 
00225                         /* Re-check for pending frames */
00226                         i = 40;
00227                         do {
00228                                 pending = ath5k_hw_reg_read(ah,
00229                                         AR5K_QUEUE_STATUS(queue)) &
00230                                         AR5K_QCU_STS_FRMPENDCNT;
00231                                 udelay(100);
00232                         } while (--i && pending);
00233 
00234                         AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
00235                                         AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
00236                 }
00237 
00238                 /* Clear register */
00239                 ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
00240                 if (pending)
00241                         return -EBUSY;
00242         }
00243 
00244         /* TODO: Check for success on 5210 else return error */
00245         return 0;
00246 }
00247 
00248 /**
00249  * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
00250  *
00251  * @ah: The &struct ath5k_hw
00252  * @queue: The hw queue number
00253  *
00254  * Get TX descriptor's address for a specific queue. For 5210 we ignore
00255  * the queue number and use tx queue type since we only have 2 queues.
00256  * We use TXDP0 for normal data queue and TXDP1 for beacon queue.
00257  * For newer chips with QCU/DCU we just read the corresponding TXDP register.
00258  *
00259  * XXX: Is TXDP read and clear ?
00260  */
00261 u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
00262 {
00263         u16 tx_reg;
00264 
00265         /*
00266          * Get the transmit queue descriptor pointer from the selected queue
00267          */
00268         /*5210 doesn't have QCU*/
00269         if (ah->ah_version == AR5K_AR5210) {
00270                 /* Assume a data queue */
00271                 tx_reg = AR5K_NOQCU_TXDP0;
00272         } else {
00273                 tx_reg = AR5K_QUEUE_TXDP(queue);
00274         }
00275 
00276         return ath5k_hw_reg_read(ah, tx_reg);
00277 }
00278 
00279 /**
00280  * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
00281  *
00282  * @ah: The &struct ath5k_hw
00283  * @queue: The hw queue number
00284  *
00285  * Set TX descriptor's address for a specific queue. For 5210 we ignore
00286  * the queue number and we use tx queue type since we only have 2 queues
00287  * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
00288  * For newer chips with QCU/DCU we just set the corresponding TXDP register.
00289  * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
00290  * active.
00291  */
00292 int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
00293 {
00294         u16 tx_reg;
00295 
00296         /*
00297          * Set the transmit queue descriptor pointer register by type
00298          * on 5210
00299          */
00300         if (ah->ah_version == AR5K_AR5210) {
00301                 /* Assume a data queue */
00302                 tx_reg = AR5K_NOQCU_TXDP0;
00303         } else {
00304                 /*
00305                  * Set the transmit queue descriptor pointer for
00306                  * the selected queue on QCU for 5211+
00307                  * (this won't work if the queue is still active)
00308                  */
00309                 if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
00310                         return -EIO;
00311 
00312                 tx_reg = AR5K_QUEUE_TXDP(queue);
00313         }
00314 
00315         /* Set descriptor pointer */
00316         ath5k_hw_reg_write(ah, phys_addr, tx_reg);
00317 
00318         return 0;
00319 }
00320 
00321 /**
00322  * ath5k_hw_update_tx_triglevel - Update tx trigger level
00323  *
00324  * @ah: The &struct ath5k_hw
00325  * @increase: Flag to force increase of trigger level
00326  *
00327  * This function increases/decreases the tx trigger level for the tx fifo
00328  * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
00329  * the buffer and transmits it's data. Lowering this results sending small
00330  * frames more quickly but can lead to tx underruns, raising it a lot can
00331  * result other problems (i think bmiss is related). Right now we start with
00332  * the lowest possible (64Bytes) and if we get tx underrun we increase it using
00333  * the increase flag. Returns -EIO if we have have reached maximum/minimum.
00334  *
00335  * XXX: Link this with tx DMA size ?
00336  * XXX: Use it to save interrupts ?
00337  * TODO: Needs testing, i think it's related to bmiss...
00338  */
00339 int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase)
00340 {
00341         u32 trigger_level, imr;
00342         int ret = -EIO;
00343 
00344         /*
00345          * Disable interrupts by setting the mask
00346          */
00347         imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
00348 
00349         trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
00350                         AR5K_TXCFG_TXFULL);
00351 
00352         if (!increase) {
00353                 if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
00354                         goto done;
00355         } else
00356                 trigger_level +=
00357                         ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
00358 
00359         /*
00360          * Update trigger level on success
00361          */
00362         if (ah->ah_version == AR5K_AR5210)
00363                 ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
00364         else
00365                 AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
00366                                 AR5K_TXCFG_TXFULL, trigger_level);
00367 
00368         ret = 0;
00369 
00370 done:
00371         /*
00372          * Restore interrupt mask
00373          */
00374         ath5k_hw_set_imr(ah, imr);
00375 
00376         return ret;
00377 }
00378 
00379 /*******************\
00380 * Interrupt masking *
00381 \*******************/
00382 
00383 /**
00384  * ath5k_hw_is_intr_pending - Check if we have pending interrupts
00385  *
00386  * @ah: The &struct ath5k_hw
00387  *
00388  * Check if we have pending interrupts to process. Returns 1 if we
00389  * have pending interrupts and 0 if we haven't.
00390  */
00391 int ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
00392 {
00393         return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
00394 }
00395 
00396 /**
00397  * ath5k_hw_get_isr - Get interrupt status
00398  *
00399  * @ah: The @struct ath5k_hw
00400  * @interrupt_mask: Driver's interrupt mask used to filter out
00401  * interrupts in sw.
00402  *
00403  * This function is used inside our interrupt handler to determine the reason
00404  * for the interrupt by reading Primary Interrupt Status Register. Returns an
00405  * abstract interrupt status mask which is mostly ISR with some uncommon bits
00406  * being mapped on some standard non hw-specific positions
00407  * (check out &ath5k_int).
00408  *
00409  * NOTE: We use read-and-clear register, so after this function is called ISR
00410  * is zeroed.
00411  */
00412 int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
00413 {
00414         u32 data;
00415 
00416         /*
00417          * Read interrupt status from the Interrupt Status register
00418          * on 5210
00419          */
00420         if (ah->ah_version == AR5K_AR5210) {
00421                 data = ath5k_hw_reg_read(ah, AR5K_ISR);
00422                 if (data == AR5K_INT_NOCARD) {
00423                         *interrupt_mask = data;
00424                         return -ENODEV;
00425                 }
00426         } else {
00427                 /*
00428                  * Read interrupt status from Interrupt
00429                  * Status Register shadow copy (Read And Clear)
00430                  *
00431                  * Note: PISR/SISR Not available on 5210
00432                  */
00433                 data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
00434                 if (data == AR5K_INT_NOCARD) {
00435                         *interrupt_mask = data;
00436                         return -ENODEV;
00437                 }
00438         }
00439 
00440         /*
00441          * Get abstract interrupt mask (driver-compatible)
00442          */
00443         *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
00444 
00445         if (ah->ah_version != AR5K_AR5210) {
00446                 u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
00447 
00448                 /*HIU = Host Interface Unit (PCI etc)*/
00449                 if (data & (AR5K_ISR_HIUERR))
00450                         *interrupt_mask |= AR5K_INT_FATAL;
00451 
00452                 /*Beacon Not Ready*/
00453                 if (data & (AR5K_ISR_BNR))
00454                         *interrupt_mask |= AR5K_INT_BNR;
00455 
00456                 if (sisr2 & (AR5K_SISR2_SSERR | AR5K_SISR2_DPERR |
00457                              AR5K_SISR2_MCABT))
00458                         *interrupt_mask |= AR5K_INT_FATAL;
00459 
00460                 if (data & AR5K_ISR_TIM)
00461                         *interrupt_mask |= AR5K_INT_TIM;
00462 
00463                 if (data & AR5K_ISR_BCNMISC) {
00464                         if (sisr2 & AR5K_SISR2_TIM)
00465                                 *interrupt_mask |= AR5K_INT_TIM;
00466                         if (sisr2 & AR5K_SISR2_DTIM)
00467                                 *interrupt_mask |= AR5K_INT_DTIM;
00468                         if (sisr2 & AR5K_SISR2_DTIM_SYNC)
00469                                 *interrupt_mask |= AR5K_INT_DTIM_SYNC;
00470                         if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
00471                                 *interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
00472                         if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
00473                                 *interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
00474                 }
00475 
00476                 if (data & AR5K_ISR_RXDOPPLER)
00477                         *interrupt_mask |= AR5K_INT_RX_DOPPLER;
00478                 if (data & AR5K_ISR_QCBRORN) {
00479                         *interrupt_mask |= AR5K_INT_QCBRORN;
00480                         ah->ah_txq_isr |= AR5K_REG_MS(
00481                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
00482                                         AR5K_SISR3_QCBRORN);
00483                 }
00484                 if (data & AR5K_ISR_QCBRURN) {
00485                         *interrupt_mask |= AR5K_INT_QCBRURN;
00486                         ah->ah_txq_isr |= AR5K_REG_MS(
00487                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
00488                                         AR5K_SISR3_QCBRURN);
00489                 }
00490                 if (data & AR5K_ISR_QTRIG) {
00491                         *interrupt_mask |= AR5K_INT_QTRIG;
00492                         ah->ah_txq_isr |= AR5K_REG_MS(
00493                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
00494                                         AR5K_SISR4_QTRIG);
00495                 }
00496 
00497                 if (data & AR5K_ISR_TXOK)
00498                         ah->ah_txq_isr |= AR5K_REG_MS(
00499                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
00500                                         AR5K_SISR0_QCU_TXOK);
00501 
00502                 if (data & AR5K_ISR_TXDESC)
00503                         ah->ah_txq_isr |= AR5K_REG_MS(
00504                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
00505                                         AR5K_SISR0_QCU_TXDESC);
00506 
00507                 if (data & AR5K_ISR_TXERR)
00508                         ah->ah_txq_isr |= AR5K_REG_MS(
00509                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
00510                                         AR5K_SISR1_QCU_TXERR);
00511 
00512                 if (data & AR5K_ISR_TXEOL)
00513                         ah->ah_txq_isr |= AR5K_REG_MS(
00514                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
00515                                         AR5K_SISR1_QCU_TXEOL);
00516 
00517                 if (data & AR5K_ISR_TXURN)
00518                         ah->ah_txq_isr |= AR5K_REG_MS(
00519                                         ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
00520                                         AR5K_SISR2_QCU_TXURN);
00521         } else {
00522                 if (data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT |
00523                             AR5K_ISR_HIUERR | AR5K_ISR_DPERR))
00524                         *interrupt_mask |= AR5K_INT_FATAL;
00525 
00526                 /*
00527                  * XXX: BMISS interrupts may occur after association.
00528                  * I found this on 5210 code but it needs testing. If this is
00529                  * true we should disable them before assoc and re-enable them
00530                  * after a successful assoc + some jiffies.
00531                         interrupt_mask &= ~AR5K_INT_BMISS;
00532                  */
00533         }
00534 
00535         return 0;
00536 }
00537 
00538 /**
00539  * ath5k_hw_set_imr - Set interrupt mask
00540  *
00541  * @ah: The &struct ath5k_hw
00542  * @new_mask: The new interrupt mask to be set
00543  *
00544  * Set the interrupt mask in hw to save interrupts. We do that by mapping
00545  * ath5k_int bits to hw-specific bits to remove abstraction and writing
00546  * Interrupt Mask Register.
00547  */
00548 enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
00549 {
00550         enum ath5k_int old_mask, int_mask;
00551 
00552         old_mask = ah->ah_imr;
00553 
00554         /*
00555          * Disable card interrupts to prevent any race conditions
00556          * (they will be re-enabled afterwards if AR5K_INT GLOBAL
00557          * is set again on the new mask).
00558          */
00559         if (old_mask & AR5K_INT_GLOBAL) {
00560                 ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
00561                 ath5k_hw_reg_read(ah, AR5K_IER);
00562         }
00563 
00564         /*
00565          * Add additional, chipset-dependent interrupt mask flags
00566          * and write them to the IMR (interrupt mask register).
00567          */
00568         int_mask = new_mask & AR5K_INT_COMMON;
00569 
00570         if (ah->ah_version != AR5K_AR5210) {
00571                 /* Preserve per queue TXURN interrupt mask */
00572                 u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
00573                                 & AR5K_SIMR2_QCU_TXURN;
00574 
00575                 if (new_mask & AR5K_INT_FATAL) {
00576                         int_mask |= AR5K_IMR_HIUERR;
00577                         simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
00578                                 | AR5K_SIMR2_DPERR);
00579                 }
00580 
00581                 /*Beacon Not Ready*/
00582                 if (new_mask & AR5K_INT_BNR)
00583                         int_mask |= AR5K_INT_BNR;
00584 
00585                 if (new_mask & AR5K_INT_TIM)
00586                         int_mask |= AR5K_IMR_TIM;
00587 
00588                 if (new_mask & AR5K_INT_TIM)
00589                         simr2 |= AR5K_SISR2_TIM;
00590                 if (new_mask & AR5K_INT_DTIM)
00591                         simr2 |= AR5K_SISR2_DTIM;
00592                 if (new_mask & AR5K_INT_DTIM_SYNC)
00593                         simr2 |= AR5K_SISR2_DTIM_SYNC;
00594                 if (new_mask & AR5K_INT_BCN_TIMEOUT)
00595                         simr2 |= AR5K_SISR2_BCN_TIMEOUT;
00596                 if (new_mask & AR5K_INT_CAB_TIMEOUT)
00597                         simr2 |= AR5K_SISR2_CAB_TIMEOUT;
00598 
00599                 if (new_mask & AR5K_INT_RX_DOPPLER)
00600                         int_mask |= AR5K_IMR_RXDOPPLER;
00601 
00602                 /* Note: Per queue interrupt masks
00603                  * are set via reset_tx_queue (qcu.c) */
00604                 ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
00605                 ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
00606 
00607         } else {
00608                 if (new_mask & AR5K_INT_FATAL)
00609                         int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
00610                                 | AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
00611 
00612                 ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
00613         }
00614 
00615         /* If RXNOFRM interrupt is masked disable it
00616          * by setting AR5K_RXNOFRM to zero */
00617         if (!(new_mask & AR5K_INT_RXNOFRM))
00618                 ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
00619 
00620         /* Store new interrupt mask */
00621         ah->ah_imr = new_mask;
00622 
00623         /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
00624         if (new_mask & AR5K_INT_GLOBAL) {
00625                 ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
00626                 ath5k_hw_reg_read(ah, AR5K_IER);
00627         }
00628 
00629         return old_mask;
00630 }
00631