ath5k_dma.c File Reference

#include <unistd.h>
#include "ath5k.h"
#include "reg.h"
#include "base.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (MIT)
void ath5k_hw_start_rx_dma (struct ath5k_hw *ah)
 ath5k_hw_start_rx_dma - Start DMA receive
int ath5k_hw_stop_rx_dma (struct ath5k_hw *ah)
 ath5k_hw_stop_rx_dma - Stop DMA receive
u32 ath5k_hw_get_rxdp (struct ath5k_hw *ah)
 ath5k_hw_get_rxdp - Get RX Descriptor's address
void ath5k_hw_set_rxdp (struct ath5k_hw *ah, u32 phys_addr)
 ath5k_hw_set_rxdp - Set RX Descriptor's address
int ath5k_hw_start_tx_dma (struct ath5k_hw *ah, unsigned int queue)
 ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
int ath5k_hw_stop_tx_dma (struct ath5k_hw *ah, unsigned int queue)
 ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
u32 ath5k_hw_get_txdp (struct ath5k_hw *ah, unsigned int queue)
 ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
int ath5k_hw_set_txdp (struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
 ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
int ath5k_hw_update_tx_triglevel (struct ath5k_hw *ah, int increase)
 ath5k_hw_update_tx_triglevel - Update tx trigger level
int ath5k_hw_is_intr_pending (struct ath5k_hw *ah)
 ath5k_hw_is_intr_pending - Check if we have pending interrupts
int ath5k_hw_get_isr (struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
enum ath5k_int ath5k_hw_set_imr (struct ath5k_hw *ah, enum ath5k_int new_mask)
 ath5k_hw_set_imr - Set interrupt mask


Function Documentation

FILE_LICENCE ( MIT   ) 

void ath5k_hw_start_rx_dma ( struct ath5k_hw ah  ) 

ath5k_hw_start_rx_dma - Start DMA receive

: The &struct ath5k_hw

Definition at line 54 of file ath5k_dma.c.

References AR5K_CR, AR5K_CR_RXE, ath5k_hw_reg_read(), and ath5k_hw_reg_write().

Referenced by ath5k_rx_start().

00055 {
00056         ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
00057         ath5k_hw_reg_read(ah, AR5K_CR);
00058 }

int ath5k_hw_stop_rx_dma ( struct ath5k_hw ah  ) 

ath5k_hw_stop_rx_dma - Stop DMA receive

: The &struct ath5k_hw

Definition at line 65 of file ath5k_dma.c.

References AR5K_CR, AR5K_CR_RXD, AR5K_CR_RXE, ath5k_hw_reg_read(), ath5k_hw_reg_write(), EBUSY, and udelay().

Referenced by ath5k_rx_stop().

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 }

u32 ath5k_hw_get_rxdp ( struct ath5k_hw ah  ) 

ath5k_hw_get_rxdp - Get RX Descriptor's address

: The &struct ath5k_hw

XXX: Is RXDP read and clear ?

Definition at line 89 of file ath5k_dma.c.

References AR5K_RXDP, and ath5k_hw_reg_read().

00090 {
00091         return ath5k_hw_reg_read(ah, AR5K_RXDP);
00092 }

void ath5k_hw_set_rxdp ( struct ath5k_hw ah,
u32  phys_addr 
)

ath5k_hw_set_rxdp - Set RX Descriptor's address

: The &struct ath5k_hw : RX descriptor address

XXX: Should we check if rx is enabled before setting rxdp ?

Definition at line 102 of file ath5k_dma.c.

References AR5K_RXDP, and ath5k_hw_reg_write().

Referenced by ath5k_rx_start().

00103 {
00104         ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
00105 }

int ath5k_hw_start_tx_dma ( struct ath5k_hw ah,
unsigned int  queue 
)

ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue

: The &struct ath5k_hw : The hw queue number

Start DMA transmit for a specific queue and since 5210 doesn't have QCU/DCU, set up queue parameters for 5210 here based on queue type (one queue for normal data and one queue for beacons). For queue setup on newer chips check out qcu.c. Returns -EINVAL if queue number is out of range or if queue is already disabled.

NOTE: Must be called after setting up tx control descriptor for that queue (see below).

Definition at line 127 of file ath5k_dma.c.

References ath5k_hw::ah_txq, ath5k_hw::ah_version, AR5K_AR5210, AR5K_CR, AR5K_CR_TXD0, AR5K_CR_TXE0, AR5K_QCU_TXD, AR5K_QCU_TXE, AR5K_REG_READ_Q, AR5K_REG_WRITE_Q, AR5K_TX_QUEUE_INACTIVE, ath5k_hw_reg_read(), ath5k_hw_reg_write(), EIO, ath5k_txq_info::tqi_type, and u32.

Referenced by ath5k_txbuf_setup().

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 }

int ath5k_hw_stop_tx_dma ( struct ath5k_hw ah,
unsigned int  queue 
)

ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue

