iwl-trans-pcie-rx.c revision ae6130fc9b5e9957aaf26355b80e0a5ef7f8f537
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" 36c17d0681b8a4d93217464d8026361c7b44b3ca99Johannes Berg#include "iwl-trans-pcie-int.h" 37ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 38ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/****************************************************************************** 39ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 40ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * RX path functions 41ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 42ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach ******************************************************************************/ 43ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 44ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/* 45ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Rx theory of operation 46ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 47ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), 48ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * each of which point to Receive Buffers to be filled by the NIC. These get 49ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * used not only for Rx frames, but for any command response or notification 50ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * from the NIC. The driver and NIC manage the Rx buffers by means 51ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * of indexes into the circular buffer. 52ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 53ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Rx Queue Indexes 54ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The host/firmware share two index registers for managing the Rx buffers. 55ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 56ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The READ index maps to the first position that the firmware may be writing 57ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to -- the driver can read up to (but not including) this position and get 58ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * good data. 59ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The READ index is managed by the firmware once the card is enabled. 60ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 61ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The WRITE index maps to the last position the driver has read from -- the 62ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * position preceding WRITE is the last slot the firmware can place a packet. 63ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 64ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The queue is empty (no good data) if WRITE = READ - 1, and is full if 65ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * WRITE = READ. 66ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 67ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * During initialization, the host sets up the READ queue position to the first 68ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * INDEX position, and WRITE to the last (READ - 1 wrapped) 69ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 70ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * When the firmware places a packet in a buffer, it will advance the READ index 71ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * and fire the RX interrupt. The driver can then query the READ index and 72ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * process as many packets as possible, moving the WRITE index forward as it 73ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * resets the Rx queue buffers with new memory. 74ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 75ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * The management in the driver is as follows: 76ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When 77ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled 78ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to replenish the iwl->rxq->rx_free. 79ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the 80ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl->rxq is replenished and the READ INDEX is updated (updating the 81ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 'processed' and 'read' driver indexes as well) 82ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + A received packet is processed and handed to the kernel network stack, 83ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * detached from the iwl->rxq. The driver 'processed' index is updated. 84ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free 85ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ 86ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there 87ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * were enough free buffers and RX_STALLED is set it is cleared. 88ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 89ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 90ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Driver sequence: 91ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 92ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_alloc() Allocates rx_free 93ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls 94ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_restock 95ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx 96ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * queue, updates firmware pointers, and updates 97ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the WRITE index. If insufficient rx_free buffers 98ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * are available, schedules iwl_rx_replenish 99ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 100ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * -- enable interrupts -- 101ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the 102ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * READ INDEX, detaching the SKB from the pool. 103ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Moves the packet buffer from queue to rx_used. 104ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Calls iwl_rx_queue_restock to refill any empty 105ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * slots. 106ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ... 107ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 108ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 109ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 110ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 111ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_space - Return number of free slots available in queue. 112ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 113ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbachstatic int iwl_rx_queue_space(const struct iwl_rx_queue *q) 114ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 115ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int s = q->read - q->write; 116ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (s <= 0) 117ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach s += RX_QUEUE_SIZE; 118ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* keep some buffer to not confuse full and empty queue */ 119ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach s -= 2; 120ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (s < 0) 121ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach s = 0; 122ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return s; 123ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 124ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 125ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 126ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue 127ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1285a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachvoid iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, 129ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_queue *q) 130ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 131ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 132ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 reg; 133ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 134ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&q->lock, flags); 135ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 136ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (q->need_update == 0) 137ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach goto exit_unlock; 138ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 139fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach if (hw_params(trans).shadow_reg_enable) { 140ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* shadow register enabled */ 141ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Device expects a multiple of 8 */ 142ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual = (q->write & ~0x7); 143fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_write32(bus(trans), FH_RSCSR_CHNL0_WPTR, q->write_actual); 144ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } else { 145ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If power-saving is in use, make sure device is awake */ 1465a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { 147fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); 148ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 149ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { 1505a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_INFO(trans, 151ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "Rx queue requesting wakeup," 152ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach " GP1 = 0x%x\n", reg); 153fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_set_bit(bus(trans), CSR_GP_CNTRL, 154ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 155ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach goto exit_unlock; 156ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 157ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 158ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual = (q->write & ~0x7); 159fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, 160ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual); 161ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 162ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Else device is assumed to be awake */ 163ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } else { 164ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Device expects a multiple of 8 */ 165ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual = (q->write & ~0x7); 166fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, 167ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->write_actual); 168ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 169ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 170ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach q->need_update = 0; 171ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 172ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach exit_unlock: 173ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&q->lock, flags); 174ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 175ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 176ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 177ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr 178ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1795a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) 180ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 181ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return cpu_to_le32((u32)(dma_addr >> 8)); 182ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 183ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 184ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 185ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool 186ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 187ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * If there are slots in the RX queue that need to be restocked, 188ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * and we have free pre-allocated buffers, fill the ranks as much 189ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * as we can, pulling from rx_free. 190ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 191ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This moves the 'write' index forward to catch up with 'processed', and 192ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * also updates the memory address in the firmware to reference the new 193ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * target buffer. 194ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1955a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwlagn_rx_queue_restock(struct iwl_trans *trans) 196ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 1975a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 1985a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 1995a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach 2005a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_rx_queue *rxq = &trans_pcie->rxq; 201ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct list_head *element; 202ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_mem_buffer *rxb; 203ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 204ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 205ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 206ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { 207ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* The overwritten rxb must be a used one */ 208ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = rxq->queue[rxq->write]; 209ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb && rxb->page); 210ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 211ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Get next free Rx buffer, remove from free list */ 212ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach element = rxq->rx_free.next; 213ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = list_entry(element, struct iwl_rx_mem_buffer, list); 214ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_del(element); 215ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 216ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Point to Rx buffer via next RBD in circular buffer */ 2175a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma); 218ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->queue[rxq->write] = rxb; 219ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; 220ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count--; 221ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 222ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 223ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If the pre-allocated buffer pool is dropping low, schedule to 224ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * refill it */ 225ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxq->free_count <= RX_LOW_WATERMARK) 2265a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); 227ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 228ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 229ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If we've added more space for the firmware to place data, tell it. 230ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Increment device's write pointer in multiples of 8. */ 231ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxq->write_actual != (rxq->write & ~0x7)) { 232ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 233ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->need_update = 1; 234ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 2355a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwl_rx_queue_update_write_ptr(trans, rxq); 236ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 237ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 238ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 239ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 240ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free 241ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 242ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * When moving to rx_free an SKB is allocated for the slot. 243ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 244ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Also restock the Rx queue via iwl_rx_queue_restock. 245ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This is called as a scheduled work item (except for during initialization) 246ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 2475a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) 248ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 2495a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 2505a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 2515a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach 2525a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_rx_queue *rxq = &trans_pcie->rxq; 253ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct list_head *element; 254ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_mem_buffer *rxb; 255ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct page *page; 256ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 257ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach gfp_t gfp_mask = priority; 258ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 259ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach while (1) { 260ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 261ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (list_empty(&rxq->rx_used)) { 262ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 263ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 264ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 265ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 266ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 267ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxq->free_count > RX_LOW_WATERMARK) 268ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach gfp_mask |= __GFP_NOWARN; 269ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 2705a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach if (hw_params(trans).rx_page_order > 0) 271ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach gfp_mask |= __GFP_COMP; 272ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 273ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Alloc a new receive buffer */ 274d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach page = alloc_pages(gfp_mask, 2755a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach hw_params(trans).rx_page_order); 276ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (!page) { 277ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (net_ratelimit()) 2785a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_INFO(trans, "alloc_pages failed, " 279d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach "order: %d\n", 2805a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach hw_params(trans).rx_page_order); 281ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 282ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if ((rxq->free_count <= RX_LOW_WATERMARK) && 283ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach net_ratelimit()) 2845a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_CRIT(trans, "Failed to alloc_pages with %s." 285ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "Only %u free buffers remaining.\n", 286ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach priority == GFP_ATOMIC ? 287ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "GFP_ATOMIC" : "GFP_KERNEL", 288ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count); 289ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* We don't reschedule replenish work here -- we will 290ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * call the restock method and if it still needs 291ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * more buffers it will schedule replenish */ 292ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 293ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 294ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 295ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 296ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 297ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (list_empty(&rxq->rx_used)) { 298ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 2995a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach __free_pages(page, hw_params(trans).rx_page_order); 300ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 301ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 302ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach element = rxq->rx_used.next; 303ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = list_entry(element, struct iwl_rx_mem_buffer, list); 304ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_del(element); 305ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 306ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 307ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 308ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb->page); 309ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb->page = page; 310ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Get physical address of the RB */ 3115a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach rxb->page_dma = dma_map_page(bus(trans)->dev, page, 0, 3125a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach PAGE_SIZE << hw_params(trans).rx_page_order, 313ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach DMA_FROM_DEVICE); 314ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* dma address must be no more than 36 bits */ 315ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); 316ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* and also 256 byte aligned! */ 317ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); 318ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 319ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 320ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 321ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_add_tail(&rxb->list, &rxq->rx_free); 322ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count++; 323ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 324ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 325ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 326ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 327ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3285a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachvoid iwlagn_rx_replenish(struct iwl_trans *trans) 329ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 330ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 331ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3325a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_allocate(trans, GFP_KERNEL); 333ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3345a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 3355a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_queue_restock(trans); 3365a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 337ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 338ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3395a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwlagn_rx_replenish_now(struct iwl_trans *trans) 340ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 3415a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_allocate(trans, GFP_ATOMIC); 342ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3435a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_queue_restock(trans); 344ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 345ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 346ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbachvoid iwl_bg_rx_replenish(struct work_struct *data) 347ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 3485a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 3495a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach container_of(data, struct iwl_trans_pcie, rx_replenish); 3505a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans *trans = trans_pcie->trans; 351ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3525a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) 353ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 354ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 3555a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach mutex_lock(&trans->shrd->mutex); 3565a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_replenish(trans); 3575a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach mutex_unlock(&trans->shrd->mutex); 358ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 359ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 360ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/** 361ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * iwl_rx_handle - Main entry function for receiving responses from uCode 362ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 363ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Uses the priv->rx_handlers callback function array to invoke 364ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the appropriate handlers, including command responses, 365ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * frame-received notifications, and other notifications. 366ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 3675a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbachstatic void iwl_rx_handle(struct iwl_trans *trans) 368ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 369ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_mem_buffer *rxb; 370ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach struct iwl_rx_packet *pkt; 3715a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 3725a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 3735a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach struct iwl_rx_queue *rxq = &trans_pcie->rxq; 374247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue]; 375247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd; 376ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 r, i; 377ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int reclaim; 378ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 379ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u8 fill_rx = 0; 380ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 count = 8; 381ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int total_empty; 382247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach int index, cmd_index; 383ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 384ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* uCode's read index (stored in shared DRAM) indicates the last Rx 385ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * buffer that the driver may process (last buffer filled by ucode). */ 386ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; 387ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i = rxq->read; 388ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 389ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Rx interrupt, but nothing sent from uCode */ 390ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (i == r) 3915a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i); 392ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 393ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* calculate total frames need to be restock after handling RX */ 394ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach total_empty = r - rxq->write_actual; 395ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (total_empty < 0) 396ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach total_empty += RX_QUEUE_SIZE; 397ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 398ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (total_empty > (RX_QUEUE_SIZE / 2)) 399ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach fill_rx = 1; 400ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 401ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach while (i != r) { 402247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach int len, err; 403d56da92092c7808fea0b6ad85fd97095067a2616Emmanuel Grumbach u16 sequence; 404ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 405ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxb = rxq->queue[i]; 406ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 407ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If an RXB doesn't have a Rx queue slot associated with it, 408ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * then a bug has been introduced in the queue refilling 409ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * routines -- catch it here */ 410ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (WARN_ON(rxb == NULL)) { 411ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i = (i + 1) & RX_QUEUE_MASK; 412ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach continue; 413ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 414ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 415ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->queue[i] = NULL; 416ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 4175a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach dma_unmap_page(bus(trans)->dev, rxb->page_dma, 4185a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach PAGE_SIZE << hw_params(trans).rx_page_order, 419ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach DMA_FROM_DEVICE); 420ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach pkt = rxb_addr(rxb); 421ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 4225a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_DEBUG_RX(trans, "r = %d, i = %d, %s, 0x%02x\n", r, 423ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); 424ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 425ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; 426ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach len += sizeof(u32); /* account for status word */ 4275a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach trace_iwlwifi_dev_rx(priv(trans), pkt, len); 428ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 429ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Reclaim a command buffer only if this packet is a response 430ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to a (driver-originated) command. 431ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * If the packet (e.g. Rx frame) originated from uCode, 432ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * there is no command buffer to reclaim. 433ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Ucode should set SEQ_RX_FRAME bit if ucode-originated, 434ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * but apparently a few don't get set; catch them here. */ 435ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && 436ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && 437ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_RX) && 438ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && 439ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && 440ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && 441ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach (pkt->hdr.cmd != REPLY_TX); 442ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 44317a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach sequence = le16_to_cpu(pkt->hdr.sequence); 444247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach index = SEQ_TO_INDEX(sequence); 445247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach cmd_index = get_cmd_index(&txq->q, index); 446247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach 447247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach if (reclaim) 448247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach cmd = txq->cmd[cmd_index]; 449247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach else 450247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach cmd = NULL; 45117a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach 45217a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach /* warn if this is cmd response / notification and the uCode 45317a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach * didn't set the SEQ_RX_FRAME for a frame that is 454d56da92092c7808fea0b6ad85fd97095067a2616Emmanuel Grumbach * uCode-originated 455d56da92092c7808fea0b6ad85fd97095067a2616Emmanuel Grumbach * If you saw this code after the second half of 2012, then 456d56da92092c7808fea0b6ad85fd97095067a2616Emmanuel Grumbach * please remove it 457d56da92092c7808fea0b6ad85fd97095067a2616Emmanuel Grumbach */ 458d56da92092c7808fea0b6ad85fd97095067a2616Emmanuel Grumbach WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false && 45917a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach (!(pkt->hdr.sequence & SEQ_RX_FRAME)), 46017a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach "reclaim is false, SEQ_RX_FRAME unset: %s\n", 46117a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach get_cmd_string(pkt->hdr.cmd)); 46217a68dd7bc25b3671d54b3b371df9b5baf985b20Emmanuel Grumbach 463247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach err = iwl_rx_dispatch(priv(trans), rxb, cmd); 464ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 465ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* 466ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * XXX: After here, we should always check rxb->page 467ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * against NULL before touching it or its virtual 468ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * memory (pkt). Because some rx_handler might have 469ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * already taken or freed the pages. 470ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 471ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 472ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (reclaim) { 473ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Invoke any callbacks, transfer the buffer to caller, 474ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * and fire off the (possibly) blocking 475e6bb4c9c00892c488f3218ea317dc6a71674faf4Emmanuel Grumbach * iwl_trans_send_cmd() 476ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * as we reclaim the driver command queue */ 477ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxb->page) 478247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach iwl_tx_cmd_complete(trans, rxb, err); 479ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else 4805a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach IWL_WARN(trans, "Claim null rxb?\n"); 481ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 482ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 483ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Reuse the page if possible. For notification packets and 484ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * SKBs that fail to Rx correctly, add them back into the 485ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * rx_free list for reuse later. */ 486ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_lock_irqsave(&rxq->lock, flags); 487ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (rxb->page != NULL) { 4885a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach rxb->page_dma = dma_map_page(bus(trans)->dev, rxb->page, 489d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach 0, PAGE_SIZE << 4905a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach hw_params(trans).rx_page_order, 491ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach DMA_FROM_DEVICE); 492ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_add_tail(&rxb->list, &rxq->rx_free); 493ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->free_count++; 494ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } else 495ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach list_add_tail(&rxb->list, &rxq->rx_used); 496ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 497ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach spin_unlock_irqrestore(&rxq->lock, flags); 498ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 499ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach i = (i + 1) & RX_QUEUE_MASK; 500ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* If there are a lot of unused frames, 501ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * restock the Rx queue so ucode wont assert. */ 502ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (fill_rx) { 503ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach count++; 504ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (count >= 8) { 505ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->read = i; 5065a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_replenish_now(trans); 507ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach count = 0; 508ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 509ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 510ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 511ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 512ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Backtrack one entry */ 513ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach rxq->read = i; 514ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (fill_rx) 5155a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_replenish_now(trans); 516ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else 5175a878bf60b2bb1f1509f49b8b1784e3c9f204c64Emmanuel Grumbach iwlagn_rx_queue_restock(trans); 518ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 519ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 5207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbachstatic const char * const desc_lookup_text[] = { 5217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "OK", 5227ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "FAIL", 5237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "BAD_PARAM", 5247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "BAD_CHECKSUM", 5257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_WDG", 5267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "SYSASSERT", 5277ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "FATAL_ERROR", 5287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "BAD_COMMAND", 5297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_TUNE_LOCK", 5307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_TEMPERATURE", 5317ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "ILLEGAL_CHAN_FREQ", 5327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "VCC_NOT_STABLE", 5337ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "FH_ERROR", 5347ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_HOST", 5357ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_ACTION_PT", 5367ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_UNKNOWN", 5377ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "UCODE_VERSION_MISMATCH", 5387ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_ABS_LOCK", 5397ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "HW_ERROR_CAL_LOCK_FAIL", 5407ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_INST_ACTION_PT", 5417ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_DATA_ACTION_PT", 5427ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_TRM_HW_ER", 5437ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_TRM", 5447ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "NMI_INTERRUPT_BREAK_POINT", 5457ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_0", 5467ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_1", 5477ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_2", 5487ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "DEBUG_3", 5497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach}; 5507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5517ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbachstatic struct { char *name; u8 num; } advanced_lookup[] = { 5527ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_WDG", 0x34 }, 5537ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "SYSASSERT", 0x35 }, 5547ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "UCODE_VERSION_MISMATCH", 0x37 }, 5557ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "BAD_COMMAND", 0x38 }, 5567ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, 5577ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "FATAL_ERROR", 0x3D }, 5587ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_TRM_HW_ERR", 0x46 }, 5597ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_TRM", 0x4C }, 5607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, 5617ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, 5627ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, 5637ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_HOST", 0x66 }, 5647ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_ACTION_PT", 0x7C }, 5657ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_UNKNOWN", 0x84 }, 5667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, 5677ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach { "ADVANCED_SYSASSERT", 0 }, 5687ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach}; 5697ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbachstatic const char *desc_lookup(u32 num) 5717ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 5727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int i; 5737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int max = ARRAY_SIZE(desc_lookup_text); 5747ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5757ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num < max) 5767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return desc_lookup_text[num]; 5777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5787ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach max = ARRAY_SIZE(advanced_lookup) - 1; 5797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach for (i = 0; i < max; i++) { 5807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (advanced_lookup[i].num == num) 5817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach break; 5827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 5837ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return advanced_lookup[i].name; 5847ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 5857ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5867ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define ERROR_START_OFFSET (1 * sizeof(u32)) 5877ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define ERROR_ELEM_SIZE (7 * sizeof(u32)) 5887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 5896bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic void iwl_dump_nic_error_log(struct iwl_trans *trans) 5907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 5917ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 base; 5927ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach struct iwl_error_event_table table; 5936bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 5941f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 5951f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 5967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 597ae6130fc9b5e9957aaf26355b80e0a5ef7f8f537Don Fry base = trans->shrd->device_pointers.error_event_table; 5983d6acefc0a24bf90746c1f259e9d65d1ed7ea5e2Don Fry if (trans->shrd->ucode_type == IWL_UCODE_INIT) { 5997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 6007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->init_errlog_ptr; 6017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 6027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 6037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->inst_errlog_ptr; 6047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6057ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!iwlagn_hw_valid_rtc_data_addr(base)) { 6076bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, 6087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "Not valid error log pointer 0x%08X for %s uCode\n", 6097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base, 6103d6acefc0a24bf90746c1f259e9d65d1ed7ea5e2Don Fry (trans->shrd->ucode_type == IWL_UCODE_INIT) 6117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? "Init" : "RT"); 6127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return; 6137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 61583ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_read_targ_mem_words(bus(priv), base, &table, sizeof(table)); 6167ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6177ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { 6186bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Start IWL Error Log Dump:\n"); 6196bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", 6206bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach trans->shrd->status, table.valid); 6217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6227ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6231f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach trans_pcie->isr_stats.err_code = table.error_id; 6247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, 6267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.data1, table.data2, table.line, 6277ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.blink1, table.blink2, table.ilink1, 6287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.ilink2, table.bcon_time, table.gp1, 6297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.gp2, table.gp3, table.ucode_ver, 6307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach table.hw_ver, table.brd_ver); 6316bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id, 6327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach desc_lookup(table.error_id)); 6336bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | uPc\n", table.pc); 6346bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1); 6356bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2); 6366bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1); 6376bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2); 6386bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | data1\n", table.data1); 6396bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | data2\n", table.data2); 6406bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | line\n", table.line); 6416bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time); 6426bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low); 6436bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi); 6446bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1); 6456bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2); 6466bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3); 6476bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver); 6486bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); 6496bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); 6506bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); 651d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy 652d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | isr0\n", table.isr0); 653d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | isr1\n", table.isr1); 654d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | isr2\n", table.isr2); 655d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | isr3\n", table.isr3); 656d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | isr4\n", table.isr4); 657d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | isr_pref\n", table.isr_pref); 658d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | wait_event\n", table.wait_event); 659d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | l2p_control\n", table.l2p_control); 660d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | l2p_duration\n", table.l2p_duration); 661d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); 662d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); 663d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); 664d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | timestamp\n", table.u_timestamp); 665d332f591daca5f5301782bad69f94e160b5fa665Wey-Yi Guy IWL_ERR(trans, "0x%08X | flow_handler\n", table.flow_handler); 6667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 6677ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6687ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach/** 6697ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * iwl_irq_handle_error - called for HW or SW error interrupt from card 6707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 6716bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic void iwl_irq_handle_error(struct iwl_trans *trans) 6727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 6736bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 6747ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ 6757ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (priv->cfg->internal_wimax_coex && 67683ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) & 6777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach APMS_CLK_VAL_MRB_FUNC_MODE) || 67883ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) & 6797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach APMG_PS_CTRL_VAL_RESET_REQ))) { 6807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* 6817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * Keep the restart process from trying to send host 6827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * commands by clearing the ready bit. 6837ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 6846bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach clear_bit(STATUS_READY, &trans->shrd->status); 6856bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); 686effd4d9aece9184f526e6556786a94d335e38b71Johannes Berg wake_up(&priv->shrd->wait_command_queue); 6876bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "RF is used by WiMAX\n"); 6887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return; 6897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 6907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6916bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Loaded firmware version: %s\n", 6927ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach priv->hw->wiphy->fw_version); 6937ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 6946bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_nic_error_log(trans); 6956bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_csr(trans); 6966bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_fh(trans, NULL, false); 6976bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_dump_nic_event_log(trans, false, NULL, false); 6987ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 6996bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) 700522376d206da66cecc90929134ad70c0446e874bEmmanuel Grumbach iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS); 7017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#endif 7027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach iwlagn_fw_error(priv, false); 7047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 7057ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define EVENT_START_OFFSET (4 * sizeof(u32)) 7077ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach/** 7097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * iwl_print_event_log - Dump error event log to syslog 7107ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * 7117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 7126bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, 7137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 num_events, u32 mode, 7147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int pos, char **buf, size_t bufsz) 7157ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 7167ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 i; 7177ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 base; /* SRAM byte address of event log header */ 7187ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ 7197ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 ptr; /* SRAM byte address of log data */ 7207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 ev, time, data; /* event log data */ 7217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach unsigned long reg_flags; 7226bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 7237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num_events == 0) 7257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 7267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 727ae6130fc9b5e9957aaf26355b80e0a5ef7f8f537Don Fry base = trans->shrd->device_pointers.log_event_table; 7283d6acefc0a24bf90746c1f259e9d65d1ed7ea5e2Don Fry if (trans->shrd->ucode_type == IWL_UCODE_INIT) { 7297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 7307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->init_evtlog_ptr; 7317ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 7337ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->inst_evtlog_ptr; 7347ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7357ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7367ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (mode == 0) 7377ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach event_size = 2 * sizeof(u32); 7387ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach else 7397ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach event_size = 3 * sizeof(u32); 7407ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7417ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ptr = base + EVENT_START_OFFSET + (start_idx * event_size); 7427ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7437ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* Make sure device is powered up for SRAM reads */ 7443e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach spin_lock_irqsave(&bus(trans)->reg_lock, reg_flags); 7453e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_grab_nic_access(bus(trans)); 7467ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7477ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* Set starting address; reads will auto-increment */ 7483e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_write32(bus(trans), HBUS_TARG_MEM_RADDR, ptr); 7497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach rmb(); 7507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7517ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* "time" is actually "data" for mode 0 (no timestamp). 7527ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * place event id # at far right for easier visual parsing. */ 7537ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach for (i = 0; i < num_events; i++) { 7543e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach ev = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7553e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach time = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7567ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (mode == 0) { 7577ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* data, ev */ 7587ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (bufsz) { 7597ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos += scnprintf(*buf + pos, bufsz - pos, 7607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "EVT_LOG:0x%08x:%04u\n", 7617ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, ev); 7627ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7637ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach trace_iwlwifi_dev_ucode_event(priv, 0, 7647ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, ev); 7656bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", 7667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, ev); 7677ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7687ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7693e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach data = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (bufsz) { 7717ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos += scnprintf(*buf + pos, bufsz - pos, 7727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "EVT_LOGT:%010u:0x%08x:%04u\n", 7737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, data, ev); 7747ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 7756bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", 7767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach time, data, ev); 7777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach trace_iwlwifi_dev_ucode_event(priv, time, 7787ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach data, ev); 7797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 7827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7837ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* Allow device to power down */ 7843e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_release_nic_access(bus(trans)); 7853e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach spin_unlock_irqrestore(&bus(trans)->reg_lock, reg_flags); 7867ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 7877ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 7887ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 7897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach/** 7907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * iwl_print_last_event_logs - Dump the newest # of event log to syslog 7917ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 7926bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachstatic int iwl_print_last_event_logs(struct iwl_trans *trans, u32 capacity, 7937ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 num_wraps, u32 next_entry, 7947ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 size, u32 mode, 7957ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int pos, char **buf, size_t bufsz) 7967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 7977ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* 7987ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * display the newest DEFAULT_LOG_ENTRIES entries 7997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * i.e the entries just before the next ont that uCode would fill. 8007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 8017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num_wraps) { 8027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (next_entry < size) { 8036bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 8047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach capacity - (size - next_entry), 8057ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size - next_entry, mode, 8067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 8076bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 0, 8087ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, mode, 8097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 8107ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else 8116bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, next_entry - size, 8127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size, mode, pos, buf, bufsz); 8137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 8147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (next_entry < size) { 8156bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 0, next_entry, 8167ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach mode, pos, buf, bufsz); 8177ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 8186bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, next_entry - size, 8197ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size, mode, pos, buf, bufsz); 8207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8227ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 8237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 8247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) 8267ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8276bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachint iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, 8287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach char **buf, bool display) 8297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach{ 8307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 base; /* SRAM byte address of event log header */ 8317ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 capacity; /* event log capacity in # entries */ 8327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ 8337ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 num_wraps; /* # times uCode wrapped to top of log */ 8347ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 next_entry; /* index of next entry to be written by uCode */ 8357ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 size; /* # entries that we'll print */ 8367ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach u32 logsize; 8377ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach int pos = 0; 8387ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size_t bufsz = 0; 8396bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach struct iwl_priv *priv = priv(trans); 8407ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 841ae6130fc9b5e9957aaf26355b80e0a5ef7f8f537Don Fry base = trans->shrd->device_pointers.log_event_table; 8423d6acefc0a24bf90746c1f259e9d65d1ed7ea5e2Don Fry if (trans->shrd->ucode_type == IWL_UCODE_INIT) { 8437ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach logsize = priv->init_evtlog_size; 8447ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 8457ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->init_evtlog_ptr; 8467ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else { 8477ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach logsize = priv->inst_evtlog_size; 8487ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!base) 8497ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base = priv->inst_evtlog_ptr; 8507ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8517ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8527ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!iwlagn_hw_valid_rtc_data_addr(base)) { 8536bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, 8547ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach "Invalid event log pointer 0x%08X for %s uCode\n", 8557ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach base, 8563d6acefc0a24bf90746c1f259e9d65d1ed7ea5e2Don Fry (trans->shrd->ucode_type == IWL_UCODE_INIT) 8577ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? "Init" : "RT"); 8587ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return -EINVAL; 8597ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8607ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8617ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* event log header */ 8623e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach capacity = iwl_read_targ_mem(bus(trans), base); 8633e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32))); 8643e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32))); 8653e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32))); 8667ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8677ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (capacity > logsize) { 8686bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " 8696bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach "entries\n", capacity, logsize); 8707ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach capacity = logsize; 8717ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8727ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8737ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (next_entry > logsize) { 8746bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", 8757ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, logsize); 8767ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry = logsize; 8777ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8787ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8797ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size = num_wraps ? capacity : next_entry; 8807ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8817ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* bail out if nothing in log */ 8827ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (size == 0) { 8836bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); 8847ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 8857ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 8867ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8877ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 8886bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log) 8897ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 8907ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 8917ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#else 8927ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 8937ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 8947ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#endif 8956bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", 8967ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach size); 8977ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 8987ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 8997ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (display) { 9007ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (full_log) 9017ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach bufsz = capacity * 48; 9027ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach else 9037ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach bufsz = size * 48; 9047ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach *buf = kmalloc(bufsz, GFP_KERNEL); 9057ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (!*buf) 9067ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return -ENOMEM; 9077ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } 9086bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) { 9097ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* 9107ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * if uCode has wrapped back to top of log, 9117ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * start at the oldest entry, 9127ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach * i.e the next one that uCode would fill. 9137ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach */ 9147ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach if (num_wraps) 9156bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, next_entry, 9167ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach capacity - next_entry, mode, 9177ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 9187ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach /* (then/else) start at top of log */ 9196bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_event_log(trans, 0, 9207ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, mode, pos, buf, bufsz); 9217ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach } else 9226bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_last_event_logs(trans, capacity, num_wraps, 9237ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, size, mode, 9247ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 9257ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#else 9266bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach pos = iwl_print_last_event_logs(trans, capacity, num_wraps, 9277ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach next_entry, size, mode, 9287ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach pos, buf, bufsz); 9297ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach#endif 9307ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach return pos; 9317ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach} 9327ff94706a055f3e21710b08ffbe3979d7db615dbEmmanuel Grumbach 933ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach/* tasklet for iwlagn interrupt */ 9340c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachvoid iwl_irq_tasklet(struct iwl_trans *trans) 935ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach{ 936ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 inta = 0; 937ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 handled = 0; 938ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach unsigned long flags; 939ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 i; 940ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 941ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach u32 inta_mask; 942ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#endif 943ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9443e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 9451f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach struct isr_statistics *isr_stats = &trans_pcie->isr_stats; 9461f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach 9470c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 9480c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 949ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 950ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Ack/clear/reset pending uCode interrupts. 951ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, 952ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 953ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* There is a hardware bug in the interrupt mask function that some 954ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if 955ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * they are disabled in the CSR_INT_MASK register. Furthermore the 956ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * ICT interrupt handling mechanism has another bug that might cause 957ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * these unmasked interrupts fail to be detected. We workaround the 958ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * hardware bugs here by ACKing all the possible interrupts so that 959ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * interrupt coalescing can still be achieved. 960ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 96183ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT, 9620c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta | ~trans_pcie->inta_mask); 963ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9640c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach inta = trans_pcie->inta; 965ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 966ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 9670c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) { 968ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* just for debug */ 96983ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); 9700c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ", 971ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach inta, inta_mask); 972ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 973ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#endif 974ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9750c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 976ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9770c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach /* saved interrupt in inta variable now we can reset trans_pcie->inta */ 9780c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta = 0; 979ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 980ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Now service all interrupt bits discovered above. */ 981ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_HW_ERR) { 9820c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Hardware error detected. Restarting.\n"); 983ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 984ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Tell the device to stop sending interrupts */ 9850c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_disable_interrupts(trans); 986ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 9871f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->hw++; 9886bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_irq_handle_error(trans); 989ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 990ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_HW_ERR; 991ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 992ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach return; 993ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 994ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 995ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 9960c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { 997ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* NIC fires this, but we don't use it, redundant with WAKEUP */ 998ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_SCD) { 9990c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Scheduler finished to transmit " 1000ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach "the frame/frames.\n"); 10011f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->sch++; 1002ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1003ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1004ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Alive notification via Rx interrupt will do the real work */ 1005ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_ALIVE) { 10060c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Alive interrupt\n"); 10071f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->alive++; 1008ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1009ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1010ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach#endif 1011ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Safely ignore these bits for debug checks below */ 1012ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); 1013ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1014ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* HW RF KILL switch toggled */ 1015ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_RF_KILL) { 1016ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach int hw_rf_kill = 0; 101783ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & 1018ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) 1019ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach hw_rf_kill = 1; 1020ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10210c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", 1022ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach hw_rf_kill ? "disable radio" : "enable radio"); 1023ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10241f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->rfkill++; 1025ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1026ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* driver only loads ucode once setting the interface up. 1027ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the driver allows loading the ucode even if the radio 1028ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * is killed. Hence update the killswitch state here. The 1029ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * rfkill handler will care about restarting if needed. 1030ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 10310c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!test_bit(STATUS_ALIVE, &trans->shrd->status)) { 1032ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (hw_rf_kill) 10330c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach set_bit(STATUS_RF_KILL_HW, 10340c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach &trans->shrd->status); 1035ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else 103663013ae30159c90d2a873e20e680e7810fa533faEmmanuel Grumbach clear_bit(STATUS_RF_KILL_HW, 10370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach &trans->shrd->status); 10383e10caeb55b2693b38f1f80c67c79d918fc42e42Emmanuel Grumbach iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill); 1039ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1040ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1041ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_RF_KILL; 1042ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1043ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1044ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Chip got too hot and stopped itself */ 1045ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_CT_KILL) { 10460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Microcode CT kill error detected.\n"); 10471f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->ctkill++; 1048ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_CT_KILL; 1049ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1050ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1051ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Error detected by uCode */ 1052ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_SW_ERR) { 10530c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Microcode SW error detected. " 1054ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach " Restarting 0x%X.\n", inta); 10551f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->sw++; 10566bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbach iwl_irq_handle_error(trans); 1057ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_SW_ERR; 1058ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1059ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1060ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* uCode wakes up after power-down sleep */ 1061ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_WAKEUP) { 10620c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); 10630c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq); 10640c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach for (i = 0; i < hw_params(trans).max_txq_num; i++) 1065fd656935cd05f522d7db97386633f6a0d7751218Emmanuel Grumbach iwl_txq_update_write_ptr(trans, 10668ad71bef4a9d8173cbcfbb2f796b08d33d4ca01bEmmanuel Grumbach &trans_pcie->txq[i]); 1067ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 10681f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->wakeup++; 1069ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1070ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_WAKEUP; 1071ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1072ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1073ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* All uCode command responses, including Tx command responses, 1074ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Rx "responses" (frame-received notification), and other 1075ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * notifications from uCode come through here*/ 1076ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | 1077ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_INT_BIT_RX_PERIODIC)) { 10780c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Rx interrupt\n"); 1079ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { 1080ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); 108183ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_FH_INT_STATUS, 1082ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_FH_INT_RX_MASK); 1083ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1084ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_RX_PERIODIC) { 1085ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_RX_PERIODIC; 108683ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), 10870c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach CSR_INT, CSR_INT_BIT_RX_PERIODIC); 1088ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1089ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Sending RX interrupt require many steps to be done in the 1090ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * the device: 1091ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 1- write interrupt to current index in ICT table. 1092ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 2- dma RX frame. 1093ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 3- update RX shared data to indicate last write index. 1094ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * 4- send interrupt. 1095ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * This could lead to RX race, driver could receive RX interrupt 1096ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * but the shared data changes does not reflect this; 1097ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * periodic interrupt will detect any dangling Rx activity. 1098ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1099ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1100ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Disable periodic interrupt; we use it as just a one-shot. */ 110183ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, 1102ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_INT_PERIODIC_DIS); 11030c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_rx_handle(trans); 1104ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1105ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* 1106ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * Enable periodic interrupt in 8 msec only if we received 1107ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * real RX interrupt (instead of just periodic int), to catch 1108ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * any dangling Rx interrupt. If it was just the periodic 1109ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * interrupt, there was no dangling Rx activity, and no need 1110ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach * to extend the periodic interrupt; one-shot is enough. 1111ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach */ 1112ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) 111383ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, 1114ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach CSR_INT_PERIODIC_ENA); 1115ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 11161f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->rx++; 1117ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1118ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1119ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* This "Tx" DMA channel is used only for loading uCode */ 1120ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & CSR_INT_BIT_FH_TX) { 112183ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); 11220c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); 11231f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->tx++; 1124ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach handled |= CSR_INT_BIT_FH_TX; 1125ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Wake up uCode load routine, now that load is complete */ 11265703ddb01328c8ee3fa315273ea3b29f6524fb38Don Fry trans->ucode_write_complete = 1; 1127effd4d9aece9184f526e6556786a94d335e38b71Johannes Berg wake_up(&trans->shrd->wait_command_queue); 1128ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1129ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1130ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach if (inta & ~handled) { 11310c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled); 11321f7b6172db86e9ab2b4cd794441bb2c40ab287fcEmmanuel Grumbach isr_stats->unhandled++; 1133ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1134ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 11350c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (inta & ~(trans_pcie->inta_mask)) { 11360c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n", 11370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach inta & ~trans_pcie->inta_mask); 1138ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach } 1139ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 1140ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Re-enable all interrupts */ 1141ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* only Re-enable if disabled by irq */ 11420c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status)) 11430c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 1144ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach /* Re-enable RF_KILL if it occurred */ 1145ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach else if (handled & CSR_INT_BIT_RF_KILL) 11460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_rfkill_int(priv(trans)); 1147ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach} 1148ab697a9f1e73ba817955e15bd899a8a0627f9fd6Emmanuel Grumbach 11491a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/****************************************************************************** 11501a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * 11511a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * ICT functions 11521a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * 11531a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach ******************************************************************************/ 11541a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) 11551a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11561a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* Free dram table */ 11570c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachvoid iwl_free_isr_ict(struct iwl_trans *trans) 11581a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 11590c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 11600c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 11610c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 11620c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (trans_pcie->ict_tbl_vir) { 11630c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach dma_free_coherent(bus(trans)->dev, 11641a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 11650c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_vir, 11660c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma); 11670c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_vir = NULL; 11680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(&trans_pcie->ict_tbl_dma, 0, 11690c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach sizeof(trans_pcie->ict_tbl_dma)); 11700c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(&trans_pcie->aligned_ict_tbl_dma, 0, 11710c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach sizeof(trans_pcie->aligned_ict_tbl_dma)); 11721a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 11731a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 11741a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11751a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11761a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* allocate dram shared table it is a PAGE_SIZE aligned 11771a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * also reset all data related to ICT table interrupt. 11781a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 11790c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachint iwl_alloc_isr_ict(struct iwl_trans *trans) 11801a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 11810c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 11820c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 11831a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11841a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* allocate shrared data table */ 11850c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_vir = 11860c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach dma_alloc_coherent(bus(trans)->dev, 11871a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 11880c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach &trans_pcie->ict_tbl_dma, GFP_KERNEL); 11890c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->ict_tbl_vir) 11901a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return -ENOMEM; 11911a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11921a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* align table to PAGE_SIZE boundary */ 11930c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->aligned_ict_tbl_dma = 11940c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE); 11951a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 11960c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n", 11970c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (unsigned long long)trans_pcie->ict_tbl_dma, 11980c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (unsigned long long)trans_pcie->aligned_ict_tbl_dma, 11990c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (int)(trans_pcie->aligned_ict_tbl_dma - 12000c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma)); 12011a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12020c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir + 12030c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (trans_pcie->aligned_ict_tbl_dma - 12040c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma); 12051a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12060c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n", 12070c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir, 12080c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (int)(trans_pcie->aligned_ict_tbl_dma - 12090c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl_dma)); 12101a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12111a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* reset table and index to all 0 */ 12120c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(trans_pcie->ict_tbl_vir, 0, 12131a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); 12140c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index = 0; 12151a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12161a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* add periodic RX interrupt */ 12170c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC; 12181a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return 0; 12191a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 12201a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12211a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* Device is going up inform it about using ICT interrupt table, 12221a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * also we need to tell the driver to start using ICT interrupt. 12231a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 12246bb7884758965ad0afd67801f0f41cefd53d0b0cEmmanuel Grumbachint iwl_reset_ict(struct iwl_trans *trans) 12251a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 12261a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 val; 12271a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 12280c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 12290c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 12301a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12310c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->ict_tbl_vir) 12321a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return 0; 12331a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12340c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 12350c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_disable_interrupts(trans); 12361a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); 12381a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12390c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT; 12401a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12411a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val |= CSR_DRAM_INT_TBL_ENABLE; 12421a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; 12431a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12440c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X " 12451a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach "aligned dma address %Lx\n", 12461a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val, 12470c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach (unsigned long long)trans_pcie->aligned_ict_tbl_dma); 12481a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 124983ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); 12500c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->use_ict = true; 12510c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index = 0; 125283ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT, trans_pcie->inta_mask); 12530c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 12540c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 12551a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12561a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return 0; 12571a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 12581a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12591a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* Device is going down disable ict interrupt usage */ 12600c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbachvoid iwl_disable_ict(struct iwl_trans *trans) 12611a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 12620c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie = 12630c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_TRANS_GET_PCIE_TRANS(trans); 12640c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 12651a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 12661a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12670c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 12680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->use_ict = false; 12690c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 12701a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 12711a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12721a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbachstatic irqreturn_t iwl_isr(int irq, void *data) 12731a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 12740c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans *trans = data; 12750c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie; 12761a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 inta, inta_mask; 12771a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 12781a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 12791a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 inta_fh; 12801a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#endif 12810c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans) 12821a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 12831a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12840c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 12850c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 12860c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 12871a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12881a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Disable (but don't clear!) interrupts here to avoid 12891a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * back-to-back ISRs and sporadic interrupts from our NIC. 12901a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we have something to service, the tasklet will re-enable ints. 12911a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we *don't* have something, we'll re-enable before leaving here. */ 129283ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ 129383ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); 12941a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12951a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Discover which interrupts are active/pending */ 129683ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta = iwl_read32(bus(trans), CSR_INT); 12971a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 12981a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Ignore interrupt if there's nothing in NIC to service. 12991a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * This may be due to IRQ shared with another device, 13001a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * or due to sporadic interrupts thrown from our NIC. */ 13011a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (!inta) { 13020c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); 13031a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach goto none; 13041a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13051a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13061a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { 13071a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Hardware disappeared. It might have already raised 13081a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * an interrupt */ 13090c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta); 13101a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach goto unplugged; 13111a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13121a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13131a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#ifdef CONFIG_IWLWIFI_DEBUG 13140c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { 131583ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_fh = iwl_read32(bus(trans), CSR_FH_INT_STATUS); 13160c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, " 13171a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach "fh 0x%08x\n", inta, inta_mask, inta_fh); 13181a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13191a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach#endif 13201a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13210c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta |= inta; 13221a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* iwl_irq_tasklet() will service interrupts and re-enable them */ 13231a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (likely(inta)) 13240c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach tasklet_schedule(&trans_pcie->irq_tasklet); 13250c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 13260c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) 13270c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 13281a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13291a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unplugged: 13300c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 13311a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_HANDLED; 13321a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13331a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach none: 13341a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* re-enable interrupts here since we don't have anything to service. */ 13351a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* only Re-enable if disabled by irq and no schedules tasklet. */ 13360c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 13370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) 13380c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 13391a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13400c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 13411a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 13421a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 13431a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13441a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach/* interrupt handler using ict table, with this interrupt driver will 13451a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * stop using INTA register to get device's interrupt, reading this register 13461a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * is expensive, device will write interrupts in ICT dram table, increment 13471a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * index then will fire interrupt to driver, driver will OR all ICT table 13481a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * entries from current index up to table entry with 0 value. the result is 13491a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * the interrupt we need to service, driver will set the entries back to 0 and 13501a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * set index. 13511a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 13521a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbachirqreturn_t iwl_isr_ict(int irq, void *data) 13531a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach{ 13540c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans *trans = data; 13550c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach struct iwl_trans_pcie *trans_pcie; 13561a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 inta, inta_mask; 13571a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach u32 val = 0; 13581a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach unsigned long flags; 13591a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13600c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans) 13611a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 13621a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13630c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 13640c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach 13651a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* dram interrupt table not set yet, 13661a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * use legacy interrupt. 13671a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 13680c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->use_ict) 13691a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return iwl_isr(irq, data); 13701a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13710c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_lock_irqsave(&trans->shrd->lock, flags); 13721a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13731a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Disable (but don't clear!) interrupts here to avoid 13741a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * back-to-back ISRs and sporadic interrupts from our NIC. 13751a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we have something to service, the tasklet will re-enable ints. 13761a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * If we *don't* have something, we'll re-enable before leaving here. 13771a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 137883ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ 137983ed90155f98bd949735c2cc22d832b557a6d7d1Emmanuel Grumbach iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); 13801a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13811a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13821a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Ignore interrupt if there's nothing in NIC to service. 13831a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * This may be due to IRQ shared with another device, 13841a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * or due to sporadic interrupts thrown from our NIC. */ 13850c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (!trans_pcie->ict_tbl[trans_pcie->ict_index]) { 13860c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); 13871a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach goto none; 13881a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 13891a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13901a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* read all entries that not 0 start with ict_index */ 13910c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach while (trans_pcie->ict_tbl[trans_pcie->ict_index]) { 13921a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 13930c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach val |= le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); 13940c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", 13950c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index, 13961a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach le32_to_cpu( 13970c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl[trans_pcie->ict_index])); 13980c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; 13990c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->ict_index = 14000c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); 14011a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14021a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 14031a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14041a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* We should not get this value, just ignore it. */ 14051a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (val == 0xffffffff) 14061a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val = 0; 14071a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14081a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* 14091a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit 14101a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * (bit 15 before shifting it to 31) to clear when using interrupt 14111a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * coalescing. fortunately, bits 18 and 19 stay set when this happens 14121a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * so we use them to decide on the real state of the Rx bit. 14131a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * In order words, bit 15 is set if bit 18 or bit 19 are set. 14141a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 14151a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (val & 0xC0000) 14161a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach val |= 0x8000; 14171a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14181a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach inta = (0xff & val) | ((0xff00 & val) << 16); 14190c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", 14201a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach inta, inta_mask, val); 14211a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14220c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach inta &= trans_pcie->inta_mask; 14230c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach trans_pcie->inta |= inta; 14241a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14251a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* iwl_irq_tasklet() will service interrupts and re-enable them */ 14261a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach if (likely(inta)) 14270c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach tasklet_schedule(&trans_pcie->irq_tasklet); 14280c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 14290c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) { 14301a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* Allow interrupt if was disabled by this handler and 14311a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * no tasklet was schedules, We should not enable interrupt, 14321a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * tasklet will enable it. 14331a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 14340c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 14351a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach } 14361a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14370c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 14381a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_HANDLED; 14391a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14401a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach none: 14411a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach /* re-enable interrupts here since we don't have anything to service. 14421a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach * only Re-enable if disabled by irq. 14431a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach */ 14440c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 14450c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach !trans_pcie->inta) 14460c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach iwl_enable_interrupts(trans); 14471a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach 14480c325769a394559941acda83e888a1d9b1ef8b7fEmmanuel Grumbach spin_unlock_irqrestore(&trans->shrd->lock, flags); 14491a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach return IRQ_NONE; 14501a361cd838173879672cb0f0ebe1e7654d7edff6Emmanuel Grumbach} 1451