iwl-trans-pcie-rx.c revision d56da92092c7808fea0b6ad85fd97095067a2616
1a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton/****************************************************************************** 20e7072ef6623c3dc58faf3f7310aba77b0a5845eMichael Krufky * 3a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. 4a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 54ac97914c6c35f6bf132071c718e034d0846b9f5Mauro Carvalho Chehab * Portions of this file are derived from the ipw3945 project, as well 62e7c6dc3989136844eb63e05f9e4dc6608a763c6Mauro Carvalho Chehab * as portions of the ieee80211 subsystem header files. 7a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 8a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * This program is free software; you can redistribute it and/or modify it 9a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * under the terms of version 2 of the GNU General Public License as 10a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * published by the Free Software Foundation. 11a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 12a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * This program is distributed in the hope that it will be useful, but WITHOUT 13a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * more details. 16a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 17a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * You should have received a copy of the GNU General Public License along with 18a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * this program; if not, write to the Free Software Foundation, Inc., 19a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 20a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 21a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * The full GNU General Public License is included in this distribution in the 22a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * file called LICENSE. 23a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 24a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * Contact Information: 253acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab * Intel Linux Wireless <ilw@linux.intel.com> 263acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 28cb77d010221e66c63f4a71546fed73be9b12b9a3Mauro Carvalho Chehab *****************************************************************************/ 29ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab#include <linux/sched.h> 30f2cf250af156bef127433efd255abfae6aab02f6Douglas Schilling Landgraf#include <linux/wait.h> 31ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab#include <linux/gfp.h> 32a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 333593cab5d62c4c7abced1076710f9bc2d8847433Ingo Molnar/*TODO: Remove include to iwl-core.h*/ 34d5e5265315770bda46c50ecaa64e2b9790f2064cMauro Carvalho Chehab#include "iwl-core.h" 353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "iwl-io.h" 363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "iwl-helpers.h" 373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "iwl-trans-pcie-int.h" 383ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab 392ba890ec0849b222a6dabb5192ccd8fd1696d6d3Mauro Carvalho Chehab/****************************************************************************** 403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * RX path functions 423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab ******************************************************************************/ 443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* 463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Rx theory of operation 473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 483aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), 493aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * each of which point to Receive Buffers to be filled by the NIC. These get 503aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * used not only for Rx frames, but for any command response or notification 513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * from the NIC. The driver and NIC manage the Rx buffers by means 523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * of indexes into the circular buffer. 533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 543aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Rx Queue Indexes 553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * The host/firmware share two index registers for managing the Rx buffers. 563aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 573aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * The READ index maps to the first position that the firmware may be writing 5810ac6603613d46a43a4544fbbe9581e50879bd45Mauro Carvalho Chehab * to -- the driver can read up to (but not including) this position and get 594fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller * good data. 6017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller * The READ index is managed by the firmware once the card is enabled. 613ed58baf5db4eab553803916a990a3dbca4dc611Devin Heitmueller * 62e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller * The WRITE index maps to the last position the driver has read from -- the 6359d07f1b705c466ea4eaca9c43d46be6d6a065a4Aron Szabo * position preceding WRITE is the last slot the firmware can place a packet. 6495b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 6595b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * The queue is empty (no good data) if WRITE = READ - 1, and is full if 6695b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * WRITE = READ. 6795b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 6895b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * During initialization, the host sets up the READ queue position to the first 6995b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * INDEX position, and WRITE to the last (READ - 1 wrapped) 7095b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 7195b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * When the firmware places a packet in a buffer, it will advance the READ index 7295b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * and fire the RX interrupt. The driver can then query the READ index and 7395b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * process as many packets as possible, moving the WRITE index forward as it 7495b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * resets the Rx queue buffers with new memory. 7595b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 7695b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * The management in the driver is as follows: 7795b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When 7895b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled 7995b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * to replenish the iwl->rxq->rx_free. 8095b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the 8195b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * iwl->rxq is replenished and the READ INDEX is updated (updating the 8295b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 'processed' and 'read' driver indexes as well) 8395b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * + A received packet is processed and handed to the kernel network stack, 8495b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * detached from the iwl->rxq. The driver 'processed' index is updated. 8595b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free 8695b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ 8795b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there 8895b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * were enough free buffers and RX_STALLED is set it is cleared. 8995b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 9095b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 9195b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * Driver sequence: 9295b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * 9395b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * iwl_rx_queue_alloc() Allocates rx_free 9495b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls 9595b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * iwl_rx_queue_restock 9695b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx 976e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora * queue, updates firmware pointers, and updates 98ee281b856d4e4921da24387ab116bb0855c2efaaMauro Carvalho Chehab * the WRITE index. If insufficient rx_free buffers 99f89bc32974a4376e8393001484af28d8c3350ab4Douglas Schilling Landgraf * are available, schedules iwl_rx_replenish 1001e1addd57bdf56c51dbc292d7760ea3d207fe833Douglas Schilling Landgraf * 101f7fe3e6f3c3e9ef6ba5ca187b514d225296d18ddDouglas Schilling Landgraf * -- enable interrupts -- 10256ee38071fe0cf1746d53c5b40a46a835b24fbe4Mauro Carvalho Chehab * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the 10356ee38071fe0cf1746d53c5b40a46a835b24fbe4Mauro Carvalho Chehab * READ INDEX, detaching the SKB from the pool. 104f74a61e3c6f218053742c2caf3e247fb41bf395eIndika Katugampala * Moves the packet buffer from queue to rx_used. 105e5db5d44432abc82b1250dd05bd0a4b011392d9dDouglas Schilling Landgraf * Calls iwl_rx_queue_restock to refill any empty 1064557af9c5338605c85fe54f5ebba3d4b14a60ab8Mauro Carvalho Chehab * slots. 107766ed64de554fda08ceb927d36279eabcb08acb3Mauro Carvalho Chehab * ... 108d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng * 10919859229d7d98bc2d582ff45045dd7f73d649383Devin Heitmueller */ 11002e7804b2135ff941b8846f5820cf48fbfdadd54Mauro Carvalho Chehab 1113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/** 1123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * iwl_rx_queue_space - Return number of free slots available in queue. 1133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 1143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int iwl_rx_queue_space(const struct iwl_rx_queue *q) 115a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton{ 116c4a98793a63c423c9e1af51822325969e23c16d4Mauro Carvalho Chehab int s = q->read - q->write; 117c4a98793a63c423c9e1af51822325969e23c16d4Mauro Carvalho Chehab if (s <= 0) 118c4a98793a63c423c9e1af51822325969e23c16d4Mauro Carvalho Chehab s += RX_QUEUE_SIZE; 11995b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf /* keep some buffer to not confuse full and empty queue */ 12095b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf s -= 2; 12195b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf if (s < 0) 12295b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf s = 0; 12322cff7b381eca256d2afb460b3b9815f83810011Douglas Schilling Landgraf return s; 12422cff7b381eca256d2afb460b3b9815f83810011Douglas Schilling Landgraf} 12522cff7b381eca256d2afb460b3b9815f83810011Douglas Schilling Landgraf 12622cff7b381eca256d2afb460b3b9815f83810011Douglas Schilling Landgraf/** 127596d92d5128d308b5a79f21c3e72c87f5fc7e58bMauro Carvalho Chehab * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue 1283687e1e67e4920a202d53cc24678fb34fcda8fc5Mauro Carvalho Chehab */ 129596d92d5128d308b5a79f21c3e72c87f5fc7e58bMauro Carvalho Chehabvoid iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, 130a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct iwl_rx_queue *q) 1313acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab{ 132a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton unsigned long flags; 1333acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab u32 reg; 134a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 135a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton spin_lock_irqsave(&q->lock, flags); 1363acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 137a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (q->need_update == 0) 138d5e5265315770bda46c50ecaa64e2b9790f2064cMauro Carvalho Chehab goto exit_unlock; 139d5e5265315770bda46c50ecaa64e2b9790f2064cMauro Carvalho Chehab 140d5e5265315770bda46c50ecaa64e2b9790f2064cMauro Carvalho Chehab if (hw_params(trans).shadow_reg_enable) { 141d5e5265315770bda46c50ecaa64e2b9790f2064cMauro Carvalho Chehab /* shadow register enabled */ 1423acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab /* Device expects a multiple of 8 */ 143a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton q->write_actual = (q->write & ~0x7); 144a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_write32(bus(trans), FH_RSCSR_CHNL0_WPTR, q->write_actual); 1453acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab } else { 146a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* If power-saving is in use, make sure device is awake */ 1473acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { 148a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); 149a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 150a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { 151a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton IWL_DEBUG_INFO(trans, 152a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "Rx queue requesting wakeup," 153a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton " GP1 = 0x%x\n", reg); 154a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_set_bit(bus(trans), CSR_GP_CNTRL, 155a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 156a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton goto exit_unlock; 157a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 158a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 159a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton q->write_actual = (q->write & ~0x7); 160a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, 161a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton q->write_actual); 162a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 163a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* Else device is assumed to be awake */ 164a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } else { 165a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* Device expects a multiple of 8 */ 166a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton q->write_actual = (q->write & ~0x7); 167a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, 168a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton q->write_actual); 169a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 170a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 171a1a6ee74f2c68918f2e145dccba3637eea91a52aNicola Soranzo q->need_update = 0; 172a1a6ee74f2c68918f2e145dccba3637eea91a52aNicola Soranzo 173a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton exit_unlock: 174596d92d5128d308b5a79f21c3e72c87f5fc7e58bMauro Carvalho Chehab spin_unlock_irqrestore(&q->lock, flags); 175596d92d5128d308b5a79f21c3e72c87f5fc7e58bMauro Carvalho Chehab} 176596d92d5128d308b5a79f21c3e72c87f5fc7e58bMauro Carvalho Chehab 1773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/** 1782fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr 1793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 1803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) 1813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{ 1823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab return cpu_to_le32((u32)(dma_addr >> 8)); 1833acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab} 184a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 185a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton/** 186a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool 187a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 188a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * If there are slots in the RX queue that need to be restocked, 189579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton * and we have free pre-allocated buffers, fill the ranks as much 190579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton * as we can, pulling from rx_free. 191ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * 192ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * This moves the 'write' index forward to catch up with 'processed', and 193ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * also updates the memory address in the firmware to reference the new 194ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * target buffer. 195ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab */ 196ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehabstatic void iwlagn_rx_queue_restock(struct iwl_trans *trans) 197ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab{ 198ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab struct iwl_trans_pcie *trans_pcie = 199ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab IWL_TRANS_GET_PCIE_TRANS(trans); 200ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab 201ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab struct iwl_rx_queue *rxq = &trans_pcie->rxq; 202ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab struct list_head *element; 203ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab struct iwl_rx_mem_buffer *rxb; 204ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab unsigned long flags; 205ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab 206ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab spin_lock_irqsave(&rxq->lock, flags); 207ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { 208ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab /* The overwritten rxb must be a used one */ 209ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab rxb = rxq->queue[rxq->write]; 210ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab BUG_ON(rxb && rxb->page); 211ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab 212ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab /* Get next free Rx buffer, remove from free list */ 213ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab element = rxq->rx_free.next; 214ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab rxb = list_entry(element, struct iwl_rx_mem_buffer, list); 215ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab list_del(element); 216ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab 217ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab /* Point to Rx buffer via next RBD in circular buffer */ 218ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma); 219ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab rxq->queue[rxq->write] = rxb; 220579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; 221579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton rxq->free_count--; 222579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton } 223579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton spin_unlock_irqrestore(&rxq->lock, flags); 224ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab /* If the pre-allocated buffer pool is dropping low, schedule to 225ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * refill it */ 226bddcf63313c6a4a85f94db092f45e31f530da691Mauro Carvalho Chehab if (rxq->free_count <= RX_LOW_WATERMARK) 227ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); 228ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab 229ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab 230bddcf63313c6a4a85f94db092f45e31f530da691Mauro Carvalho Chehab /* If we've added more space for the firmware to place data, tell it. 231bddcf63313c6a4a85f94db092f45e31f530da691Mauro Carvalho Chehab * Increment device's write pointer in multiples of 8. */ 232ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab if (rxq->write_actual != (rxq->write & ~0x7)) { 233ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab spin_lock_irqsave(&rxq->lock, flags); 234ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab rxq->need_update = 1; 235ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 236ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab iwl_rx_queue_update_write_ptr(trans, rxq); 237ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab } 238ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab} 239a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 240a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton/** 241ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free 242ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * 243ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * When moving to rx_free an SKB is allocated for the slot. 244ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * 245ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * Also restock the Rx queue via iwl_rx_queue_restock. 246ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab * This is called as a scheduled work item (except for during initialization) 247ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab */ 248ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehabstatic void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) 249ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab{ 250ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab struct iwl_trans_pcie *trans_pcie = 251ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab IWL_TRANS_GET_PCIE_TRANS(trans); 252a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 253a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct iwl_rx_queue *rxq = &trans_pcie->rxq; 254a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct list_head *element; 2553acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab struct iwl_rx_mem_buffer *rxb; 256a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct page *page; 257a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton unsigned long flags; 258a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton gfp_t gfp_mask = priority; 259a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 260a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton while (1) { 261a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton spin_lock_irqsave(&rxq->lock, flags); 262a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (list_empty(&rxq->rx_used)) { 2633acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 2643acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab return; 2653acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab } 2663acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 2673acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 2683acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab if (rxq->free_count > RX_LOW_WATERMARK) 2693acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab gfp_mask |= __GFP_NOWARN; 2703acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 2713acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab if (hw_params(trans).rx_page_order > 0) 2723acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab gfp_mask |= __GFP_COMP; 2733acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 2743acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab /* Alloc a new receive buffer */ 275a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton page = alloc_pages(gfp_mask, 276a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton hw_params(trans).rx_page_order); 27735643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab if (!page) { 27835643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab if (net_ratelimit()) 27935643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab IWL_DEBUG_INFO(trans, "alloc_pages failed, " 280209acc02249d831e7f2e3d8083b6b562dde5fc6fMauro Carvalho Chehab "order: %d\n", 28135643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab hw_params(trans).rx_page_order); 28235643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab 28335643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab if ((rxq->free_count <= RX_LOW_WATERMARK) && 28435643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab net_ratelimit()) 28535643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab IWL_CRIT(trans, "Failed to alloc_pages with %s." 28635643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab "Only %u free buffers remaining.\n", 28735643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab priority == GFP_ATOMIC ? 28816c7bcadff2222b297d13951dc30e133f56d0154Mauro Carvalho Chehab "GFP_ATOMIC" : "GFP_KERNEL", 28935643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab rxq->free_count); 29035643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab /* We don't reschedule replenish work here -- we will 29135643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab * call the restock method and if it still needs 29235643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab * more buffers it will schedule replenish */ 29335643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab return; 2945c2231c84304563fd5d28e8bbb72e09e882a8e32Devin Heitmueller } 2955c2231c84304563fd5d28e8bbb72e09e882a8e32Devin Heitmueller 2965faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab spin_lock_irqsave(&rxq->lock, flags); 2975faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab 2985faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab if (list_empty(&rxq->rx_used)) { 2995faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 3005faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab __free_pages(page, hw_params(trans).rx_page_order); 3015faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab return; 302539c96d0fd86bfdcfac75c88b74aa5798439293dMauro Carvalho Chehab } 3035faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab element = rxq->rx_used.next; 3045faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab rxb = list_entry(element, struct iwl_rx_mem_buffer, list); 3055faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab list_del(element); 3065faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab 3075faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 3085faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab 3095faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab BUG_ON(rxb->page); 3105faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab rxb->page = page; 3115faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab /* Get physical address of the RB */ 3125faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab rxb->page_dma = dma_map_page(bus(trans)->dev, page, 0, 3135faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab PAGE_SIZE << hw_params(trans).rx_page_order, 3145faff78904d9c07f38ac0e227b322e9f58d5447cMauro Carvalho Chehab DMA_FROM_DEVICE); 315539c96d0fd86bfdcfac75c88b74aa5798439293dMauro Carvalho Chehab /* dma address must be no more than 36 bits */ 316539c96d0fd86bfdcfac75c88b74aa5798439293dMauro Carvalho Chehab BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); 31735ae6f04ad3e4c3ed8a83382b6511bd9beb5c768Mauro Carvalho Chehab /* and also 256 byte aligned! */ 3188866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); 319e879b8ebb000298f8124fc8fae570afc9eb37cbbMauro Carvalho Chehab 320e879b8ebb000298f8124fc8fae570afc9eb37cbbMauro Carvalho Chehab spin_lock_irqsave(&rxq->lock, flags); 321e879b8ebb000298f8124fc8fae570afc9eb37cbbMauro Carvalho Chehab 322e879b8ebb000298f8124fc8fae570afc9eb37cbbMauro Carvalho Chehab list_add_tail(&rxb->list, &rxq->rx_free); 323e879b8ebb000298f8124fc8fae570afc9eb37cbbMauro Carvalho Chehab rxq->free_count++; 3248866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab 3258866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 3268866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab } 3278866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab} 3288866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab 3298866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehabvoid iwlagn_rx_replenish(struct iwl_trans *trans) 3308866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab{ 3318866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab unsigned long flags; 3328866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab 3338866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab iwlagn_rx_allocate(trans, GFP_KERNEL); 3348866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab 3358866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab spin_lock_irqsave(&trans->shrd->lock, flags); 3368866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab iwlagn_rx_queue_restock(trans); 33735ae6f04ad3e4c3ed8a83382b6511bd9beb5c768Mauro Carvalho Chehab spin_unlock_irqrestore(&trans->shrd->lock, flags); 33835ae6f04ad3e4c3ed8a83382b6511bd9beb5c768Mauro Carvalho Chehab} 33932929fb4c7c4a693ed723253b21e7bf3c8cb4b1cHans Verkuil 3408866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehabstatic void iwlagn_rx_replenish_now(struct iwl_trans *trans) 3418866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab{ 3428866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab iwlagn_rx_allocate(trans, GFP_ATOMIC); 3438866f9cf8d85f3614855a49b9d9056f265d0cd33Mauro Carvalho Chehab 344122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab iwlagn_rx_queue_restock(trans); 345122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab} 346122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab 347122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehabvoid iwl_bg_rx_replenish(struct work_struct *data) 348122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab{ 349122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab struct iwl_trans_pcie *trans_pcie = 3503acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab container_of(data, struct iwl_trans_pcie, rx_replenish); 3513acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab struct iwl_trans *trans = trans_pcie->trans; 352a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 353539c96d0fd86bfdcfac75c88b74aa5798439293dMauro Carvalho Chehab if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) 35435ae6f04ad3e4c3ed8a83382b6511bd9beb5c768Mauro Carvalho Chehab return; 355122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab 356a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton mutex_lock(&trans->shrd->mutex); 357a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwlagn_rx_replenish(trans); 3583acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab mutex_unlock(&trans->shrd->mutex); 359a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton} 3603acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 361527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab/** 3623acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab * iwl_rx_handle - Main entry function for receiving responses from uCode 363ec5de990d912c0d5cca98e030bf6447c1529f56dMauro Carvalho Chehab * 364527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab * Uses the priv->rx_handlers callback function array to invoke 365527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab * the appropriate handlers, including command responses, 366527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab * frame-received notifications, and other notifications. 367527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab */ 36802e7804b2135ff941b8846f5820cf48fbfdadd54Mauro Carvalho Chehabstatic void iwl_rx_handle(struct iwl_trans *trans) 369a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton{ 370a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct iwl_rx_mem_buffer *rxb; 371df7fa09cca9d80f746c29f95b09a7223f6c2f4e7Mauro Carvalho Chehab struct iwl_rx_packet *pkt; 372df7fa09cca9d80f746c29f95b09a7223f6c2f4e7Mauro Carvalho Chehab struct iwl_trans_pcie *trans_pcie = 373df7fa09cca9d80f746c29f95b09a7223f6c2f4e7Mauro Carvalho Chehab IWL_TRANS_GET_PCIE_TRANS(trans); 374df7fa09cca9d80f746c29f95b09a7223f6c2f4e7Mauro Carvalho Chehab struct iwl_rx_queue *rxq = &trans_pcie->rxq; 375df7fa09cca9d80f746c29f95b09a7223f6c2f4e7Mauro Carvalho Chehab struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue]; 3763acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab struct iwl_device_cmd *cmd; 377a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 r, i; 378505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab int reclaim; 379a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton unsigned long flags; 38066767920e3e6532db8afe04f9b2d8e1a9e95cad9Mauro Carvalho Chehab u8 fill_rx = 0; 381a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 count = 8; 382a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton int total_empty; 383a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton int index, cmd_index; 384a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 385017ab4b1e2aa31dc9fe986ab6d1f5ffa2a84395bMauro Carvalho Chehab /* uCode's read index (stored in shared DRAM) indicates the last Rx 386122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab * buffer that the driver may process (last buffer filled by ucode). */ 3872fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; 388017ab4b1e2aa31dc9fe986ab6d1f5ffa2a84395bMauro Carvalho Chehab i = rxq->read; 3892bd1d9eb1c27034a77c8e1887156da72d6160ae1Vitaly Wool 390122b77e59ed2de0692dfe45c87a93e98156fe03aMauro Carvalho Chehab /* Rx interrupt, but nothing sent from uCode */ 39174f38a82376fb1b289d0957429ba45349f0cad62Mauro Carvalho Chehab if (i == r) 392a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i); 3935add9a6f3c90680f89b4694e81025d2aed9559afMauro Carvalho Chehab 394c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab /* calculate total frames need to be restock after handling RX */ 3953aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab total_empty = r - rxq->write_actual; 396a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller if (total_empty < 0) 397c43221df762c33e832e8855cae77989b6bf69fa6Mauro Carvalho Chehab total_empty += RX_QUEUE_SIZE; 39895b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf 3993abee53e4402b6ae39e1e610f9ef94eb74097138Mauro Carvalho Chehab if (total_empty > (RX_QUEUE_SIZE / 2)) 400a2070c665459ac37a36bebae5e97bb4a2568990eMauro Carvalho Chehab fill_rx = 1; 401f2cf250af156bef127433efd255abfae6aab02f6Douglas Schilling Landgraf 402f2cf250af156bef127433efd255abfae6aab02f6Douglas Schilling Landgraf while (i != r) { 403a2070c665459ac37a36bebae5e97bb4a2568990eMauro Carvalho Chehab int len, err; 4043acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab u16 sequence; 405df7fa09cca9d80f746c29f95b09a7223f6c2f4e7Mauro Carvalho Chehab 406a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton rxb = rxq->queue[i]; 4073acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 4080be4375410f1ecc917f3c0caf8f98908d357c93fMauro Carvalho Chehab /* If an RXB doesn't have a Rx queue slot associated with it, 4094b92253acc723f365ad6b2f32e4118e38133b7b8Devin Heitmueller * then a bug has been introduced in the queue refilling 410a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * routines -- catch it here */ 411a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (WARN_ON(rxb == NULL)) { 4123acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab i = (i + 1) & RX_QUEUE_MASK; 413a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton continue; 414a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 415a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 416a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton rxq->queue[i] = NULL; 417a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 418a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton dma_unmap_page(bus(trans)->dev, rxb->page_dma, 419a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton PAGE_SIZE << hw_params(trans).rx_page_order, 420a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton DMA_FROM_DEVICE); 421a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton pkt = rxb_addr(rxb); 422a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 423a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton IWL_DEBUG_RX(trans, "r = %d, i = %d, %s, 0x%02x\n", r, 424a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); 425a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 426a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; 4273acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab len += sizeof(u32); /* account for status word */ 428a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton trace_iwlwifi_dev_rx(priv(trans), pkt, len); 429a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 430a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* Reclaim a command buffer only if this packet is a response 431a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * to a (driver-originated) command. 432a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * If the packet (e.g. Rx frame) originated from uCode, 4336d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * there is no command buffer to reclaim. 4346d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * Ucode should set SEQ_RX_FRAME bit if ucode-originated, 4356d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * but apparently a few don't get set; catch them here. */ 4366d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && 4373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && 4383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab (pkt->hdr.cmd != REPLY_RX) && 4396d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && 4403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && 4416d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && 4426d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab (pkt->hdr.cmd != REPLY_TX); 4436d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab 4446d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab sequence = le16_to_cpu(pkt->hdr.sequence); 4456d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab index = SEQ_TO_INDEX(sequence); 4466d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab cmd_index = get_cmd_index(&txq->q, index); 4476d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab 4486d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab if (reclaim) 4496d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab cmd = txq->cmd[cmd_index]; 4506d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab else 4516d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab cmd = NULL; 4526d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab 453c744dff260e9efb1080d1e823e588f85176a057bRobert Krakora /* warn if this is cmd response / notification and the uCode 4546d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * didn't set the SEQ_RX_FRAME for a frame that is 4556d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * uCode-originated 4566d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * If you saw this code after the second half of 2012, then 4576d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * please remove it 45852284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab */ 45952284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false && 46052284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab (!(pkt->hdr.sequence & SEQ_RX_FRAME)), 46152284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab "reclaim is false, SEQ_RX_FRAME unset: %s\n", 46252284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab get_cmd_string(pkt->hdr.cmd)); 46352284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab 46452284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab err = iwl_rx_dispatch(priv(trans), rxb, cmd); 46552284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab 46652284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab /* 46752284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab * XXX: After here, we should always check rxb->page 46852284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab * against NULL before touching it or its virtual 46952284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab * memory (pkt). Because some rx_handler might have 470a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * already taken or freed the pages. 4713acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab */ 472a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 473a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (reclaim) { 474a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* Invoke any callbacks, transfer the buffer to caller, 475e5589befc472ca50882f37c4fb32333fc93a65b7Mauro Carvalho Chehab * and fire off the (possibly) blocking 476600bd7f0edee0f9687c3c77e6fe63c74452acbfaDevin Heitmueller * iwl_trans_send_cmd() 477505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab * as we reclaim the driver command queue */ 478f2cf250af156bef127433efd255abfae6aab02f6Douglas Schilling Landgraf if (rxb->page) 479505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab iwl_tx_cmd_complete(trans, rxb, err); 480505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab else 481d36bb4e77257ed0df86deca3f69794f037f68c7dMauro Carvalho Chehab IWL_WARN(trans, "Claim null rxb?\n"); 482527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab } 4835569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab 484d36bb4e77257ed0df86deca3f69794f037f68c7dMauro Carvalho Chehab /* Reuse the page if possible. For notification packets and 485527f09a981e398331c2f8d8f7af83cd46e6a06ccMauro Carvalho Chehab * SKBs that fail to Rx correctly, add them back into the 486579d315218e8a3f696e375c5f6917da6488bec8aMauro Carvalho Chehab * rx_free list for reuse later. */ 487579d315218e8a3f696e375c5f6917da6488bec8aMauro Carvalho Chehab spin_lock_irqsave(&rxq->lock, flags); 488579d315218e8a3f696e375c5f6917da6488bec8aMauro Carvalho Chehab if (rxb->page != NULL) { 489a225452ef80a7bd894fd2dfd01a4973d444152f4Mauro Carvalho Chehab rxb->page_dma = dma_map_page(bus(trans)->dev, rxb->page, 490d7448a8d9d06ca2ca4fd1f17404450ecba8bea3aMauro Carvalho Chehab 0, PAGE_SIZE << 49124a613e4b08c4077b4c809bebab1d4a36d541fccDevin Heitmueller hw_params(trans).rx_page_order, 492a2070c665459ac37a36bebae5e97bb4a2568990eMauro Carvalho Chehab DMA_FROM_DEVICE); 493bddcf63313c6a4a85f94db092f45e31f530da691Mauro Carvalho Chehab list_add_tail(&rxb->list, &rxq->rx_free); 494bddcf63313c6a4a85f94db092f45e31f530da691Mauro Carvalho Chehab rxq->free_count++; 495a924a499adb89f52046936deac87264774652a81Mauro Carvalho Chehab } else 496a924a499adb89f52046936deac87264774652a81Mauro Carvalho Chehab list_add_tail(&rxb->list, &rxq->rx_used); 49789b329ef9d7cc16ed46fc991b21b2d45e7bf452cMauro Carvalho Chehab 49889b329ef9d7cc16ed46fc991b21b2d45e7bf452cMauro Carvalho Chehab spin_unlock_irqrestore(&rxq->lock, flags); 49989b329ef9d7cc16ed46fc991b21b2d45e7bf452cMauro Carvalho Chehab 50074f38a82376fb1b289d0957429ba45349f0cad62Mauro Carvalho Chehab i = (i + 1) & RX_QUEUE_MASK; 50174f38a82376fb1b289d0957429ba45349f0cad62Mauro Carvalho Chehab /* If there are a lot of unused frames, 5029bb13a6dc3a6f68c990264838ff0493d900c48d7Mauro Carvalho Chehab * restock the Rx queue so ucode wont assert. */ 5039bb13a6dc3a6f68c990264838ff0493d900c48d7Mauro Carvalho Chehab if (fill_rx) { 50435643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab count++; 505a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (count >= 8) { 506a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton rxq->read = i; 507a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwlagn_rx_replenish_now(trans); 508a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton count = 0; 509a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 510a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 511a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 512a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 513a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* Backtrack one entry */ 514a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton rxq->read = i; 5157d497f8afa80128bb99a425a6d7a766a863128a5Mauro Carvalho Chehab if (fill_rx) 516a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwlagn_rx_replenish_now(trans); 517a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton else 51895b86a9a9020da22e7c25abc77aae4dc8f02ab55Douglas Schilling Landgraf iwlagn_rx_queue_restock(trans); 51935ae6f04ad3e4c3ed8a83382b6511bd9beb5c768Mauro Carvalho Chehab} 520a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 521a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Mortonstatic const char * const desc_lookup_text[] = { 522a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "OK", 523a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "FAIL", 524a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "BAD_PARAM", 525d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuil "BAD_CHECKSUM", 526d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuil "NMI_INTERRUPT_WDG", 527a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "SYSASSERT", 5289e31ced888d1ca49ec5be51ef295e3ce994366c4Mauro Carvalho Chehab "FATAL_ERROR", 529a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "BAD_COMMAND", 53003910cc39035d27f4c85c8ad2a236cc5c9456127Mauro Carvalho Chehab "HW_ERROR_TUNE_LOCK", 5316ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf "HW_ERROR_TEMPERATURE", 5326ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf "ILLEGAL_CHAN_FREQ", 53303910cc39035d27f4c85c8ad2a236cc5c9456127Mauro Carvalho Chehab "VCC_NOT_STABLE", 5349baed99ee7a834b1f2599e13f219087f01c63f38Mauro Carvalho Chehab "FH_ERROR", 5356d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab "NMI_INTERRUPT_HOST", 536a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "NMI_INTERRUPT_ACTION_PT", 5373acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab "NMI_INTERRUPT_UNKNOWN", 5383acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab "UCODE_VERSION_MISMATCH", 5399e31ced888d1ca49ec5be51ef295e3ce994366c4Mauro Carvalho Chehab "HW_ERROR_ABS_LOCK", 540d7448a8d9d06ca2ca4fd1f17404450ecba8bea3aMauro Carvalho Chehab "HW_ERROR_CAL_LOCK_FAIL", 541d7448a8d9d06ca2ca4fd1f17404450ecba8bea3aMauro Carvalho Chehab "NMI_INTERRUPT_INST_ACTION_PT", 542a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "NMI_INTERRUPT_DATA_ACTION_PT", 5435a80415bcabf2b59e8c34db6e743c54582cfd3c2Sascha Sommer "NMI_TRM_HW_ER", 544f2a2e4910502e866833732f31ee697d15b3e56fdMauro Carvalho Chehab "NMI_INTERRUPT_TRM", 545d7aa80207babe694b316a48200b096cf0336ecb3Aidan Thornton "NMI_INTERRUPT_BREAK_POINT", 546a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "DEBUG_0", 547a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "DEBUG_1", 548a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "DEBUG_2", 5490be4375410f1ecc917f3c0caf8f98908d357c93fMauro Carvalho Chehab "DEBUG_3", 550a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton}; 551a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 552a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Mortonstatic struct { char *name; u8 num; } advanced_lookup[] = { 553ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab { "NMI_INTERRUPT_WDG", 0x34 }, 554ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab { "SYSASSERT", 0x35 }, 555ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab { "UCODE_VERSION_MISMATCH", 0x37 }, 556ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab { "BAD_COMMAND", 0x38 }, 557ad0ebb96c220c461386e9a765fca3daf5590d01eMauro Carvalho Chehab { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, 558a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton { "FATAL_ERROR", 0x3D }, 559a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton { "NMI_TRM_HW_ERR", 0x46 }, 560a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton { "NMI_INTERRUPT_TRM", 0x4C }, 561a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, 5629d4d9c05c807ab8a49ac0024987b223bb32c022dMauro Carvalho Chehab { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, 5639d4d9c05c807ab8a49ac0024987b223bb32c022dMauro Carvalho Chehab { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, 5643acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab { "NMI_INTERRUPT_HOST", 0x66 }, 565a1a6ee74f2c68918f2e145dccba3637eea91a52aNicola Soranzo { "NMI_INTERRUPT_ACTION_PT", 0x7C }, 566a1a6ee74f2c68918f2e145dccba3637eea91a52aNicola Soranzo { "NMI_INTERRUPT_UNKNOWN", 0x84 }, 567c4a98793a63c423c9e1af51822325969e23c16d4Mauro Carvalho Chehab { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, 568c4a98793a63c423c9e1af51822325969e23c16d4Mauro Carvalho Chehab { "ADVANCED_SYSASSERT", 0 }, 569a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton}; 5706ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf 571a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Mortonstatic const char *desc_lookup(u32 num) 5726ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{ 5736ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf int i; 5746ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf int max = ARRAY_SIZE(desc_lookup_text); 5756ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf 576a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (num < max) 5776ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf return desc_lookup_text[num]; 5783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 5793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab max = ARRAY_SIZE(advanced_lookup) - 1; 5803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab for (i = 0; i < max; i++) { 5816a1acc3bc5144e004996029b20e46e6020d128a7Devin Heitmueller if (advanced_lookup[i].num == num) 5826a1acc3bc5144e004996029b20e46e6020d128a7Devin Heitmueller break; 5836a1acc3bc5144e004996029b20e46e6020d128a7Devin Heitmueller } 584c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab return advanced_lookup[i].name; 585c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab} 586c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab 587a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller#define ERROR_START_OFFSET (1 * sizeof(u32)) 588a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller#define ERROR_ELEM_SIZE (7 * sizeof(u32)) 589a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller 590a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmuellerstatic void iwl_dump_nic_error_log(struct iwl_trans *trans) 591a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller{ 5923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton u32 base; 593a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct iwl_error_event_table table; 594a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct iwl_priv *priv = priv(trans); 5956d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab struct iwl_trans_pcie *trans_pcie = 5966d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab IWL_TRANS_GET_PCIE_TRANS(trans); 5976d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab 5986d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab base = priv->device_pointers.error_event_table; 5996d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab if (priv->ucode_type == IWL_UCODE_INIT) { 6006d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab if (!base) 601a3a048cea301baba5d451991074a85dc20a8f228Mauro Carvalho Chehab base = priv->init_errlog_ptr; 602a3a048cea301baba5d451991074a85dc20a8f228Mauro Carvalho Chehab } else { 6033acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab if (!base) 604fad7b958e753e18ff443786360f7846da50a3085Sascha Sommer base = priv->inst_errlog_ptr; 605f2cf250af156bef127433efd255abfae6aab02f6Douglas Schilling Landgraf } 606f2cf250af156bef127433efd255abfae6aab02f6Douglas Schilling Landgraf 607a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (!iwlagn_hw_valid_rtc_data_addr(base)) { 6083acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab IWL_ERR(trans, 609a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "Not valid error log pointer 0x%08X for %s uCode\n", 6103acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab base, 6113acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab (priv->ucode_type == IWL_UCODE_INIT) 6123acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab ? "Init" : "RT"); 613a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton return; 6143acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab } 615a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 6163acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab iwl_read_targ_mem_words(bus(priv), base, &table, sizeof(table)); 6173acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab 6183acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { 619a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton IWL_ERR(trans, "Start IWL Error Log Dump:\n"); 6203acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", 621b69724899440289ab258ff417c2d6aa104c70310Devin Heitmueller trans->shrd->status, table.valid); 622b69724899440289ab258ff417c2d6aa104c70310Devin Heitmueller } 623531c98e71805b32e9ea35a218119100bbd2b7615Mauro Carvalho Chehab 624531c98e71805b32e9ea35a218119100bbd2b7615Mauro Carvalho Chehab trans_pcie->isr_stats.err_code = table.error_id; 625531c98e71805b32e9ea35a218119100bbd2b7615Mauro Carvalho Chehab 6263acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, 62735643943be58aef82826e340761e86e0d37870ecMauro Carvalho Chehab table.data1, table.data2, table.line, 628539c96d0fd86bfdcfac75c88b74aa5798439293dMauro Carvalho Chehab table.blink1, table.blink2, table.ilink1, 6293acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab table.ilink2, table.bcon_time, table.gp1, 6303acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab table.gp2, table.gp3, table.ucode_ver, 631bddcf63313c6a4a85f94db092f45e31f530da691Mauro Carvalho Chehab table.hw_ver, table.brd_ver); 6323acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id, 6333acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab desc_lookup(table.error_id)); 634579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton IWL_ERR(trans, "0x%08X | uPc\n", table.pc); 635579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1); 636c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2); 637579f72e44fb1c991352f44c20b471c3001357f68Aidan Thornton IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1); 638d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2); 639c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab IWL_ERR(trans, "0x%08X | data1\n", table.data1); 640c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab IWL_ERR(trans, "0x%08X | data2\n", table.data2); 6411a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | line\n", table.line); 6421a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time); 6431a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low); 644bec43661b1dc0075b7445223ba775674133b164dHans Verkuil IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi); 6451a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1); 6461a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2); 6476d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3); 6486d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver); 6491a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); 6501a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); 6511a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); 6521a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab} 6531a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab 6541a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab/** 6556d79468dd8537530f4150e76ed9b4b63f80571c6Mauro Carvalho Chehab * iwl_irq_handle_error - called for HW or SW error interrupt from card 6563acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab */ 6576ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic void iwl_irq_handle_error(struct iwl_trans *trans) 658a94e95b443811c127734ef10f3b7d2220532c1d2Markus Rechberger{ 6593acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab struct iwl_priv *priv = priv(trans); 6603acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ 6613acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab if (priv->cfg->internal_wimax_coex && 6623acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) & 663c668f32dca105d876e51862a003a302fa61e4ae4Jean Delvare APMS_CLK_VAL_MRB_FUNC_MODE) || 664d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) & 6651a23f81b7dc3115b29cff0e4f58b5dd04a6242adMauro Carvalho Chehab APMG_PS_CTRL_VAL_RESET_REQ))) { 666c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab /* 667c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab * Keep the restart process from trying to send host 668c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab * commands by clearing the ready bit. 669c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab */ 670c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab clear_bit(STATUS_READY, &trans->shrd->status); 671c8793b035df7b18997d1cf34254064dac166f009Mauro Carvalho Chehab clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); 672a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller wake_up(&priv->shrd->wait_command_queue); 673a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3Devin Heitmueller IWL_ERR(trans, "RF is used by WiMAX\n"); 674a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton return; 675a924a499adb89f52046936deac87264774652a81Mauro Carvalho Chehab } 676a924a499adb89f52046936deac87264774652a81Mauro Carvalho Chehab 677a924a499adb89f52046936deac87264774652a81Mauro Carvalho Chehab IWL_ERR(trans, "Loaded firmware version: %s\n", 678a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton priv->hw->wiphy->fw_version); 679a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 6803acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab iwl_dump_nic_error_log(trans); 681f85c657ff1f712abd5207a95fba8a5fcc282ab04Jean Delvare iwl_dump_csr(trans); 682a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_dump_fh(trans, NULL, false); 6833acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab iwl_dump_nic_event_log(trans, false, NULL, false); 6844ac97914c6c35f6bf132071c718e034d0846b9f5Mauro Carvalho Chehab#ifdef CONFIG_IWLWIFI_DEBUG 685f85c657ff1f712abd5207a95fba8a5fcc282ab04Jean Delvare if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) 686a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS); 6873acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab#endif 6884ac97914c6c35f6bf132071c718e034d0846b9f5Mauro Carvalho Chehab 689f85c657ff1f712abd5207a95fba8a5fcc282ab04Jean Delvare iwlagn_fw_error(priv, false); 6903acf28095009509c9ca1e283de821b5be9ddede6Mauro Carvalho Chehab} 6914ac97914c6c35f6bf132071c718e034d0846b9f5Mauro Carvalho Chehab 692f85c657ff1f712abd5207a95fba8a5fcc282ab04Jean Delvare#define EVENT_START_OFFSET (4 * sizeof(u32)) 693a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 6946ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf/** 695a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * iwl_print_event_log - Dump error event log to syslog 696a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * 6972a29a0d770ef6f24a8fd7806655c826d45888cbaMauro Carvalho Chehab */ 698a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Mortonstatic int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, 699a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 num_events, u32 mode, 7006ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf int pos, char **buf, size_t bufsz) 701a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton{ 70241facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab u32 i; 703a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 base; /* SRAM byte address of event log header */ 704a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ 7056ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf u32 ptr; /* SRAM byte address of log data */ 706a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 ev, time, data; /* event log data */ 70741facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab unsigned long reg_flags; 708a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton struct iwl_priv *priv = priv(trans); 709a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 7106ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf if (num_events == 0) 711a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton return pos; 71241facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab 713a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton base = priv->device_pointers.log_event_table; 714a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (priv->ucode_type == IWL_UCODE_INIT) { 7156ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf if (!base) 716a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton base = priv->init_evtlog_ptr; 71741facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab } else { 718a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (!base) 719a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton base = priv->inst_evtlog_ptr; 7206ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf } 721a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 72241facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab if (mode == 0) 723a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton event_size = 2 * sizeof(u32); 724a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton else 7256ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf event_size = 3 * sizeof(u32); 726a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 72741facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab ptr = base + EVENT_START_OFFSET + (start_idx * event_size); 728a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 729a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* Make sure device is powered up for SRAM reads */ 7306ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf spin_lock_irqsave(&bus(trans)->reg_lock, reg_flags); 731a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_grab_nic_access(bus(trans)); 732a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton 73341facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab /* Set starting address; reads will auto-increment */ 734a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton iwl_write32(bus(trans), HBUS_TARG_MEM_RADDR, ptr); 735a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton rmb(); 7366ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf 737a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* "time" is actually "data" for mode 0 (no timestamp). 738a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton * place event id # at far right for easier visual parsing. */ 73941facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab for (i = 0; i < num_events; i++) { 740a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton ev = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 741a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton time = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 7426ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf if (mode == 0) { 743a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton /* data, ev */ 744a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (bufsz) { 74541facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab pos += scnprintf(*buf + pos, bufsz - pos, 746a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "EVT_LOG:0x%08x:%04u\n", 747a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton time, ev); 7486ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf } else { 749a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton trace_iwlwifi_dev_ucode_event(priv, 0, 750a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton time, ev); 75141facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", 752a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton time, ev); 753a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 7546ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf } else { 755a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton data = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); 756a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (bufsz) { 75741facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab pos += scnprintf(*buf + pos, bufsz - pos, 758a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton "EVT_LOGT:%010u:0x%08x:%04u\n", 759a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton time, data, ev); 7606ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf } else { 761a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", 762a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton time, data, ev); 76341facaa4b63cc1a0ff5a900149a29942d47e1491Mauro Carvalho Chehab trace_iwlwifi_dev_ucode_event(priv, time, 764a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton data, ev); 765a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 766a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton } 7676ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf } 76830556b23f31973ca311341277c4e4b128c0528bbMarkus Rechberger 7695569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab /* Allow device to power down */ 7705569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab iwl_release_nic_access(bus(trans)); 7715569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab spin_unlock_irqrestore(&bus(trans)->reg_lock, reg_flags); 772505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab return pos; 7737d497f8afa80128bb99a425a6d7a766a863128a5Mauro Carvalho Chehab} 7745569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab 7755569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab/** 77630556b23f31973ca311341277c4e4b128c0528bbMarkus Rechberger * iwl_print_last_event_logs - Dump the newest # of event log to syslog 77730556b23f31973ca311341277c4e4b128c0528bbMarkus Rechberger */ 7786ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int iwl_print_last_event_logs(struct iwl_trans *trans, u32 capacity, 779a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton u32 num_wraps, u32 next_entry, 7805569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab u32 size, u32 mode, 7815569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab int pos, char **buf, size_t bufsz) 7825569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab{ 783505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab /* 7847d497f8afa80128bb99a425a6d7a766a863128a5Mauro Carvalho Chehab * display the newest DEFAULT_LOG_ENTRIES entries 7855569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab * i.e the entries just before the next ont that uCode would fill. 7865569996421fa1cfc1fc0d9e683ac1def46ea985dMauro Carvalho Chehab */ 787a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (num_wraps) { 788a6c2ba283565dbc9f055dcb2ecba1971460bb535Andrew Morton if (next_entry < size) { 789 pos = iwl_print_event_log(trans, 790 capacity - (size - next_entry), 791 size - next_entry, mode, 792 pos, buf, bufsz); 793 pos = iwl_print_event_log(trans, 0, 794 next_entry, mode, 795 pos, buf, bufsz); 796 } else 797 pos = iwl_print_event_log(trans, next_entry - size, 798 size, mode, pos, buf, bufsz); 799 } else { 800 if (next_entry < size) { 801 pos = iwl_print_event_log(trans, 0, next_entry, 802 mode, pos, buf, bufsz); 803 } else { 804 pos = iwl_print_event_log(trans, next_entry - size, 805 size, mode, pos, buf, bufsz); 806 } 807 } 808 return pos; 809} 810 811#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) 812 813int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, 814 char **buf, bool display) 815{ 816 u32 base; /* SRAM byte address of event log header */ 817 u32 capacity; /* event log capacity in # entries */ 818 u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ 819 u32 num_wraps; /* # times uCode wrapped to top of log */ 820 u32 next_entry; /* index of next entry to be written by uCode */ 821 u32 size; /* # entries that we'll print */ 822 u32 logsize; 823 int pos = 0; 824 size_t bufsz = 0; 825 struct iwl_priv *priv = priv(trans); 826 827 base = priv->device_pointers.log_event_table; 828 if (priv->ucode_type == IWL_UCODE_INIT) { 829 logsize = priv->init_evtlog_size; 830 if (!base) 831 base = priv->init_evtlog_ptr; 832 } else { 833 logsize = priv->inst_evtlog_size; 834 if (!base) 835 base = priv->inst_evtlog_ptr; 836 } 837 838 if (!iwlagn_hw_valid_rtc_data_addr(base)) { 839 IWL_ERR(trans, 840 "Invalid event log pointer 0x%08X for %s uCode\n", 841 base, 842 (priv->ucode_type == IWL_UCODE_INIT) 843 ? "Init" : "RT"); 844 return -EINVAL; 845 } 846 847 /* event log header */ 848 capacity = iwl_read_targ_mem(bus(trans), base); 849 mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32))); 850 num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32))); 851 next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32))); 852 853 if (capacity > logsize) { 854 IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " 855 "entries\n", capacity, logsize); 856 capacity = logsize; 857 } 858 859 if (next_entry > logsize) { 860 IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", 861 next_entry, logsize); 862 next_entry = logsize; 863 } 864 865 size = num_wraps ? capacity : next_entry; 866 867 /* bail out if nothing in log */ 868 if (size == 0) { 869 IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); 870 return pos; 871 } 872 873#ifdef CONFIG_IWLWIFI_DEBUG 874 if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log) 875 size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 876 ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 877#else 878 size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 879 ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 880#endif 881 IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", 882 size); 883 884#ifdef CONFIG_IWLWIFI_DEBUG 885 if (display) { 886 if (full_log) 887 bufsz = capacity * 48; 888 else 889 bufsz = size * 48; 890 *buf = kmalloc(bufsz, GFP_KERNEL); 891 if (!*buf) 892 return -ENOMEM; 893 } 894 if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) { 895 /* 896 * if uCode has wrapped back to top of log, 897 * start at the oldest entry, 898 * i.e the next one that uCode would fill. 899 */ 900 if (num_wraps) 901 pos = iwl_print_event_log(trans, next_entry, 902 capacity - next_entry, mode, 903 pos, buf, bufsz); 904 /* (then/else) start at top of log */ 905 pos = iwl_print_event_log(trans, 0, 906 next_entry, mode, pos, buf, bufsz); 907 } else 908 pos = iwl_print_last_event_logs(trans, capacity, num_wraps, 909 next_entry, size, mode, 910 pos, buf, bufsz); 911#else 912 pos = iwl_print_last_event_logs(trans, capacity, num_wraps, 913 next_entry, size, mode, 914 pos, buf, bufsz); 915#endif 916 return pos; 917} 918 919/* tasklet for iwlagn interrupt */ 920void iwl_irq_tasklet(struct iwl_trans *trans) 921{ 922 u32 inta = 0; 923 u32 handled = 0; 924 unsigned long flags; 925 u32 i; 926#ifdef CONFIG_IWLWIFI_DEBUG 927 u32 inta_mask; 928#endif 929 930 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 931 struct isr_statistics *isr_stats = &trans_pcie->isr_stats; 932 933 934 spin_lock_irqsave(&trans->shrd->lock, flags); 935 936 /* Ack/clear/reset pending uCode interrupts. 937 * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, 938 */ 939 /* There is a hardware bug in the interrupt mask function that some 940 * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if 941 * they are disabled in the CSR_INT_MASK register. Furthermore the 942 * ICT interrupt handling mechanism has another bug that might cause 943 * these unmasked interrupts fail to be detected. We workaround the 944 * hardware bugs here by ACKing all the possible interrupts so that 945 * interrupt coalescing can still be achieved. 946 */ 947 iwl_write32(bus(trans), CSR_INT, 948 trans_pcie->inta | ~trans_pcie->inta_mask); 949 950 inta = trans_pcie->inta; 951 952#ifdef CONFIG_IWLWIFI_DEBUG 953 if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) { 954 /* just for debug */ 955 inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); 956 IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ", 957 inta, inta_mask); 958 } 959#endif 960 961 spin_unlock_irqrestore(&trans->shrd->lock, flags); 962 963 /* saved interrupt in inta variable now we can reset trans_pcie->inta */ 964 trans_pcie->inta = 0; 965 966 /* Now service all interrupt bits discovered above. */ 967 if (inta & CSR_INT_BIT_HW_ERR) { 968 IWL_ERR(trans, "Hardware error detected. Restarting.\n"); 969 970 /* Tell the device to stop sending interrupts */ 971 iwl_disable_interrupts(trans); 972 973 isr_stats->hw++; 974 iwl_irq_handle_error(trans); 975 976 handled |= CSR_INT_BIT_HW_ERR; 977 978 return; 979 } 980 981#ifdef CONFIG_IWLWIFI_DEBUG 982 if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { 983 /* NIC fires this, but we don't use it, redundant with WAKEUP */ 984 if (inta & CSR_INT_BIT_SCD) { 985 IWL_DEBUG_ISR(trans, "Scheduler finished to transmit " 986 "the frame/frames.\n"); 987 isr_stats->sch++; 988 } 989 990 /* Alive notification via Rx interrupt will do the real work */ 991 if (inta & CSR_INT_BIT_ALIVE) { 992 IWL_DEBUG_ISR(trans, "Alive interrupt\n"); 993 isr_stats->alive++; 994 } 995 } 996#endif 997 /* Safely ignore these bits for debug checks below */ 998 inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); 999 1000 /* HW RF KILL switch toggled */ 1001 if (inta & CSR_INT_BIT_RF_KILL) { 1002 int hw_rf_kill = 0; 1003 if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & 1004 CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) 1005 hw_rf_kill = 1; 1006 1007 IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", 1008 hw_rf_kill ? "disable radio" : "enable radio"); 1009 1010 isr_stats->rfkill++; 1011 1012 /* driver only loads ucode once setting the interface up. 1013 * the driver allows loading the ucode even if the radio 1014 * is killed. Hence update the killswitch state here. The 1015 * rfkill handler will care about restarting if needed. 1016 */ 1017 if (!test_bit(STATUS_ALIVE, &trans->shrd->status)) { 1018 if (hw_rf_kill) 1019 set_bit(STATUS_RF_KILL_HW, 1020 &trans->shrd->status); 1021 else 1022 clear_bit(STATUS_RF_KILL_HW, 1023 &trans->shrd->status); 1024 iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill); 1025 } 1026 1027 handled |= CSR_INT_BIT_RF_KILL; 1028 } 1029 1030 /* Chip got too hot and stopped itself */ 1031 if (inta & CSR_INT_BIT_CT_KILL) { 1032 IWL_ERR(trans, "Microcode CT kill error detected.\n"); 1033 isr_stats->ctkill++; 1034 handled |= CSR_INT_BIT_CT_KILL; 1035 } 1036 1037 /* Error detected by uCode */ 1038 if (inta & CSR_INT_BIT_SW_ERR) { 1039 IWL_ERR(trans, "Microcode SW error detected. " 1040 " Restarting 0x%X.\n", inta); 1041 isr_stats->sw++; 1042 iwl_irq_handle_error(trans); 1043 handled |= CSR_INT_BIT_SW_ERR; 1044 } 1045 1046 /* uCode wakes up after power-down sleep */ 1047 if (inta & CSR_INT_BIT_WAKEUP) { 1048 IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); 1049 iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq); 1050 for (i = 0; i < hw_params(trans).max_txq_num; i++) 1051 iwl_txq_update_write_ptr(trans, 1052 &trans_pcie->txq[i]); 1053 1054 isr_stats->wakeup++; 1055 1056 handled |= CSR_INT_BIT_WAKEUP; 1057 } 1058 1059 /* All uCode command responses, including Tx command responses, 1060 * Rx "responses" (frame-received notification), and other 1061 * notifications from uCode come through here*/ 1062 if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | 1063 CSR_INT_BIT_RX_PERIODIC)) { 1064 IWL_DEBUG_ISR(trans, "Rx interrupt\n"); 1065 if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { 1066 handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); 1067 iwl_write32(bus(trans), CSR_FH_INT_STATUS, 1068 CSR_FH_INT_RX_MASK); 1069 } 1070 if (inta & CSR_INT_BIT_RX_PERIODIC) { 1071 handled |= CSR_INT_BIT_RX_PERIODIC; 1072 iwl_write32(bus(trans), 1073 CSR_INT, CSR_INT_BIT_RX_PERIODIC); 1074 } 1075 /* Sending RX interrupt require many steps to be done in the 1076 * the device: 1077 * 1- write interrupt to current index in ICT table. 1078 * 2- dma RX frame. 1079 * 3- update RX shared data to indicate last write index. 1080 * 4- send interrupt. 1081 * This could lead to RX race, driver could receive RX interrupt 1082 * but the shared data changes does not reflect this; 1083 * periodic interrupt will detect any dangling Rx activity. 1084 */ 1085 1086 /* Disable periodic interrupt; we use it as just a one-shot. */ 1087 iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, 1088 CSR_INT_PERIODIC_DIS); 1089 iwl_rx_handle(trans); 1090 1091 /* 1092 * Enable periodic interrupt in 8 msec only if we received 1093 * real RX interrupt (instead of just periodic int), to catch 1094 * any dangling Rx interrupt. If it was just the periodic 1095 * interrupt, there was no dangling Rx activity, and no need 1096 * to extend the periodic interrupt; one-shot is enough. 1097 */ 1098 if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) 1099 iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, 1100 CSR_INT_PERIODIC_ENA); 1101 1102 isr_stats->rx++; 1103 } 1104 1105 /* This "Tx" DMA channel is used only for loading uCode */ 1106 if (inta & CSR_INT_BIT_FH_TX) { 1107 iwl_write32(bus(trans), CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); 1108 IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); 1109 isr_stats->tx++; 1110 handled |= CSR_INT_BIT_FH_TX; 1111 /* Wake up uCode load routine, now that load is complete */ 1112 priv(trans)->ucode_write_complete = 1; 1113 wake_up(&trans->shrd->wait_command_queue); 1114 } 1115 1116 if (inta & ~handled) { 1117 IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled); 1118 isr_stats->unhandled++; 1119 } 1120 1121 if (inta & ~(trans_pcie->inta_mask)) { 1122 IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n", 1123 inta & ~trans_pcie->inta_mask); 1124 } 1125 1126 /* Re-enable all interrupts */ 1127 /* only Re-enable if disabled by irq */ 1128 if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status)) 1129 iwl_enable_interrupts(trans); 1130 /* Re-enable RF_KILL if it occurred */ 1131 else if (handled & CSR_INT_BIT_RF_KILL) 1132 iwl_enable_rfkill_int(priv(trans)); 1133} 1134 1135/****************************************************************************** 1136 * 1137 * ICT functions 1138 * 1139 ******************************************************************************/ 1140#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) 1141 1142/* Free dram table */ 1143void iwl_free_isr_ict(struct iwl_trans *trans) 1144{ 1145 struct iwl_trans_pcie *trans_pcie = 1146 IWL_TRANS_GET_PCIE_TRANS(trans); 1147 1148 if (trans_pcie->ict_tbl_vir) { 1149 dma_free_coherent(bus(trans)->dev, 1150 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 1151 trans_pcie->ict_tbl_vir, 1152 trans_pcie->ict_tbl_dma); 1153 trans_pcie->ict_tbl_vir = NULL; 1154 memset(&trans_pcie->ict_tbl_dma, 0, 1155 sizeof(trans_pcie->ict_tbl_dma)); 1156 memset(&trans_pcie->aligned_ict_tbl_dma, 0, 1157 sizeof(trans_pcie->aligned_ict_tbl_dma)); 1158 } 1159} 1160 1161 1162/* allocate dram shared table it is a PAGE_SIZE aligned 1163 * also reset all data related to ICT table interrupt. 1164 */ 1165int iwl_alloc_isr_ict(struct iwl_trans *trans) 1166{ 1167 struct iwl_trans_pcie *trans_pcie = 1168 IWL_TRANS_GET_PCIE_TRANS(trans); 1169 1170 /* allocate shrared data table */ 1171 trans_pcie->ict_tbl_vir = 1172 dma_alloc_coherent(bus(trans)->dev, 1173 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 1174 &trans_pcie->ict_tbl_dma, GFP_KERNEL); 1175 if (!trans_pcie->ict_tbl_vir) 1176 return -ENOMEM; 1177 1178 /* align table to PAGE_SIZE boundary */ 1179 trans_pcie->aligned_ict_tbl_dma = 1180 ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE); 1181 1182 IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n", 1183 (unsigned long long)trans_pcie->ict_tbl_dma, 1184 (unsigned long long)trans_pcie->aligned_ict_tbl_dma, 1185 (int)(trans_pcie->aligned_ict_tbl_dma - 1186 trans_pcie->ict_tbl_dma)); 1187 1188 trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir + 1189 (trans_pcie->aligned_ict_tbl_dma - 1190 trans_pcie->ict_tbl_dma); 1191 1192 IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n", 1193 trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir, 1194 (int)(trans_pcie->aligned_ict_tbl_dma - 1195 trans_pcie->ict_tbl_dma)); 1196 1197 /* reset table and index to all 0 */ 1198 memset(trans_pcie->ict_tbl_vir, 0, 1199 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); 1200 trans_pcie->ict_index = 0; 1201 1202 /* add periodic RX interrupt */ 1203 trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC; 1204 return 0; 1205} 1206 1207/* Device is going up inform it about using ICT interrupt table, 1208 * also we need to tell the driver to start using ICT interrupt. 1209 */ 1210int iwl_reset_ict(struct iwl_trans *trans) 1211{ 1212 u32 val; 1213 unsigned long flags; 1214 struct iwl_trans_pcie *trans_pcie = 1215 IWL_TRANS_GET_PCIE_TRANS(trans); 1216 1217 if (!trans_pcie->ict_tbl_vir) 1218 return 0; 1219 1220 spin_lock_irqsave(&trans->shrd->lock, flags); 1221 iwl_disable_interrupts(trans); 1222 1223 memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); 1224 1225 val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT; 1226 1227 val |= CSR_DRAM_INT_TBL_ENABLE; 1228 val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; 1229 1230 IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X " 1231 "aligned dma address %Lx\n", 1232 val, 1233 (unsigned long long)trans_pcie->aligned_ict_tbl_dma); 1234 1235 iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); 1236 trans_pcie->use_ict = true; 1237 trans_pcie->ict_index = 0; 1238 iwl_write32(bus(trans), CSR_INT, trans_pcie->inta_mask); 1239 iwl_enable_interrupts(trans); 1240 spin_unlock_irqrestore(&trans->shrd->lock, flags); 1241 1242 return 0; 1243} 1244 1245/* Device is going down disable ict interrupt usage */ 1246void iwl_disable_ict(struct iwl_trans *trans) 1247{ 1248 struct iwl_trans_pcie *trans_pcie = 1249 IWL_TRANS_GET_PCIE_TRANS(trans); 1250 1251 unsigned long flags; 1252 1253 spin_lock_irqsave(&trans->shrd->lock, flags); 1254 trans_pcie->use_ict = false; 1255 spin_unlock_irqrestore(&trans->shrd->lock, flags); 1256} 1257 1258static irqreturn_t iwl_isr(int irq, void *data) 1259{ 1260 struct iwl_trans *trans = data; 1261 struct iwl_trans_pcie *trans_pcie; 1262 u32 inta, inta_mask; 1263 unsigned long flags; 1264#ifdef CONFIG_IWLWIFI_DEBUG 1265 u32 inta_fh; 1266#endif 1267 if (!trans) 1268 return IRQ_NONE; 1269 1270 trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 1271 1272 spin_lock_irqsave(&trans->shrd->lock, flags); 1273 1274 /* Disable (but don't clear!) interrupts here to avoid 1275 * back-to-back ISRs and sporadic interrupts from our NIC. 1276 * If we have something to service, the tasklet will re-enable ints. 1277 * If we *don't* have something, we'll re-enable before leaving here. */ 1278 inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ 1279 iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); 1280 1281 /* Discover which interrupts are active/pending */ 1282 inta = iwl_read32(bus(trans), CSR_INT); 1283 1284 /* Ignore interrupt if there's nothing in NIC to service. 1285 * This may be due to IRQ shared with another device, 1286 * or due to sporadic interrupts thrown from our NIC. */ 1287 if (!inta) { 1288 IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); 1289 goto none; 1290 } 1291 1292 if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { 1293 /* Hardware disappeared. It might have already raised 1294 * an interrupt */ 1295 IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta); 1296 goto unplugged; 1297 } 1298 1299#ifdef CONFIG_IWLWIFI_DEBUG 1300 if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { 1301 inta_fh = iwl_read32(bus(trans), CSR_FH_INT_STATUS); 1302 IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, " 1303 "fh 0x%08x\n", inta, inta_mask, inta_fh); 1304 } 1305#endif 1306 1307 trans_pcie->inta |= inta; 1308 /* iwl_irq_tasklet() will service interrupts and re-enable them */ 1309 if (likely(inta)) 1310 tasklet_schedule(&trans_pcie->irq_tasklet); 1311 else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 1312 !trans_pcie->inta) 1313 iwl_enable_interrupts(trans); 1314 1315 unplugged: 1316 spin_unlock_irqrestore(&trans->shrd->lock, flags); 1317 return IRQ_HANDLED; 1318 1319 none: 1320 /* re-enable interrupts here since we don't have anything to service. */ 1321 /* only Re-enable if disabled by irq and no schedules tasklet. */ 1322 if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 1323 !trans_pcie->inta) 1324 iwl_enable_interrupts(trans); 1325 1326 spin_unlock_irqrestore(&trans->shrd->lock, flags); 1327 return IRQ_NONE; 1328} 1329 1330/* interrupt handler using ict table, with this interrupt driver will 1331 * stop using INTA register to get device's interrupt, reading this register 1332 * is expensive, device will write interrupts in ICT dram table, increment 1333 * index then will fire interrupt to driver, driver will OR all ICT table 1334 * entries from current index up to table entry with 0 value. the result is 1335 * the interrupt we need to service, driver will set the entries back to 0 and 1336 * set index. 1337 */ 1338irqreturn_t iwl_isr_ict(int irq, void *data) 1339{ 1340 struct iwl_trans *trans = data; 1341 struct iwl_trans_pcie *trans_pcie; 1342 u32 inta, inta_mask; 1343 u32 val = 0; 1344 unsigned long flags; 1345 1346 if (!trans) 1347 return IRQ_NONE; 1348 1349 trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 1350 1351 /* dram interrupt table not set yet, 1352 * use legacy interrupt. 1353 */ 1354 if (!trans_pcie->use_ict) 1355 return iwl_isr(irq, data); 1356 1357 spin_lock_irqsave(&trans->shrd->lock, flags); 1358 1359 /* Disable (but don't clear!) interrupts here to avoid 1360 * back-to-back ISRs and sporadic interrupts from our NIC. 1361 * If we have something to service, the tasklet will re-enable ints. 1362 * If we *don't* have something, we'll re-enable before leaving here. 1363 */ 1364 inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ 1365 iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); 1366 1367 1368 /* Ignore interrupt if there's nothing in NIC to service. 1369 * This may be due to IRQ shared with another device, 1370 * or due to sporadic interrupts thrown from our NIC. */ 1371 if (!trans_pcie->ict_tbl[trans_pcie->ict_index]) { 1372 IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); 1373 goto none; 1374 } 1375 1376 /* read all entries that not 0 start with ict_index */ 1377 while (trans_pcie->ict_tbl[trans_pcie->ict_index]) { 1378 1379 val |= le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); 1380 IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", 1381 trans_pcie->ict_index, 1382 le32_to_cpu( 1383 trans_pcie->ict_tbl[trans_pcie->ict_index])); 1384 trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; 1385 trans_pcie->ict_index = 1386 iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); 1387 1388 } 1389 1390 /* We should not get this value, just ignore it. */ 1391 if (val == 0xffffffff) 1392 val = 0; 1393 1394 /* 1395 * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit 1396 * (bit 15 before shifting it to 31) to clear when using interrupt 1397 * coalescing. fortunately, bits 18 and 19 stay set when this happens 1398 * so we use them to decide on the real state of the Rx bit. 1399 * In order words, bit 15 is set if bit 18 or bit 19 are set. 1400 */ 1401 if (val & 0xC0000) 1402 val |= 0x8000; 1403 1404 inta = (0xff & val) | ((0xff00 & val) << 16); 1405 IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", 1406 inta, inta_mask, val); 1407 1408 inta &= trans_pcie->inta_mask; 1409 trans_pcie->inta |= inta; 1410 1411 /* iwl_irq_tasklet() will service interrupts and re-enable them */ 1412 if (likely(inta)) 1413 tasklet_schedule(&trans_pcie->irq_tasklet); 1414 else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 1415 !trans_pcie->inta) { 1416 /* Allow interrupt if was disabled by this handler and 1417 * no tasklet was schedules, We should not enable interrupt, 1418 * tasklet will enable it. 1419 */ 1420 iwl_enable_interrupts(trans); 1421 } 1422 1423 spin_unlock_irqrestore(&trans->shrd->lock, flags); 1424 return IRQ_HANDLED; 1425 1426 none: 1427 /* re-enable interrupts here since we don't have anything to service. 1428 * only Re-enable if disabled by irq. 1429 */ 1430 if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && 1431 !trans_pcie->inta) 1432 iwl_enable_interrupts(trans); 1433 1434 spin_unlock_irqrestore(&trans->shrd->lock, flags); 1435 return IRQ_NONE; 1436} 1437