: The &struct ath5k_hw : The hw queue number

Stop DMA transmit on a specific hw queue and drain queue so we don't have any pending frames. Returns -EBUSY if we still have pending frames, -EINVAL if queue number is out of range.

Definition at line 167 of file ath5k_dma.c.

References ath5k_hw::ah_mac_version, ath5k_hw::ah_txq, ath5k_hw::ah_version, AR5K_AR5210, AR5K_CR, AR5K_CR_TXD0, AR5K_CR_TXE0, AR5K_DIAG_SW_5211, AR5K_DIAG_SW_CHANEL_IDLE_HIGH, AR5K_QCU_STS_FRMPENDCNT, AR5K_QCU_TXD, AR5K_QUEUE_STATUS, AR5K_QUIET_CTL1, AR5K_QUIET_CTL1_NEXT_QT_TSF, AR5K_QUIET_CTL1_QT_EN, AR5K_QUIET_CTL2, AR5K_QUIET_CTL2_QT_DUR, AR5K_QUIET_CTL2_QT_PER, AR5K_REG_DISABLE_BITS, AR5K_REG_ENABLE_BITS, AR5K_REG_SM, AR5K_REG_WRITE_Q, AR5K_SREV_AR2414, AR5K_TSF_L32_5211, AR5K_TX_QUEUE_INACTIVE, ath5k_hw_reg_read(), ath5k_hw_reg_write(), EBUSY, EIO, ath5k_txq_info::tqi_type, u32, and udelay().

Referenced by ath5k_txq_cleanup().

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 }

u32 ath5k_hw_get_txdp ( struct ath5k_hw ah,
unsigned int  queue 
)

ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue

: The &struct ath5k_hw : The hw queue number

Get TX descriptor's address for a specific queue. For 5210 we ignore the queue number and use tx queue type since we only have 2 queues. We use TXDP0 for normal data queue and TXDP1 for beacon queue. For newer chips with QCU/DCU we just read the corresponding TXDP register.

XXX: Is TXDP read and clear ?

Definition at line 261 of file ath5k_dma.c.

References ath5k_hw::ah_version, AR5K_AR5210, AR5K_NOQCU_TXDP0, AR5K_QUEUE_TXDP, ath5k_hw_reg_read(), and u16.

Referenced by ath5k_txq_cleanup().

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 }

int ath5k_hw_set_txdp ( struct ath5k_hw ah,
unsigned int  queue,
u32  phys_addr 
)

ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue

: The &struct ath5k_hw : The hw queue number

Set TX descriptor's address for a specific queue. For 5210 we ignore the queue number and we use tx queue type since we only have 2 queues so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue. For newer chips with QCU/DCU we just set the corresponding TXDP register. Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still active.

Definition at line 292 of file ath5k_dma.c.

References ath5k_hw::ah_version, AR5K_AR5210, AR5K_NOQCU_TXDP0, AR5K_QCU_TXE, AR5K_QUEUE_TXDP, AR5K_REG_READ_Q, ath5k_hw_reg_write(), EIO, and u16.

Referenced by ath5k_txbuf_setup().

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 }

int ath5k_hw_update_tx_triglevel ( struct ath5k_hw ah,
int  increase 
)

ath5k_hw_update_tx_triglevel - Update tx trigger level

: The &struct ath5k_hw : Flag to force increase of trigger level

This function increases/decreases the tx trigger level for the tx fifo buffer (aka FIFO threshold) that is used to indicate when PCU flushes the buffer and transmits it's data. Lowering this results sending small frames more quickly but can lead to tx underruns, raising it a lot can result other problems (i think bmiss is related). Right now we start with the lowest possible (64Bytes) and if we get tx underrun we increase it using the increase flag. Returns -EIO if we have have reached maximum/minimum.

XXX: Link this with tx DMA size ? XXX: Use it to save interrupts ? TODO: Needs testing, i think it's related to bmiss...

Definition at line 339 of file ath5k_dma.c.

References ath5k_hw::ah_imr, ath5k_hw::ah_version, AR5K_AR5210, AR5K_INT_GLOBAL, AR5K_REG_MS, AR5K_REG_WRITE_BITS, AR5K_TRIG_LVL, AR5K_TUNE_MAX_TX_FIFO_THRES, AR5K_TUNE_MIN_TX_FIFO_THRES, AR5K_TXCFG, AR5K_TXCFG_TXFULL, ath5k_hw_reg_read(), ath5k_hw_reg_write(), ath5k_hw_set_imr(), EIO, imr, and u32.

Referenced by ath5k_poll().

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 }

int ath5k_hw_is_intr_pending ( struct ath5k_hw ah  ) 

ath5k_hw_is_intr_pending - Check if we have pending interrupts

: The &struct ath5k_hw

Check if we have pending interrupts to process. Returns 1 if we have pending interrupts and 0 if we haven't.

