iwl-trans-pcie-rx.c revision 247c61d625154e18a105d663281c52376a882762
1ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/****************************************************************************** 2ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 3ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. 4ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 5ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Portions of this file are derived from the ipw3945 project, as well 6ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * as portions of the ieee80211 subsystem header files. 7ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 8ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This program is free software; you can redistribute it and/or modify it 9ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * under the terms of version 2 of the GNU General Public License as 10ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * published by the Free Software Foundation. 11ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 12ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This program is distributed in the hope that it will be useful, but WITHOUT 13ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * more details. 16ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 17ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * You should have received a copy of the GNU General Public License along with 18ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * this program; if not, write to the Free Software Foundation, Inc., 19ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 20ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 21ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The full GNU General Public License is included in this distribution in the 22ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * file called LICENSE. 23ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 24ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Contact Information: 25ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Intel Linux Wireless <ilw@linux.intel.com> 26ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 28ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach *****************************************************************************/ 29ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#include <linux/sched.h> 30ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#include <linux/wait.h> 311a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#include <linux/gfp.h> 32ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 33522376d206da66cecc90929134ad70c0446e874bEmmanuel Grumbach/*TODO: Remove include to iwl-core.h*/ 34ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#include "iwl-core.h" 35ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#include "iwl-io.h" 36ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#include "iwl-helpers.h" 37c17d0681b8a4d93217464d8026361c7b44b3ca99Johannes Berg#include "iwl-trans-pcie-int.h" 38ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 39ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/****************************************************************************** 40ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 41ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * RX path functions 42ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 43ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach ******************************************************************************/ 44ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 45ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/* 46ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Rx theory of operation 47ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 48ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), 49ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * each of which point to Receive Buffers to be filled by the NIC. These get 50ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * used not only for Rx frames, but for any command response or notification 51ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * from the NIC. The driver and NIC manage the Rx buffers by means 52ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * of indexes into the circular buffer. 53ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 54ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Rx Queue Indexes 55ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The host/firmware share two index registers for managing the Rx buffers. 56ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 57ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The READ index maps to the first position that the firmware may be writing 58ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to -- the driver can read up to (but not including) this position and get 59ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * good data. 60ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The READ index is managed by the firmware once the card is enabled. 61ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 62ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The WRITE index maps to the last position the driver has read from -- the 63ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * position preceding WRITE is the last slot the firmware can place a packet. 64ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 65ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The queue is empty (no good data) if WRITE = READ - 1, and is full if 66ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * WRITE = READ. 67ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 68ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * During initialization, the host sets up the READ queue position to the first 69ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * INDEX position, and WRITE to the last (READ - 1 wrapped) 70ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 71ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * When the firmware places a packet in a buffer, it will advance the READ index 72ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * and fire the RX interrupt. The driver can then query the READ index and 73ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * process as many packets as possible, moving the WRITE index forward as it 74ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * resets the Rx queue buffers with new memory. 75ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 76ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The management in the driver is as follows: 77ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When 78ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled 79ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to replenish the iwl->rxq->rx_free. 80ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the 81ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl->rxq is replenished and the READ INDEX is updated (updating the 82ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 'processed' and 'read' driver indexes as well) 83ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + A received packet is processed and handed to the kernel network stack, 84ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * detached from the iwl->rxq. The driver 'processed' index is updated. 85ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free 86ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ 87ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there 88ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * were enough free buffers and RX_STALLED is set it is cleared. 89ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 90ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 91ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Driver sequence: 92ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 93ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_alloc() Allocates rx_free 94ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls 95ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_restock 96ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx 97ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * queue, updates firmware pointers, and updates 98ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the WRITE index. If insufficient rx_free buffers 99ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * are available, schedules iwl_rx_replenish 100ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 101ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * -- enable interrupts -- 102ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the 103ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * READ INDEX, detaching the SKB from the pool. 104ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Moves the packet buffer from queue to rx_used. 105ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Calls iwl_rx_queue_restock to refill any empty 106ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * slots. 107ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ... 108ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 109ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 110ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 111ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 112ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_space - Return number of free slots available in queue. 113ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 114ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbachstatic int iwl_rx_queue_space(const struct iwl_rx_queue *q) 115ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 116ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int s = q->read - q->write; 117ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (s <= 0) 118ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach s += RX_QUEUE_SIZE; 119ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* keep some buffer to not confuse full and empty queue */ 120ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach s -= 2; 121ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (s < 0) 122ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach s = 0; 123ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return s; 124ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 125ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 126ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 127ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue 128ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1295a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachvoid iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, 130ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_queue *q) 131ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 132ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 133ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 reg; 134ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 135ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&q->lock, flags); 136ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 137ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (q->need_update == 0) 138ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach goto exit_unlock; 139ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 140fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach if (hw_params(trans).shadow_reg_enable) { 141ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* shadow register enabled */ 142ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Device expects a multiple of 8 */ 143ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual = (q->write & ~0x7); 144fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_write32(bus(trans), FH_RSCSR_CHNL0_WPTR, q->write_actual); 145ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } else { 146ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If power-saving is in use, make sure device is awake */ 1475a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { 148fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); 149ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 150ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { 1515a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_INFO(trans, 152ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "Rx queue requesting wakeup," 153ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach " GP1 = 0x%x\n", reg); 154fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_set_bit(bus(trans), CSR_GP_CNTRL, 155ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 156ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach goto exit_unlock; 157ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 158ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 159ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual = (q->write & ~0x7); 160fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, 161ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual); 162ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 163ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Else device is assumed to be awake */ 164ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } else { 165ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Device expects a multiple of 8 */ 166ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual = (q->write & ~0x7); 167fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, 168ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual); 169ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 170ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 171ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->need_update = 0; 172ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 173ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach exit_unlock: 174ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&q->lock, flags); 175ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 176ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 177ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 178ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr 179ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1805a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) 181ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 182ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return cpu_to_le32((u32)(dma_addr >> 8)); 183ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 184ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 185ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 186ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool 187ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 188ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * If there are slots in the RX queue that need to be restocked, 189ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * and we have free pre-allocated buffers, fill the ranks as much 190ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * as we can, pulling from rx_free. 191ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 192ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This moves the 'write' index forward to catch up with 'processed', and 193ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * also updates the memory address in the firmware to reference the new 194ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * target buffer. 195ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1965a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwlagn_rx_queue_restock(struct iwl_trans *trans) 197ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 1985a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 1995a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 2005a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach 2015a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_rx_queue *rxq = &trans_pcie->rxq; 202ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct list_head *element; 203ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_mem_buffer *rxb; 204ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 205ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 206ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 207ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { 208ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* The overwritten rxb must be a used one */ 209ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = rxq->queue[rxq->write]; 210ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb && rxb->page); 211ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 212ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Get next free Rx buffer, remove from free list */ 213ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach element = rxq->rx_free.next; 214ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = list_entry(element, struct iwl_rx_mem_buffer, list); 215ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_del(element); 216ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 217ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Point to Rx buffer via next RBD in circular buffer */ 2185a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma); 219ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->queue[rxq->write] = rxb; 220ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; 221ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count--; 222ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 223ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 224ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If the pre-allocated buffer pool is dropping low, schedule to 225ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * refill it */ 226ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxq->free_count <= RX_LOW_WATERMARK) 2275a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); 228ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 229ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 230ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If we've added more space for the firmware to place data, tell it. 231ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Increment device's write pointer in multiples of 8. */ 232ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxq->write_actual != (rxq->write & ~0x7)) { 233ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 234ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->need_update = 1; 235ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 2365a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwl_rx_queue_update_write_ptr(trans, rxq); 237ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 238ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 239ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 240ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 241ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free 242ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 243ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * When moving to rx_free an SKB is allocated for the slot. 244ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 245ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Also restock the Rx queue via iwl_rx_queue_restock. 246ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This is called as a scheduled work item (except for during initialization) 247ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 2485a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) 249ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 2505a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 2515a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 2525a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach 2535a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_rx_queue *rxq = &trans_pcie->rxq; 254ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct list_head *element; 255ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_mem_buffer *rxb; 256ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct page *page; 257ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 258ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach gfp_t gfp_mask = priority; 259ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 260ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach while (1) { 261ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 262ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (list_empty(&rxq->rx_used)) { 263ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 264ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 265ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 266ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 267ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 268ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxq->free_count > RX_LOW_WATERMARK) 269ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach gfp_mask |= __GFP_NOWARN; 270ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 2715a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach if (hw_params(trans).rx_page_order > 0) 272ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach gfp_mask |= __GFP_COMP; 273ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 274ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Alloc a new receive buffer */ 275d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach page = alloc_pages(gfp_mask, 2765a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach hw_params(trans).rx_page_order); 277ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (!page) { 278ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (net_ratelimit()) 2795a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_INFO(trans, "alloc_pages failed, " 280d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach "order: %d\n", 2815a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach hw_params(trans).rx_page_order); 282ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 283ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if ((rxq->free_count <= RX_LOW_WATERMARK) && 284ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach net_ratelimit()) 2855a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_CRIT(trans, "Failed to alloc_pages with %s." 286ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "Only %u free buffers remaining.\n", 287ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach priority == GFP_ATOMIC ? 288ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "GFP_ATOMIC" : "GFP_KERNEL", 289ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count); 290ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* We don't reschedule replenish work here -- we will 291ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * call the restock method and if it still needs 292ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * more buffers it will schedule replenish */ 293ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 294ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 295ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 296ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 297ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 298ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (list_empty(&rxq->rx_used)) { 299ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 3005a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach __free_pages(page, hw_params(trans).rx_page_order); 301ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 302ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 303ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach element = rxq->rx_used.next; 304ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = list_entry(element, struct iwl_rx_mem_buffer, list); 305ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_del(element); 306ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 307ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 308ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 309ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb->page); 310ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb->page = page; 311ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Get physical address of the RB */ 3125a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach rxb->page_dma = dma_map_page(bus(trans)->dev, page, 0, 3135a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach PAGE_SIZE << hw_params(trans).rx_page_order, 314ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach DMA_FROM_DEVICE); 315ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* dma address must be no more than 36 bits */ 316ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); 317ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* and also 256 byte aligned! */ 318ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); 319ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 320ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 321ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 322ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_add_tail(&rxb->list, &rxq->rx_free); 323ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count++; 324ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 325ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 326ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 327ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 328ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3295a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachvoid iwlagn_rx_replenish(struct iwl_trans *trans) 330ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 331ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 332ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3335a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_allocate(trans, GFP_KERNEL); 334ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3355a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 3365a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_queue_restock(trans); 3375a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 338ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 339ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3405a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwlagn_rx_replenish_now(struct iwl_trans *trans) 341ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 3425a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_allocate(trans, GFP_ATOMIC); 343ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3445a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_queue_restock(trans); 345ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 346ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 347ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbachvoid iwl_bg_rx_replenish(struct work_struct *data) 348ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 3495a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 3505a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach container_of(data, struct iwl_trans_pcie, rx_replenish); 3515a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans *trans = trans_pcie->trans; 352ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3535a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) 354ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 355ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3565a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach mutex_lock(&trans->shrd->mutex); 3575a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_replenish(trans); 3585a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach mutex_unlock(&trans->shrd->mutex); 359ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 360ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 361ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 362ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_handle - Main entry function for receiving responses from uCode 363ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 364ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Uses the priv->rx_handlers callback function array to invoke 365ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the appropriate handlers, including command responses, 366ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * frame-received notifications, and other notifications. 367ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 3685a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwl_rx_handle(struct iwl_trans *trans) 369ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 370ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_mem_buffer *rxb; 371ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_packet *pkt; 3725a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 3735a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 3745a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_rx_queue *rxq = &trans_pcie->rxq; 375247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue]; 376247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd; 377ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 r, i; 378ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int reclaim; 379ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 380ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u8 fill_rx = 0; 381ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 count = 8; 382ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int total_empty; 383247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach int index, cmd_index; 384ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 385ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* uCode's read index (stored in shared DRAM) indicates the last Rx 386ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * buffer that the driver may process (last buffer filled by ucode). */ 387ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; 388ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i = rxq->read; 389ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 390ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Rx interrupt, but nothing sent from uCode */ 391ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (i == r) 3925a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i); 393ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 394ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* calculate total frames need to be restock after handling RX */ 395ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach total_empty = r - rxq->write_actual; 396ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (total_empty < 0) 397ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach total_empty += RX_QUEUE_SIZE; 398ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 399ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (total_empty > (RX_QUEUE_SIZE / 2)) 400ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach fill_rx = 1; 401ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 402ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach while (i != r) { 403247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach int len, err; 40417a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach u16 txq_id, sequence; 405ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 406ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = rxq->queue[i]; 407ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 408ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If an RXB doesn't have a Rx queue slot associated with it, 409ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * then a bug has been introduced in the queue refilling 410ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * routines -- catch it here */ 411ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (WARN_ON(rxb == NULL)) { 412ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i = (i + 1) & RX_QUEUE_MASK; 413ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach continue; 414ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 415ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 416ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->queue[i] = NULL; 417ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 4185a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach dma_unmap_page(bus(trans)->dev, rxb->page_dma, 4195a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach PAGE_SIZE << hw_params(trans).rx_page_order, 420ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach DMA_FROM_DEVICE); 421ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach pkt = rxb_addr(rxb); 422ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 4235a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_RX(trans, "r = %d, i = %d, %s, 0x%02x\n", r, 424ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); 425ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 426ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; 427ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach len += sizeof(u32); /* account for status word */ 4285a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach trace_iwlwifi_dev_rx(priv(trans), pkt, len); 429ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 430ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Reclaim a command buffer only if this packet is a response 431ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to a (driver-originated) command. 432ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * If the packet (e.g. Rx frame) originated from uCode, 433ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * there is no command buffer to reclaim. 434ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Ucode should set SEQ_RX_FRAME bit if ucode-originated, 435ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * but apparently a few don't get set; catch them here. */ 436ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && 437ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && 438ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_RX) && 439ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && 440ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && 441ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && 442ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_TX); 443ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 44417a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach sequence = le16_to_cpu(pkt->hdr.sequence); 445247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach index = SEQ_TO_INDEX(sequence); 446247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach cmd_index = get_cmd_index(&txq->q, index); 447247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach 448247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach if (reclaim) 449247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach cmd = txq->cmd[cmd_index]; 450247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach else 451247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach cmd = NULL; 45217a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach 45317a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach /* warn if this is cmd response / notification and the uCode 45417a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach * didn't set the SEQ_RX_FRAME for a frame that is 45517a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach * uCode-originated*/ 45617a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach WARN(txq_id == trans->shrd->cmd_queue && reclaim == false && 45717a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach (!(pkt->hdr.sequence & SEQ_RX_FRAME)), 45817a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach "reclaim is false, SEQ_RX_FRAME unset: %s\n", 45917a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach get_cmd_string(pkt->hdr.cmd)); 46017a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach 461247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach err = iwl_rx_dispatch(priv(trans), rxb, cmd); 462ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 463ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* 464ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * XXX: After here, we should always check rxb->page 465ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * against NULL before touching it or its virtual 466ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * memory (pkt). Because some rx_handler might have 467ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * already taken or freed the pages. 468ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 469ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 470ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (reclaim) { 471ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Invoke any callbacks, transfer the buffer to caller, 472ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * and fire off the (possibly) blocking 473e6bb4c9c00892c488f3218ea317dc6a71674faf4Emmanuel Grumbach * iwl_trans_send_cmd() 474ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * as we reclaim the driver command queue */ 475ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxb->page) 476247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach iwl_tx_cmd_complete(trans, rxb, err); 477ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else 4785a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_WARN(trans, "Claim null rxb?\n"); 479ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 480ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 481ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Reuse the page if possible. For notification packets and 482ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * SKBs that fail to Rx correctly, add them back into the 483ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * rx_free list for reuse later. */ 484ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 485ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxb->page != NULL) { 4865a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach rxb->page_dma = dma_map_page(bus(trans)->dev, rxb->page, 487d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach 0, PAGE_SIZE << 4885a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach hw_params(trans).rx_page_order, 489ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach DMA_FROM_DEVICE); 490ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_add_tail(&rxb->list, &rxq->rx_free); 491ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count++; 492ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } else 493ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_add_tail(&rxb->list, &rxq->rx_used); 494ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 495ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 496ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 497ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i = (i + 1) & RX_QUEUE_MASK; 498ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If there are a lot of unused frames, 499ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * restock the Rx queue so ucode wont assert. */ 500ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (fill_rx) { 501ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach count++; 502ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (count >= 8) { 503ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->read = i; 5045a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_replenish_now(trans); 505ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach count = 0; 506ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 507ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 508ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 509ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 510ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Backtrack one entry */ 511ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->read = i; 512ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (fill_rx) 5135a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_replenish_now(trans); 514ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else 5155a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_queue_restock(trans); 516ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 517ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 5187ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbachstatic const char * const desc_lookup_text[] = { 5197ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "OK", 5207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "FAIL", 5217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "BAD_PARAM", 5227ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "BAD_CHECKSUM", 5237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_WDG", 5247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "SYSASSERT", 5257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "FATAL_ERROR", 5267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "BAD_COMMAND", 5277ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_TUNE_LOCK", 5287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_TEMPERATURE", 5297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "ILLEGAL_CHAN_FREQ", 5307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "VCC_NOT_STABLE", 5317ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "FH_ERROR", 5327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_HOST", 5337ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_ACTION_PT", 5347ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_UNKNOWN", 5357ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "UCODE_VERSION_MISMATCH", 5367ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_ABS_LOCK", 5377ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_CAL_LOCK_FAIL", 5387ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_INST_ACTION_PT", 5397ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_DATA_ACTION_PT", 5407ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_TRM_HW_ER", 5417ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_TRM", 5427ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_BREAK_POINT", 5437ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_0", 5447ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_1", 5457ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_2", 5467ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_3", 5477ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach}; 5487ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbachstatic struct { char *name; u8 num; } advanced_lookup[] = { 5507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_WDG", 0x34 }, 5517ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "SYSASSERT", 0x35 }, 5527ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "UCODE_VERSION_MISMATCH", 0x37 }, 5537ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "BAD_COMMAND", 0x38 }, 5547ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, 5557ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "FATAL_ERROR", 0x3D }, 5567ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_TRM_HW_ERR", 0x46 }, 5577ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_TRM", 0x4C }, 5587ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, 5597ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, 5607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, 5617ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_HOST", 0x66 }, 5627ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_ACTION_PT", 0x7C }, 5637ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_UNKNOWN", 0x84 }, 5647ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, 5657ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "ADVANCED_SYSASSERT", 0 }, 5667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach}; 5677ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5687ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbachstatic const char *desc_lookup(u32 num) 5697ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 5707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int i; 5717ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int max = ARRAY_SIZE(desc_lookup_text); 5727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num < max) 5747ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return desc_lookup_text[num]; 5757ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach max = ARRAY_SIZE(advanced_lookup) - 1; 5777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach for (i = 0; i < max; i++) { 5787ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (advanced_lookup[i].num == num) 5797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach break; 5807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 5817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return advanced_lookup[i].name; 5827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 5837ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5847ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define ERROR_START_OFFSET (1 * sizeof(u32)) 5857ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define ERROR_ELEM_SIZE (7 * sizeof(u32)) 5867ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5876bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic void iwl_dump_nic_error_log(struct iwl_trans *trans) 5887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 5897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 base; 5907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach struct iwl_error_event_table table; 5916bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 5921f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 5931f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 5947ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5957ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->device_pointers.error_event_table; 5967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (priv->ucode_type == IWL_UCODE_INIT) { 5977ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 5987ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->init_errlog_ptr; 5997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 6007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 6017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->inst_errlog_ptr; 6027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!iwlagn_hw_valid_rtc_data_addr(base)) { 6056bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, 6067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "Not valid error log pointer 0x%08X for %s uCode\n", 6077ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base, 6087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach (priv->ucode_type == IWL_UCODE_INIT) 6097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? "Init" : "RT"); 6107ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return; 6117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 61383ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_read_targ_mem_words(bus(priv), base, &table, sizeof(table)); 6147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6157ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { 6166bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Start IWL Error Log Dump:\n"); 6176bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", 6186bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach trans->shrd->status, table.valid); 6197ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6211f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach trans_pcie->isr_stats.err_code = table.error_id; 6227ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, 6247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.data1, table.data2, table.line, 6257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.blink1, table.blink2, table.ilink1, 6267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.ilink2, table.bcon_time, table.gp1, 6277ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.gp2, table.gp3, table.ucode_ver, 6287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.hw_ver, table.brd_ver); 6296bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id, 6307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach desc_lookup(table.error_id)); 6316bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | uPc\n", table.pc); 6326bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1); 6336bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2); 6346bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1); 6356bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2); 6366bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | data1\n", table.data1); 6376bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | data2\n", table.data2); 6386bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | line\n", table.line); 6396bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time); 6406bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low); 6416bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi); 6426bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1); 6436bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2); 6446bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3); 6456bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver); 6466bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); 6476bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); 6486bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); 6497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 6507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6517ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach/** 6527ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * iwl_irq_handle_error - called for HW or SW error interrupt from card 6537ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 6546bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic void iwl_irq_handle_error(struct iwl_trans *trans) 6557ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 6566bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 6577ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ 6587ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (priv->cfg->internal_wimax_coex && 65983ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) & 6607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach APMS_CLK_VAL_MRB_FUNC_MODE) || 66183ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) & 6627ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach APMG_PS_CTRL_VAL_RESET_REQ))) { 6637ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* 6647ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * Keep the restart process from trying to send host 6657ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * commands by clearing the ready bit. 6667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 6676bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach clear_bit(STATUS_READY, &trans->shrd->status); 6686bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); 669effd4d9aece9184f526e6556786a94d335e38b71Johannes Berg wake_up(&priv->shrd->wait_command_queue); 6706bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "RF is used by WiMAX\n"); 6717ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return; 6727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6746bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Loaded firmware version: %s\n", 6757ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach priv->hw->wiphy->fw_version); 6767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6776bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_nic_error_log(trans); 6786bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_csr(trans); 6796bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_fh(trans, NULL, false); 6806bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_nic_event_log(trans, false, NULL, false); 6817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 6826bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) 683522376d206da66cecc90929134ad70c0446e874bEmmanuel Grumbach iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS); 6847ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#endif 6857ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6867ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach iwlagn_fw_error(priv, false); 6877ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 6887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define EVENT_START_OFFSET (4 * sizeof(u32)) 6907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6917ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach/** 6927ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * iwl_print_event_log - Dump error event log to syslog 6937ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * 6947ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 6956bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, 6967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 num_events, u32 mode, 6977ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int pos, char **buf, size_t bufsz) 6987ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 6997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 i; 7007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 base; /* SRAM byte address of event log header */ 7017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ 7027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 ptr; /* SRAM byte address of log data */ 7037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 ev, time, data; /* event log data */ 7047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach unsigned long reg_flags; 7056bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 7067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7077ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num_events == 0) 7087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 7097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7107ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->device_pointers.log_event_table; 7117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (priv->ucode_type == IWL_UCODE_INIT) { 7127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 7137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->init_evtlog_ptr; 7147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7157ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 7167ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->inst_evtlog_ptr; 7177ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7187ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7197ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (mode == 0) 7207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach event_size = 2 * sizeof(u32); 7217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach else 7227ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach event_size = 3 * sizeof(u32); 7237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ptr = base + EVENT_START_OFFSET + (start_idx * event_size); 7257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* Make sure device is powered up for SRAM reads */ 7273e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach spin_lock_irqsave(&bus(trans)->reg_lock, reg_flags); 7283e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_grab_nic_access(bus(trans)); 7297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* Set starting address; reads will auto-increment */ 7313e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_write32(bus(trans), HBUS_TARG_MEM_RADDR, ptr); 7327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach rmb(); 7337ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7347ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* "time" is actually "data" for mode 0 (no timestamp). 7357ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * place event id # at far right for easier visual parsing. */ 7367ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach for (i = 0; i < num_events; i++) { 7373e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach ev = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7383e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach time = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7397ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (mode == 0) { 7407ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* data, ev */ 7417ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (bufsz) { 7427ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos += scnprintf(*buf + pos, bufsz - pos, 7437ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "EVT_LOG:0x%08x:%04u\n", 7447ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, ev); 7457ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7467ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach trace_iwlwifi_dev_ucode_event(priv, 0, 7477ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, ev); 7486bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", 7497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, ev); 7507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7517ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7523e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach data = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7537ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (bufsz) { 7547ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos += scnprintf(*buf + pos, bufsz - pos, 7557ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "EVT_LOGT:%010u:0x%08x:%04u\n", 7567ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, data, ev); 7577ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7586bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", 7597ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, data, ev); 7607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach trace_iwlwifi_dev_ucode_event(priv, time, 7617ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach data, ev); 7627ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7637ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7647ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7657ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* Allow device to power down */ 7673e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_release_nic_access(bus(trans)); 7683e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach spin_unlock_irqrestore(&bus(trans)->reg_lock, reg_flags); 7697ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 7707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 7717ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach/** 7737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * iwl_print_last_event_logs - Dump the newest # of event log to syslog 7747ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 7756bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic int iwl_print_last_event_logs(struct iwl_trans *trans, u32 capacity, 7767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 num_wraps, u32 next_entry, 7777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 size, u32 mode, 7787ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int pos, char **buf, size_t bufsz) 7797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 7807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* 7817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * display the newest DEFAULT_LOG_ENTRIES entries 7827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * i.e the entries just before the next ont that uCode would fill. 7837ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 7847ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num_wraps) { 7857ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (next_entry < size) { 7866bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 7877ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach capacity - (size - next_entry), 7887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size - next_entry, mode, 7897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 7906bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 0, 7917ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, mode, 7927ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 7937ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else 7946bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, next_entry - size, 7957ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size, mode, pos, buf, bufsz); 7967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7977ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (next_entry < size) { 7986bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 0, next_entry, 7997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach mode, pos, buf, bufsz); 8007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 8016bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, next_entry - size, 8027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size, mode, pos, buf, bufsz); 8037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8057ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 8067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 8077ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) 8097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8106bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachint iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, 8117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach char **buf, bool display) 8127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 8137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 base; /* SRAM byte address of event log header */ 8147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 capacity; /* event log capacity in # entries */ 8157ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ 8167ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 num_wraps; /* # times uCode wrapped to top of log */ 8177ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 next_entry; /* index of next entry to be written by uCode */ 8187ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 size; /* # entries that we'll print */ 8197ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 logsize; 8207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int pos = 0; 8217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size_t bufsz = 0; 8226bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 8237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->device_pointers.log_event_table; 8257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (priv->ucode_type == IWL_UCODE_INIT) { 8267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach logsize = priv->init_evtlog_size; 8277ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 8287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->init_evtlog_ptr; 8297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 8307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach logsize = priv->inst_evtlog_size; 8317ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 8327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->inst_evtlog_ptr; 8337ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8347ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8357ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!iwlagn_hw_valid_rtc_data_addr(base)) { 8366bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, 8377ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "Invalid event log pointer 0x%08X for %s uCode\n", 8387ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base, 8397ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach (priv->ucode_type == IWL_UCODE_INIT) 8407ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? "Init" : "RT"); 8417ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return -EINVAL; 8427ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8437ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8447ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* event log header */ 8453e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach capacity = iwl_read_targ_mem(bus(trans), base); 8463e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32))); 8473e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32))); 8483e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32))); 8497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (capacity > logsize) { 8516bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " 8526bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach "entries\n", capacity, logsize); 8537ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach capacity = logsize; 8547ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8557ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8567ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (next_entry > logsize) { 8576bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", 8587ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, logsize); 8597ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry = logsize; 8607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8617ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8627ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size = num_wraps ? capacity : next_entry; 8637ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8647ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* bail out if nothing in log */ 8657ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (size == 0) { 8666bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); 8677ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 8687ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8697ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 8716bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log) 8727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 8737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 8747ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#else 8757ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 8767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 8777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#endif 8786bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", 8797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size); 8807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 8827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (display) { 8837ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (full_log) 8847ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach bufsz = capacity * 48; 8857ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach else 8867ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach bufsz = size * 48; 8877ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach *buf = kmalloc(bufsz, GFP_KERNEL); 8887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!*buf) 8897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return -ENOMEM; 8907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8916bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) { 8927ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* 8937ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * if uCode has wrapped back to top of log, 8947ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * start at the oldest entry, 8957ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * i.e the next one that uCode would fill. 8967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 8977ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num_wraps) 8986bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, next_entry, 8997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach capacity - next_entry, mode, 9007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 9017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* (then/else) start at top of log */ 9026bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 0, 9037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, mode, pos, buf, bufsz); 9047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else 9056bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_last_event_logs(trans, capacity, num_wraps, 9067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, size, mode, 9077ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 9087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#else 9096bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_last_event_logs(trans, capacity, num_wraps, 9107ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, size, mode, 9117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 9127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#endif 9137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 9147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 9157ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 916ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/* tasklet for iwlagn interrupt */ 9170c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachvoid iwl_irq_tasklet(struct iwl_trans *trans) 918ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 919ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 inta = 0; 920ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 handled = 0; 921ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 922ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 i; 923ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 924ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 inta_mask; 925ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#endif 926ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9273e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 9281f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach struct isr_statistics *isr_stats = &trans_pcie->isr_stats; 9291f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach 9300c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 9310c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 932ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 933ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Ack/clear/reset pending uCode interrupts. 934ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, 935ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 936ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* There is a hardware bug in the interrupt mask function that some 937ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if 938ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * they are disabled in the CSR_INT_MASK register. Furthermore the 939ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ICT interrupt handling mechanism has another bug that might cause 940ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * these unmasked interrupts fail to be detected. We workaround the 941ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * hardware bugs here by ACKing all the possible interrupts so that 942ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * interrupt coalescing can still be achieved. 943ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 94483ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT, 9450c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta | ~trans_pcie->inta_mask); 946ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9470c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach inta = trans_pcie->inta; 948ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 949ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 9500c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) { 951ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* just for debug */ 95283ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); 9530c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ", 954ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach inta, inta_mask); 955ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 956ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#endif 957ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9580c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 959ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9600c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach /* saved interrupt in inta variable now we can reset trans_pcie->inta */ 9610c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta = 0; 962ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 963ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Now service all interrupt bits discovered above. */ 964ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_HW_ERR) { 9650c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Hardware error detected. Restarting.\n"); 966ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 967ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Tell the device to stop sending interrupts */ 9680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_disable_interrupts(trans); 969ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9701f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->hw++; 9716bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_irq_handle_error(trans); 972ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 973ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_HW_ERR; 974ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 975ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 976ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 977ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 978ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 9790c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { 980ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* NIC fires this, but we don't use it, redundant with WAKEUP */ 981ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_SCD) { 9820c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Scheduler finished to transmit " 983ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "the frame/frames.\n"); 9841f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->sch++; 985ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 986ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 987ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Alive notification via Rx interrupt will do the real work */ 988ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_ALIVE) { 9890c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Alive interrupt\n"); 9901f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->alive++; 991ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 992ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 993ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#endif 994ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Safely ignore these bits for debug checks below */ 995ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); 996ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 997ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* HW RF KILL switch toggled */ 998ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_RF_KILL) { 999ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int hw_rf_kill = 0; 100083ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & 1001ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) 1002ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach hw_rf_kill = 1; 1003ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10040c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", 1005ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach hw_rf_kill ? "disable radio" : "enable radio"); 1006ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10071f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->rfkill++; 1008ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1009ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* driver only loads ucode once setting the interface up. 1010ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the driver allows loading the ucode even if the radio 1011ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * is killed. Hence update the killswitch state here. The 1012ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * rfkill handler will care about restarting if needed. 1013ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 10140c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!test_bit(STATUS_ALIVE, &trans->shrd->status)) { 1015ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (hw_rf_kill) 10160c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach set_bit(STATUS_RF_KILL_HW, 10170c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach &trans->shrd->status); 1018ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else 101963013ae30159c90d2a873e20e680e7810fa533faEmmanuel Grumbach clear_bit(STATUS_RF_KILL_HW, 10200c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach &trans->shrd->status); 10213e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill); 1022ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1023ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1024ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_RF_KILL; 1025ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1026ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1027ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Chip got too hot and stopped itself */ 1028ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_CT_KILL) { 10290c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Microcode CT kill error detected.\n"); 10301f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->ctkill++; 1031ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_CT_KILL; 1032ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1033ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1034ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Error detected by uCode */ 1035ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_SW_ERR) { 10360c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Microcode SW error detected. " 1037ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach " Restarting 0x%X.\n", inta); 10381f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->sw++; 10396bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_irq_handle_error(trans); 1040ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_SW_ERR; 1041ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1042ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1043ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* uCode wakes up after power-down sleep */ 1044ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_WAKEUP) { 10450c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); 10460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq); 10470c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach for (i = 0; i < hw_params(trans).max_txq_num; i++) 1048fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_txq_update_write_ptr(trans, 10498ad71bef4a9d8173cbcfbb2f796b08d33d4ca01bEmmanuel Grumbach &trans_pcie->txq[i]); 1050ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10511f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->wakeup++; 1052ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1053ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_WAKEUP; 1054ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1055ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1056ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* All uCode command responses, including Tx command responses, 1057ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Rx "responses" (frame-received notification), and other 1058ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * notifications from uCode come through here*/ 1059ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | 1060ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_INT_BIT_RX_PERIODIC)) { 10610c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Rx interrupt\n"); 1062ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { 1063ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); 106483ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_FH_INT_STATUS, 1065ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_FH_INT_RX_MASK); 1066ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1067ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_RX_PERIODIC) { 1068ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_RX_PERIODIC; 106983ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), 10700c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach CSR_INT, CSR_INT_BIT_RX_PERIODIC); 1071ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1072ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Sending RX interrupt require many steps to be done in the 1073ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the device: 1074ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 1- write interrupt to current index in ICT table. 1075ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 2- dma RX frame. 1076ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 3- update RX shared data to indicate last write index. 1077ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 4- send interrupt. 1078ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This could lead to RX race, driver could receive RX interrupt 1079ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * but the shared data changes does not reflect this; 1080ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * periodic interrupt will detect any dangling Rx activity. 1081ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1082ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1083ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Disable periodic interrupt; we use it as just a one-shot. */ 108483ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, 1085ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_INT_PERIODIC_DIS); 10860c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_rx_handle(trans); 1087ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1088ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* 1089ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Enable periodic interrupt in 8 msec only if we received 1090ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * real RX interrupt (instead of just periodic int), to catch 1091ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * any dangling Rx interrupt. If it was just the periodic 1092ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * interrupt, there was no dangling Rx activity, and no need 1093ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to extend the periodic interrupt; one-shot is enough. 1094ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1095ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) 109683ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, 1097ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_INT_PERIODIC_ENA); 1098ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10991f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->rx++; 1100ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1101ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1102ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* This "Tx" DMA channel is used only for loading uCode */ 1103ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_FH_TX) { 110483ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); 11050c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); 11061f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->tx++; 1107ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_FH_TX; 1108ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Wake up uCode load routine, now that load is complete */ 11090c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach priv(trans)->ucode_write_complete = 1; 1110effd4d9aece9184f526e6556786a94d335e38b71Johannes Berg wake_up(&trans->shrd->wait_command_queue); 1111ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1112ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1113ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & ~handled) { 11140c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled); 11151f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->unhandled++; 1116ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1117ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 11180c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (inta & ~(trans_pcie->inta_mask)) { 11190c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n", 11200c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach inta & ~trans_pcie->inta_mask); 1121ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1122ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1123ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Re-enable all interrupts */ 1124ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* only Re-enable if disabled by irq */ 11250c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status)) 11260c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 1127ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Re-enable RF_KILL if it occurred */ 1128ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else if (handled & CSR_INT_BIT_RF_KILL) 11290c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_rfkill_int(priv(trans)); 1130ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 1131ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 11321a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/****************************************************************************** 11331a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * 11341a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * ICT functions 11351a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * 11361a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach ******************************************************************************/ 11371a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) 11381a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11391a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* Free dram table */ 11400c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachvoid iwl_free_isr_ict(struct iwl_trans *trans) 11411a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 11420c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 11430c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 11440c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 11450c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (trans_pcie->ict_tbl_vir) { 11460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach dma_free_coherent(bus(trans)->dev, 11471a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 11480c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_vir, 11490c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma); 11500c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_vir = NULL; 11510c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(&trans_pcie->ict_tbl_dma, 0, 11520c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach sizeof(trans_pcie->ict_tbl_dma)); 11530c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(&trans_pcie->aligned_ict_tbl_dma, 0, 11540c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach sizeof(trans_pcie->aligned_ict_tbl_dma)); 11551a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 11561a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 11571a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11581a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11591a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* allocate dram shared table it is a PAGE_SIZE aligned 11601a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * also reset all data related to ICT table interrupt. 11611a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 11620c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachint iwl_alloc_isr_ict(struct iwl_trans *trans) 11631a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 11640c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 11650c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 11661a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11671a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* allocate shrared data table */ 11680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_vir = 11690c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach dma_alloc_coherent(bus(trans)->dev, 11701a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 11710c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach &trans_pcie->ict_tbl_dma, GFP_KERNEL); 11720c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->ict_tbl_vir) 11731a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return -ENOMEM; 11741a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11751a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* align table to PAGE_SIZE boundary */ 11760c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->aligned_ict_tbl_dma = 11770c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE); 11781a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11790c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n", 11800c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (unsigned long long)trans_pcie->ict_tbl_dma, 11810c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (unsigned long long)trans_pcie->aligned_ict_tbl_dma, 11820c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (int)(trans_pcie->aligned_ict_tbl_dma - 11830c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma)); 11841a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11850c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir + 11860c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (trans_pcie->aligned_ict_tbl_dma - 11870c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma); 11881a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11890c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n", 11900c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir, 11910c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (int)(trans_pcie->aligned_ict_tbl_dma - 11920c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma)); 11931a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11941a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* reset table and index to all 0 */ 11950c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(trans_pcie->ict_tbl_vir, 0, 11961a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); 11970c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index = 0; 11981a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11991a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* add periodic RX interrupt */ 12000c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC; 12011a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return 0; 12021a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 12031a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12041a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* Device is going up inform it about using ICT interrupt table, 12051a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * also we need to tell the driver to start using ICT interrupt. 12061a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 12076bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachint iwl_reset_ict(struct iwl_trans *trans) 12081a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 12091a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 val; 12101a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 12110c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 12120c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 12131a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12140c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->ict_tbl_vir) 12151a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return 0; 12161a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12170c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 12180c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_disable_interrupts(trans); 12191a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12200c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); 12211a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12220c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT; 12231a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12241a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val |= CSR_DRAM_INT_TBL_ENABLE; 12251a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; 12261a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12270c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X " 12281a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach "aligned dma address %Lx\n", 12291a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val, 12300c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (unsigned long long)trans_pcie->aligned_ict_tbl_dma); 12311a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 123283ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); 12330c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->use_ict = true; 12340c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index = 0; 123583ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT, trans_pcie->inta_mask); 12360c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 12370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 12381a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12391a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return 0; 12401a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 12411a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12421a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* Device is going down disable ict interrupt usage */ 12430c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachvoid iwl_disable_ict(struct iwl_trans *trans) 12441a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 12450c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 12460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 12470c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 12481a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 12491a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12500c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 12510c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->use_ict = false; 12520c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 12531a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 12541a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12551a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbachstatic irqreturn_t iwl_isr(int irq, void *data) 12561a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 12570c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans *trans = data; 12580c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie; 12591a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 inta, inta_mask; 12601a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 12611a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 12621a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 inta_fh; 12631a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#endif 12640c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans) 12651a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 12661a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12670c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 12680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 12690c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 12701a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12711a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Disable (but don't clear!) interrupts here to avoid 12721a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * back-to-back ISRs and sporadic interrupts from our NIC. 12731a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we have something to service, the tasklet will re-enable ints. 12741a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we *don't* have something, we'll re-enable before leaving here. */ 127583ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ 127683ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); 12771a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12781a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Discover which interrupts are active/pending */ 127983ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta = iwl_read32(bus(trans), CSR_INT); 12801a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12811a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Ignore interrupt if there's nothing in NIC to service. 12821a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * This may be due to IRQ shared with another device, 12831a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * or due to sporadic interrupts thrown from our NIC. */ 12841a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (!inta) { 12850c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); 12861a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach goto none; 12871a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 12881a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12891a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { 12901a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Hardware disappeared. It might have already raised 12911a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * an interrupt */ 12920c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta); 12931a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach goto unplugged; 12941a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 12951a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12961a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 12970c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { 129883ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_fh = iwl_read32(bus(trans), CSR_FH_INT_STATUS); 12990c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, " 13001a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach "fh 0x%08x\n", inta, inta_mask, inta_fh); 13011a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13021a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#endif 13031a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13040c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta |= inta; 13051a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* iwl_irq_tasklet() will service interrupts and re-enable them */ 13061a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (likely(inta)) 13070c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach tasklet_schedule(&trans_pcie->irq_tasklet); 13080c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 13090c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) 13100c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 13111a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13121a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unplugged: 13130c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 13141a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_HANDLED; 13151a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13161a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach none: 13171a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* re-enable interrupts here since we don't have anything to service. */ 13181a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* only Re-enable if disabled by irq and no schedules tasklet. */ 13190c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 13200c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) 13210c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 13221a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13230c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 13241a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 13251a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 13261a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13271a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* interrupt handler using ict table, with this interrupt driver will 13281a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * stop using INTA register to get device's interrupt, reading this register 13291a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * is expensive, device will write interrupts in ICT dram table, increment 13301a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * index then will fire interrupt to driver, driver will OR all ICT table 13311a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * entries from current index up to table entry with 0 value. the result is 13321a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * the interrupt we need to service, driver will set the entries back to 0 and 13331a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * set index. 13341a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 13351a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbachirqreturn_t iwl_isr_ict(int irq, void *data) 13361a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 13370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans *trans = data; 13380c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie; 13391a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 inta, inta_mask; 13401a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 val = 0; 13411a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 13421a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13430c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans) 13441a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 13451a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 13470c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 13481a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* dram interrupt table not set yet, 13491a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * use legacy interrupt. 13501a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 13510c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->use_ict) 13521a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return iwl_isr(irq, data); 13531a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13540c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 13551a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13561a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Disable (but don't clear!) interrupts here to avoid 13571a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * back-to-back ISRs and sporadic interrupts from our NIC. 13581a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we have something to service, the tasklet will re-enable ints. 13591a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we *don't* have something, we'll re-enable before leaving here. 13601a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 136183ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ 136283ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); 13631a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13641a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13651a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Ignore interrupt if there's nothing in NIC to service. 13661a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * This may be due to IRQ shared with another device, 13671a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * or due to sporadic interrupts thrown from our NIC. */ 13680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->ict_tbl[trans_pcie->ict_index]) { 13690c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); 13701a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach goto none; 13711a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13721a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13731a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* read all entries that not 0 start with ict_index */ 13740c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach while (trans_pcie->ict_tbl[trans_pcie->ict_index]) { 13751a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13760c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach val |= le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); 13770c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", 13780c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index, 13791a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach le32_to_cpu( 13800c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl[trans_pcie->ict_index])); 13810c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; 13820c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index = 13830c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); 13841a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13851a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13861a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13871a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* We should not get this value, just ignore it. */ 13881a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (val == 0xffffffff) 13891a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val = 0; 13901a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13911a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* 13921a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit 13931a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * (bit 15 before shifting it to 31) to clear when using interrupt 13941a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * coalescing. fortunately, bits 18 and 19 stay set when this happens 13951a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * so we use them to decide on the real state of the Rx bit. 13961a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * In order words, bit 15 is set if bit 18 or bit 19 are set. 13971a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 13981a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (val & 0xC0000) 13991a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val |= 0x8000; 14001a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14011a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach inta = (0xff & val) | ((0xff00 & val) << 16); 14020c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", 14031a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach inta, inta_mask, val); 14041a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14050c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach inta &= trans_pcie->inta_mask; 14060c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta |= inta; 14071a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14081a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* iwl_irq_tasklet() will service interrupts and re-enable them */ 14091a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (likely(inta)) 14100c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach tasklet_schedule(&trans_pcie->irq_tasklet); 14110c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 14120c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) { 14131a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Allow interrupt if was disabled by this handler and 14141a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * no tasklet was schedules, We should not enable interrupt, 14151a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * tasklet will enable it. 14161a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 14170c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 14181a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 14191a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14200c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 14211a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_HANDLED; 14221a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14231a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach none: 14241a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* re-enable interrupts here since we don't have anything to service. 14251a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * only Re-enable if disabled by irq. 14261a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 14270c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 14280c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) 14290c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 14301a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14310c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 14321a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 14331a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 1434