176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Lightly modified for gPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>. 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Permission to use, copy, modify, and distribute this software for any 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * purpose with or without fee is hereby granted, provided that the above 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * copyright notice and this permission notice appear in all copies. 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( MIT ); 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*************************************\ 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* DMA and interrupt masking functions * 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\*************************************/ 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * dma.c - DMA and interrupt masking functions 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * handle queue setup for 5210 chipset (rest are handled on qcu.c). 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Also we setup interrupt mask register (IMR) and read the various iterrupt 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * status registers (ISR). 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TODO: Handle SISR on 5211+ and introduce a function to return the queue 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number that resulted the interrupt. 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h> 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "ath5k.h" 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "reg.h" 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "base.h" 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*********\ 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* Receive * 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\*********/ 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_start_rx_dma - Start DMA receive 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid ath5k_hw_start_rx_dma(struct ath5k_hw *ah) 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_CR); 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_stop_rx_dma - Stop DMA receive 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It may take some time to disable the DMA receive unit 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 1000; i > 0 && 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i--) 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(10); 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return i ? 0 : -EBUSY; 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_get_rxdp - Get RX Descriptor's address 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Is RXDP read and clear ? 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanu32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ath5k_hw_reg_read(ah, AR5K_RXDP); 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_set_rxdp - Set RX Descriptor's address 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @phys_addr: RX descriptor address 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Should we check if rx is enabled before setting rxdp ? 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**********\ 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* Transmit * 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\**********/ 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @queue: The hw queue number 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Start DMA transmit for a specific queue and since 5210 doesn't have 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * QCU/DCU, set up queue parameters for 5210 here based on queue type (one 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * queue for normal data and one queue for beacons). For queue setup 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * on newer chips check out qcu.c. Returns -EINVAL if queue number is out 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of range or if queue is already disabled. 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * NOTE: Must be called after setting up tx control descriptor for that 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * queue (see below). 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 tx_queue; 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Return if queue is declared inactive */ 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE) 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) { 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assume always a data queue */ 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Start queue */ 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_CR); 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Return if queue is disabled */ 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Start queue */ 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @queue: The hw queue number 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Stop DMA transmit on a specific hw queue and drain queue so we don't 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * have any pending frames. Returns -EBUSY if we still have pending frames, 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * -EINVAL if queue number is out of range. 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i = 40; 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 tx_queue, pending; 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Return if queue is declared inactive */ 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE) 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) { 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assume a data queue */ 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Stop queue */ 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_CR); 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Schedule TX disable and wait until queue is empty 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /*Check for pending frames*/ 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pending = ath5k_hw_reg_read(ah, 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUEUE_STATUS(queue)) & 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QCU_STS_FRMPENDCNT; 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(100); 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (--i && pending); 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For 2413+ order PCU to drop packets using 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * QUIET mechanism */ 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && pending) { 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set periodicity and duration */ 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)| 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR), 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUIET_CTL2); 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable quiet period for current TSF */ 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUIET_CTL1_QT_EN | 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_SM(ath5k_hw_reg_read(ah, 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TSF_L32_5211) >> 10, 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUIET_CTL1_NEXT_QT_TSF), 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUIET_CTL1); 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Force channel idle high */ 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_DIAG_SW_CHANEL_IDLE_HIGH); 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Wait a while and disable mechanism */ 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(200); 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1, 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUIET_CTL1_QT_EN); 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Re-check for pending frames */ 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i = 40; 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pending = ath5k_hw_reg_read(ah, 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QUEUE_STATUS(queue)) & 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_QCU_STS_FRMPENDCNT; 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(100); 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (--i && pending); 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_DIAG_SW_CHANEL_IDLE_HIGH); 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear register */ 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pending) 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EBUSY; 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TODO: Check for success on 5210 else return error */ 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @queue: The hw queue number 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get TX descriptor's address for a specific queue. For 5210 we ignore 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the queue number and use tx queue type since we only have 2 queues. 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We use TXDP0 for normal data queue and TXDP1 for beacon queue. 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For newer chips with QCU/DCU we just read the corresponding TXDP register. 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Is TXDP read and clear ? 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanu32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 tx_reg; 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get the transmit queue descriptor pointer from the selected queue 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /*5210 doesn't have QCU*/ 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) { 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assume a data queue */ 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_reg = AR5K_NOQCU_TXDP0; 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_reg = AR5K_QUEUE_TXDP(queue); 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ath5k_hw_reg_read(ah, tx_reg); 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @queue: The hw queue number 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set TX descriptor's address for a specific queue. For 5210 we ignore 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the queue number and we use tx queue type since we only have 2 queues 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue. 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For newer chips with QCU/DCU we just set the corresponding TXDP register. 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * active. 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 tx_reg; 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the transmit queue descriptor pointer register by type 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * on 5210 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) { 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Assume a data queue */ 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_reg = AR5K_NOQCU_TXDP0; 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the transmit queue descriptor pointer for 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the selected queue on QCU for 5211+ 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (this won't work if the queue is still active) 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman tx_reg = AR5K_QUEUE_TXDP(queue); 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set descriptor pointer */ 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, phys_addr, tx_reg); 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_update_tx_triglevel - Update tx trigger level 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @increase: Flag to force increase of trigger level 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function increases/decreases the tx trigger level for the tx fifo 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * buffer (aka FIFO threshold) that is used to indicate when PCU flushes 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the buffer and transmits it's data. Lowering this results sending small 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * frames more quickly but can lead to tx underruns, raising it a lot can 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * result other problems (i think bmiss is related). Right now we start with 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the lowest possible (64Bytes) and if we get tx underrun we increase it using 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the increase flag. Returns -EIO if we have have reached maximum/minimum. 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Link this with tx DMA size ? 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: Use it to save interrupts ? 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * TODO: Needs testing, i think it's related to bmiss... 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase) 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 trigger_level, imr; 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret = -EIO; 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Disable interrupts by setting the mask 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXCFG_TXFULL); 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!increase) { 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman trigger_level += 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Update trigger level on success 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_TXCFG_TXFULL, trigger_level); 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = 0; 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Restore interrupt mask 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_set_imr(ah, imr); 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*******************\ 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman* Interrupt masking * 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman\*******************/ 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_is_intr_pending - Check if we have pending interrupts 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Check if we have pending interrupts to process. Returns 1 if we 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * have pending interrupts and 0 if we haven't. 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_is_intr_pending(struct ath5k_hw *ah) 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0; 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_get_isr - Get interrupt status 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The @struct ath5k_hw 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @interrupt_mask: Driver's interrupt mask used to filter out 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * interrupts in sw. 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function is used inside our interrupt handler to determine the reason 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for the interrupt by reading Primary Interrupt Status Register. Returns an 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * abstract interrupt status mask which is mostly ISR with some uncommon bits 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * being mapped on some standard non hw-specific positions 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (check out &ath5k_int). 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * NOTE: We use read-and-clear register, so after this function is called ISR 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is zeroed. 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 data; 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Read interrupt status from the Interrupt Status register 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * on 5210 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version == AR5K_AR5210) { 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = ath5k_hw_reg_read(ah, AR5K_ISR); 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data == AR5K_INT_NOCARD) { 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask = data; 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENODEV; 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Read interrupt status from Interrupt 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Status Register shadow copy (Read And Clear) 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: PISR/SISR Not available on 5210 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data == AR5K_INT_NOCARD) { 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask = data; 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENODEV; 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get abstract interrupt mask (driver-compatible) 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version != AR5K_AR5210) { 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /*HIU = Host Interface Unit (PCI etc)*/ 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & (AR5K_ISR_HIUERR)) 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_FATAL; 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /*Beacon Not Ready*/ 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & (AR5K_ISR_BNR)) 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_BNR; 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sisr2 & (AR5K_SISR2_SSERR | AR5K_SISR2_DPERR | 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR2_MCABT)) 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_FATAL; 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_TIM) 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_TIM; 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_BCNMISC) { 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sisr2 & AR5K_SISR2_TIM) 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_TIM; 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sisr2 & AR5K_SISR2_DTIM) 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_DTIM; 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sisr2 & AR5K_SISR2_DTIM_SYNC) 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_DTIM_SYNC; 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sisr2 & AR5K_SISR2_BCN_TIMEOUT) 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_BCN_TIMEOUT; 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sisr2 & AR5K_SISR2_CAB_TIMEOUT) 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_RXDOPPLER) 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_RX_DOPPLER; 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_QCBRORN) { 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_QCBRORN; 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR3_QCBRORN); 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_QCBRURN) { 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_QCBRURN; 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR3_QCBRURN); 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_QTRIG) { 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_QTRIG; 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR4_QTRIG); 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_TXOK) 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR0_QCU_TXOK); 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_TXDESC) 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR0_QCU_TXDESC); 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_TXERR) 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR1_QCU_TXERR); 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_TXEOL) 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR1_QCU_TXEOL); 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & AR5K_ISR_TXURN) 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_txq_isr |= AR5K_REG_MS( 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_SISR2_QCU_TXURN); 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT | 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman AR5K_ISR_HIUERR | AR5K_ISR_DPERR)) 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *interrupt_mask |= AR5K_INT_FATAL; 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XXX: BMISS interrupts may occur after association. 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I found this on 5210 code but it needs testing. If this is 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * true we should disable them before assoc and re-enable them 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * after a successful assoc + some jiffies. 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman interrupt_mask &= ~AR5K_INT_BMISS; 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_hw_set_imr - Set interrupt mask 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ah: The &struct ath5k_hw 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @new_mask: The new interrupt mask to be set 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set the interrupt mask in hw to save interrupts. We do that by mapping 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ath5k_int bits to hw-specific bits to remove abstraction and writing 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Interrupt Mask Register. 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman enum ath5k_int old_mask, int_mask; 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman old_mask = ah->ah_imr; 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Disable card interrupts to prevent any race conditions 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (they will be re-enabled afterwards if AR5K_INT GLOBAL 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is set again on the new mask). 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (old_mask & AR5K_INT_GLOBAL) { 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_IER); 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Add additional, chipset-dependent interrupt mask flags 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and write them to the IMR (interrupt mask register). 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int_mask = new_mask & AR5K_INT_COMMON; 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ah->ah_version != AR5K_AR5210) { 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Preserve per queue TXURN interrupt mask */ 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & AR5K_SIMR2_QCU_TXURN; 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_FATAL) { 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int_mask |= AR5K_IMR_HIUERR; 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | AR5K_SIMR2_DPERR); 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /*Beacon Not Ready*/ 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_BNR) 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int_mask |= AR5K_INT_BNR; 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_TIM) 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int_mask |= AR5K_IMR_TIM; 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_TIM) 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman simr2 |= AR5K_SISR2_TIM; 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_DTIM) 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman simr2 |= AR5K_SISR2_DTIM; 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_DTIM_SYNC) 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman simr2 |= AR5K_SISR2_DTIM_SYNC; 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_BCN_TIMEOUT) 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman simr2 |= AR5K_SISR2_BCN_TIMEOUT; 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_CAB_TIMEOUT) 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman simr2 |= AR5K_SISR2_CAB_TIMEOUT; 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_RX_DOPPLER) 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int_mask |= AR5K_IMR_RXDOPPLER; 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Note: Per queue interrupt masks 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are set via reset_tx_queue (qcu.c) */ 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_FATAL) 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If RXNOFRM interrupt is masked disable it 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * by setting AR5K_RXNOFRM to zero */ 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(new_mask & AR5K_INT_RXNOFRM)) 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM); 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Store new interrupt mask */ 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ah->ah_imr = new_mask; 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */ 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (new_mask & AR5K_INT_GLOBAL) { 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER); 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ath5k_hw_reg_read(ah, AR5K_IER); 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return old_mask; 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 632