Definition at line 391 of file ath5k_dma.c.

References AR5K_INTPEND, and ath5k_hw_reg_read().

Referenced by ath5k_poll().

00392 {
00393         return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
00394 }

int ath5k_hw_get_isr ( struct ath5k_hw ah,
enum ath5k_int interrupt_mask 
)

Definition at line 412 of file ath5k_dma.c.

References ath5k_hw::ah_imr, ath5k_hw::ah_txq_isr, ath5k_hw::ah_version, AR5K_AR5210, AR5K_INT_BCN_TIMEOUT, AR5K_INT_BNR, AR5K_INT_CAB_TIMEOUT, AR5K_INT_COMMON, AR5K_INT_DTIM, AR5K_INT_DTIM_SYNC, AR5K_INT_FATAL, AR5K_INT_NOCARD, AR5K_INT_QCBRORN, AR5K_INT_QCBRURN, AR5K_INT_QTRIG, AR5K_INT_RX_DOPPLER, AR5K_INT_TIM, AR5K_ISR, AR5K_ISR_BCNMISC, AR5K_ISR_BNR, AR5K_ISR_DPERR, AR5K_ISR_HIUERR, AR5K_ISR_MCABT, AR5K_ISR_QCBRORN, AR5K_ISR_QCBRURN, AR5K_ISR_QTRIG, AR5K_ISR_RXDOPPLER, AR5K_ISR_SSERR, AR5K_ISR_TIM, AR5K_ISR_TXDESC, AR5K_ISR_TXEOL, AR5K_ISR_TXERR, AR5K_ISR_TXOK, AR5K_ISR_TXURN, AR5K_RAC_PISR, AR5K_RAC_SISR0, AR5K_RAC_SISR1, AR5K_RAC_SISR2, AR5K_RAC_SISR3, AR5K_RAC_SISR4, AR5K_REG_MS, AR5K_SISR0_QCU_TXDESC, AR5K_SISR0_QCU_TXOK, AR5K_SISR1_QCU_TXEOL, AR5K_SISR1_QCU_TXERR, AR5K_SISR2_BCN_TIMEOUT, AR5K_SISR2_CAB_TIMEOUT, AR5K_SISR2_DPERR, AR5K_SISR2_DTIM, AR5K_SISR2_DTIM_SYNC, AR5K_SISR2_MCABT, AR5K_SISR2_QCU_TXURN, AR5K_SISR2_SSERR, AR5K_SISR2_TIM, AR5K_SISR3_QCBRORN, AR5K_SISR3_QCBRURN, AR5K_SISR4_QTRIG, ath5k_hw_reg_read(), ENODEV, and u32.

Referenced by ath5k_poll().

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 }

enum ath5k_int ath5k_hw_set_imr ( struct ath5k_hw ah,
enum ath5k_int  new_mask 
)

ath5k_hw_set_imr - Set interrupt mask

: The &struct ath5k_hw : The new interrupt mask to be set

Set the interrupt mask in hw to save interrupts. We do that by mapping ath5k_int bits to hw-specific bits to remove abstraction and writing Interrupt Mask Register.

Definition at line 548 of file ath5k_dma.c.

References ath5k_hw::ah_ier, ath5k_hw::ah_imr, ath5k_hw::ah_version, AR5K_AR5210, AR5K_IER, AR5K_IER_DISABLE, AR5K_IMR, AR5K_IMR_DPERR, AR5K_IMR_HIUERR, AR5K_IMR_MCABT, AR5K_IMR_RXDOPPLER, AR5K_IMR_SSERR, AR5K_IMR_TIM, AR5K_INT_BCN_TIMEOUT, AR5K_INT_BNR, AR5K_INT_CAB_TIMEOUT, AR5K_INT_COMMON, AR5K_INT_DTIM, AR5K_INT_DTIM_SYNC, AR5K_INT_FATAL, AR5K_INT_GLOBAL, AR5K_INT_RX_DOPPLER, AR5K_INT_RXNOFRM, AR5K_INT_TIM, AR5K_PIMR, AR5K_RXNOFRM, AR5K_SIMR2, AR5K_SIMR2_DPERR, AR5K_SIMR2_MCABT, AR5K_SIMR2_QCU_TXURN, AR5K_SIMR2_SSERR, AR5K_SISR2_BCN_TIMEOUT, AR5K_SISR2_CAB_TIMEOUT, AR5K_SISR2_DTIM, AR5K_SISR2_DTIM_SYNC, AR5K_SISR2_TIM, ath5k_hw_reg_read(), ath5k_hw_reg_write(), and u32.

Referenced by ath5k_hw_reset(), ath5k_hw_update_tx_triglevel(), ath5k_irq(), ath5k_reset(), and ath5k_stop_hw().

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 }


Generated on Tue Apr 6 20:01:19 2010 for gPXE by  doxygen 1.5.7.1