| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 1 | /****************************************************************************** | 
 | 2 |  * | 
| Wey-Yi Guy | 4e31826 | 2011-12-27 11:21:32 -0800 | [diff] [blame] | 3 |  * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 4 |  * | 
 | 5 |  * Portions of this file are derived from the ipw3945 project, as well | 
 | 6 |  * as portions of the ieee80211 subsystem header files. | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or modify it | 
 | 9 |  * under the terms of version 2 of the GNU General Public License as | 
 | 10 |  * published by the Free Software Foundation. | 
 | 11 |  * | 
 | 12 |  * This program is distributed in the hope that it will be useful, but WITHOUT | 
 | 13 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
 | 14 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
 | 15 |  * more details. | 
 | 16 |  * | 
 | 17 |  * You should have received a copy of the GNU General Public License along with | 
 | 18 |  * this program; if not, write to the Free Software Foundation, Inc., | 
 | 19 |  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | 
 | 20 |  * | 
 | 21 |  * The full GNU General Public License is included in this distribution in the | 
 | 22 |  * file called LICENSE. | 
 | 23 |  * | 
 | 24 |  * Contact Information: | 
 | 25 |  *  Intel Linux Wireless <ilw@linux.intel.com> | 
 | 26 |  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
 | 27 |  * | 
 | 28 |  *****************************************************************************/ | 
 | 29 | #ifndef __iwl_trans_int_pcie_h__ | 
 | 30 | #define __iwl_trans_int_pcie_h__ | 
 | 31 |  | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 32 | #include <linux/spinlock.h> | 
 | 33 | #include <linux/interrupt.h> | 
 | 34 | #include <linux/skbuff.h> | 
| Johannes Berg | 13df1aa | 2012-03-06 13:31:00 -0800 | [diff] [blame] | 35 | #include <linux/wait.h> | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 36 | #include <linux/pci.h> | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 37 |  | 
| Emmanuel Grumbach | dda61a4 | 2011-08-25 23:11:11 -0700 | [diff] [blame] | 38 | #include "iwl-fh.h" | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 39 | #include "iwl-csr.h" | 
 | 40 | #include "iwl-shared.h" | 
 | 41 | #include "iwl-trans.h" | 
 | 42 | #include "iwl-debug.h" | 
 | 43 | #include "iwl-io.h" | 
| Emmanuel Grumbach | 02e3835 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 44 | #include "iwl-op-mode.h" | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 45 |  | 
 | 46 | struct iwl_tx_queue; | 
 | 47 | struct iwl_queue; | 
 | 48 | struct iwl_host_cmd; | 
| Emmanuel Grumbach | dda61a4 | 2011-08-25 23:11:11 -0700 | [diff] [blame] | 49 |  | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 50 | /*This file includes the declaration that are internal to the | 
 | 51 |  * trans_pcie layer */ | 
 | 52 |  | 
| Johannes Berg | 48a2d66 | 2012-03-05 11:24:39 -0800 | [diff] [blame] | 53 | struct iwl_rx_mem_buffer { | 
 | 54 | 	dma_addr_t page_dma; | 
 | 55 | 	struct page *page; | 
 | 56 | 	struct list_head list; | 
 | 57 | }; | 
 | 58 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 59 | /** | 
| Emmanuel Grumbach | 1f7b617 | 2011-08-25 23:10:59 -0700 | [diff] [blame] | 60 |  * struct isr_statistics - interrupt statistics | 
 | 61 |  * | 
 | 62 |  */ | 
 | 63 | struct isr_statistics { | 
 | 64 | 	u32 hw; | 
 | 65 | 	u32 sw; | 
 | 66 | 	u32 err_code; | 
 | 67 | 	u32 sch; | 
 | 68 | 	u32 alive; | 
 | 69 | 	u32 rfkill; | 
 | 70 | 	u32 ctkill; | 
 | 71 | 	u32 wakeup; | 
 | 72 | 	u32 rx; | 
 | 73 | 	u32 tx; | 
 | 74 | 	u32 unhandled; | 
 | 75 | }; | 
 | 76 |  | 
 | 77 | /** | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 78 |  * struct iwl_rx_queue - Rx queue | 
 | 79 |  * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) | 
 | 80 |  * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) | 
 | 81 |  * @pool: | 
 | 82 |  * @queue: | 
 | 83 |  * @read: Shared index to newest available Rx buffer | 
 | 84 |  * @write: Shared index to oldest written Rx packet | 
 | 85 |  * @free_count: Number of pre-allocated buffers in rx_free | 
 | 86 |  * @write_actual: | 
 | 87 |  * @rx_free: list of free SKBs for use | 
 | 88 |  * @rx_used: List of Rx buffers with no SKB | 
 | 89 |  * @need_update: flag to indicate we need to update read/write index | 
 | 90 |  * @rb_stts: driver's pointer to receive buffer status | 
 | 91 |  * @rb_stts_dma: bus address of receive buffer status | 
 | 92 |  * @lock: | 
 | 93 |  * | 
 | 94 |  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers | 
 | 95 |  */ | 
 | 96 | struct iwl_rx_queue { | 
 | 97 | 	__le32 *bd; | 
 | 98 | 	dma_addr_t bd_dma; | 
 | 99 | 	struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; | 
 | 100 | 	struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; | 
 | 101 | 	u32 read; | 
 | 102 | 	u32 write; | 
 | 103 | 	u32 free_count; | 
 | 104 | 	u32 write_actual; | 
 | 105 | 	struct list_head rx_free; | 
 | 106 | 	struct list_head rx_used; | 
 | 107 | 	int need_update; | 
 | 108 | 	struct iwl_rb_status *rb_stts; | 
 | 109 | 	dma_addr_t rb_stts_dma; | 
 | 110 | 	spinlock_t lock; | 
 | 111 | }; | 
 | 112 |  | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 113 | struct iwl_dma_ptr { | 
 | 114 | 	dma_addr_t dma; | 
 | 115 | 	void *addr; | 
 | 116 | 	size_t size; | 
 | 117 | }; | 
 | 118 |  | 
| Johannes Berg | bffc66c | 2012-03-05 11:24:42 -0800 | [diff] [blame] | 119 | /** | 
 | 120 |  * iwl_queue_inc_wrap - increment queue index, wrap back to beginning | 
 | 121 |  * @index -- current index | 
 | 122 |  * @n_bd -- total number of entries in queue (must be power of 2) | 
 | 123 |  */ | 
 | 124 | static inline int iwl_queue_inc_wrap(int index, int n_bd) | 
 | 125 | { | 
 | 126 | 	return ++index & (n_bd - 1); | 
 | 127 | } | 
 | 128 |  | 
 | 129 | /** | 
 | 130 |  * iwl_queue_dec_wrap - decrement queue index, wrap back to end | 
 | 131 |  * @index -- current index | 
 | 132 |  * @n_bd -- total number of entries in queue (must be power of 2) | 
 | 133 |  */ | 
 | 134 | static inline int iwl_queue_dec_wrap(int index, int n_bd) | 
 | 135 | { | 
 | 136 | 	return --index & (n_bd - 1); | 
 | 137 | } | 
 | 138 |  | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 139 | /* | 
 | 140 |  * This queue number is required for proper operation | 
 | 141 |  * because the ucode will stop/start the scheduler as | 
 | 142 |  * required. | 
 | 143 |  */ | 
 | 144 | #define IWL_IPAN_MCAST_QUEUE		8 | 
 | 145 |  | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 146 | struct iwl_cmd_meta { | 
 | 147 | 	/* only for SYNC commands, iff the reply skb is wanted */ | 
 | 148 | 	struct iwl_host_cmd *source; | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 149 |  | 
 | 150 | 	u32 flags; | 
 | 151 |  | 
 | 152 | 	DEFINE_DMA_UNMAP_ADDR(mapping); | 
 | 153 | 	DEFINE_DMA_UNMAP_LEN(len); | 
 | 154 | }; | 
 | 155 |  | 
 | 156 | /* | 
 | 157 |  * Generic queue structure | 
 | 158 |  * | 
 | 159 |  * Contains common data for Rx and Tx queues. | 
 | 160 |  * | 
 | 161 |  * Note the difference between n_bd and n_window: the hardware | 
 | 162 |  * always assumes 256 descriptors, so n_bd is always 256 (unless | 
 | 163 |  * there might be HW changes in the future). For the normal TX | 
 | 164 |  * queues, n_window, which is the size of the software queue data | 
 | 165 |  * is also 256; however, for the command queue, n_window is only | 
 | 166 |  * 32 since we don't need so many commands pending. Since the HW | 
 | 167 |  * still uses 256 BDs for DMA though, n_bd stays 256. As a result, | 
 | 168 |  * the software buffers (in the variables @meta, @txb in struct | 
 | 169 |  * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds | 
 | 170 |  * in the same struct) have 256. | 
 | 171 |  * This means that we end up with the following: | 
 | 172 |  *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 | | 
 | 173 |  *  SW entries:           | 0      | ... | 31          | | 
 | 174 |  * where N is a number between 0 and 7. This means that the SW | 
 | 175 |  * data is a window overlayed over the HW queue. | 
 | 176 |  */ | 
 | 177 | struct iwl_queue { | 
 | 178 | 	int n_bd;              /* number of BDs in this queue */ | 
 | 179 | 	int write_ptr;       /* 1-st empty entry (index) host_w*/ | 
 | 180 | 	int read_ptr;         /* last used entry (index) host_r*/ | 
 | 181 | 	/* use for monitoring and recovering the stuck queue */ | 
 | 182 | 	dma_addr_t dma_addr;   /* physical addr for BD's */ | 
 | 183 | 	int n_window;	       /* safe queue window */ | 
 | 184 | 	u32 id; | 
 | 185 | 	int low_mark;	       /* low watermark, resume queue if free | 
 | 186 | 				* space more than this */ | 
 | 187 | 	int high_mark;         /* high watermark, stop queue if free | 
 | 188 | 				* space less than this */ | 
 | 189 | }; | 
 | 190 |  | 
 | 191 | /** | 
 | 192 |  * struct iwl_tx_queue - Tx Queue for DMA | 
 | 193 |  * @q: generic Rx/Tx queue descriptor | 
 | 194 |  * @bd: base of circular buffer of TFDs | 
 | 195 |  * @cmd: array of command/TX buffer pointers | 
 | 196 |  * @meta: array of meta data for each command/tx buffer | 
 | 197 |  * @dma_addr_cmd: physical address of cmd/tx buffer array | 
 | 198 |  * @txb: array of per-TFD driver data | 
| Johannes Berg | 015c15e | 2012-03-05 11:24:24 -0800 | [diff] [blame] | 199 |  * lock: queue lock | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 200 |  * @time_stamp: time (in jiffies) of last read_ptr change | 
 | 201 |  * @need_update: indicates need to update read/write index | 
 | 202 |  * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled | 
 | 203 |  * @sta_id: valid if sched_retry is set | 
 | 204 |  * @tid: valid if sched_retry is set | 
 | 205 |  * | 
 | 206 |  * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame | 
 | 207 |  * descriptors) and required locking structures. | 
 | 208 |  */ | 
 | 209 | #define TFD_TX_CMD_SLOTS 256 | 
 | 210 | #define TFD_CMD_SLOTS 32 | 
 | 211 |  | 
 | 212 | struct iwl_tx_queue { | 
 | 213 | 	struct iwl_queue q; | 
 | 214 | 	struct iwl_tfd *tfds; | 
 | 215 | 	struct iwl_device_cmd **cmd; | 
 | 216 | 	struct iwl_cmd_meta *meta; | 
 | 217 | 	struct sk_buff **skbs; | 
| Johannes Berg | 015c15e | 2012-03-05 11:24:24 -0800 | [diff] [blame] | 218 | 	spinlock_t lock; | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 219 | 	unsigned long time_stamp; | 
 | 220 | 	u8 need_update; | 
 | 221 | 	u8 sched_retry; | 
 | 222 | 	u8 active; | 
 | 223 | 	u8 swq_id; | 
 | 224 |  | 
 | 225 | 	u16 sta_id; | 
 | 226 | 	u16 tid; | 
 | 227 | }; | 
 | 228 |  | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 229 | /** | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 230 |  * struct iwl_trans_pcie - PCIe transport specific data | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 231 |  * @rxq: all the RX queue data | 
 | 232 |  * @rx_replenish: work that will be called when buffers need to be allocated | 
 | 233 |  * @trans: pointer to the generic transport area | 
| Johannes Berg | 7559553 | 2012-03-06 13:31:01 -0800 | [diff] [blame] | 234 |  * @irq - the irq number for the device | 
| Emmanuel Grumbach | 57a1dc8 | 2012-01-08 13:22:16 +0200 | [diff] [blame] | 235 |  * @irq_requested: true when the irq has been requested | 
| Emmanuel Grumbach | 105183b | 2011-08-25 23:11:02 -0700 | [diff] [blame] | 236 |  * @scd_base_addr: scheduler sram base address in SRAM | 
 | 237 |  * @scd_bc_tbls: pointer to the byte count table of the scheduler | 
| Emmanuel Grumbach | 9d6b2cb | 2011-08-25 23:11:12 -0700 | [diff] [blame] | 238 |  * @kw: keep warm address | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 239 |  * @ac_to_fifo: to what fifo is a specifc AC mapped ? | 
 | 240 |  * @ac_to_queue: to what tx queue  is a specifc AC mapped ? | 
 | 241 |  * @mcast_queue: | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 242 |  * @txq: Tx DMA processing queues | 
 | 243 |  * @txq_ctx_active_msk: what queue is active | 
 | 244 |  * queue_stopped: tracks what queue is stopped | 
 | 245 |  * queue_stop_count: tracks what SW queue is stopped | 
| Emmanuel Grumbach | a42a184 | 2012-02-02 14:33:08 -0800 | [diff] [blame] | 246 |  * @pci_dev: basic pci-network driver stuff | 
 | 247 |  * @hw_base: pci hardware address support | 
| Johannes Berg | 13df1aa | 2012-03-06 13:31:00 -0800 | [diff] [blame] | 248 |  * @ucode_write_complete: indicates that the ucode has been copied. | 
 | 249 |  * @ucode_write_waitq: wait queue for uCode load | 
| Don Fry | 9a71686 | 2012-03-07 09:52:32 -0800 | [diff] [blame] | 250 |  * @status - transport specific status flags | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 251 |  * @cmd_queue - command queue number | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 252 |  */ | 
 | 253 | struct iwl_trans_pcie { | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 254 | 	struct iwl_rx_queue rxq; | 
 | 255 | 	struct work_struct rx_replenish; | 
 | 256 | 	struct iwl_trans *trans; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 257 |  | 
 | 258 | 	/* INT ICT Table */ | 
 | 259 | 	__le32 *ict_tbl; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 260 | 	dma_addr_t ict_tbl_dma; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 261 | 	int ict_index; | 
 | 262 | 	u32 inta; | 
 | 263 | 	bool use_ict; | 
| Emmanuel Grumbach | 57a1dc8 | 2012-01-08 13:22:16 +0200 | [diff] [blame] | 264 | 	bool irq_requested; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 265 | 	struct tasklet_struct irq_tasklet; | 
| Emmanuel Grumbach | 1f7b617 | 2011-08-25 23:10:59 -0700 | [diff] [blame] | 266 | 	struct isr_statistics isr_stats; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 267 |  | 
| Johannes Berg | 7559553 | 2012-03-06 13:31:01 -0800 | [diff] [blame] | 268 | 	unsigned int irq; | 
| Johannes Berg | 7b11488 | 2012-02-05 13:55:11 -0800 | [diff] [blame] | 269 | 	spinlock_t irq_lock; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 270 | 	u32 inta_mask; | 
| Emmanuel Grumbach | 105183b | 2011-08-25 23:11:02 -0700 | [diff] [blame] | 271 | 	u32 scd_base_addr; | 
 | 272 | 	struct iwl_dma_ptr scd_bc_tbls; | 
| Emmanuel Grumbach | 9d6b2cb | 2011-08-25 23:11:12 -0700 | [diff] [blame] | 273 | 	struct iwl_dma_ptr kw; | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 274 |  | 
 | 275 | 	const u8 *ac_to_fifo[NUM_IWL_RXON_CTX]; | 
 | 276 | 	const u8 *ac_to_queue[NUM_IWL_RXON_CTX]; | 
 | 277 | 	u8 mcast_queue[NUM_IWL_RXON_CTX]; | 
| Emmanuel Grumbach | 76bc10f | 2011-11-21 13:25:31 +0200 | [diff] [blame] | 278 | 	u8 agg_txq[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 279 |  | 
 | 280 | 	struct iwl_tx_queue *txq; | 
 | 281 | 	unsigned long txq_ctx_active_msk; | 
 | 282 | #define IWL_MAX_HW_QUEUES	32 | 
 | 283 | 	unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; | 
 | 284 | 	atomic_t queue_stop_count[4]; | 
| Emmanuel Grumbach | a42a184 | 2012-02-02 14:33:08 -0800 | [diff] [blame] | 285 |  | 
 | 286 | 	/* PCI bus related data */ | 
 | 287 | 	struct pci_dev *pci_dev; | 
 | 288 | 	void __iomem *hw_base; | 
| Johannes Berg | 13df1aa | 2012-03-06 13:31:00 -0800 | [diff] [blame] | 289 |  | 
 | 290 | 	bool ucode_write_complete; | 
 | 291 | 	wait_queue_head_t ucode_write_waitq; | 
| Don Fry | 9a71686 | 2012-03-07 09:52:32 -0800 | [diff] [blame] | 292 | 	unsigned long status; | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 293 | 	u8 cmd_queue; | 
| Johannes Berg | d663ee7 | 2012-03-10 13:00:07 -0800 | [diff] [blame] | 294 | 	u8 n_no_reclaim_cmds; | 
 | 295 | 	u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 296 | }; | 
 | 297 |  | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 298 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ | 
 | 299 | 	((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) | 
 | 300 |  | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 301 | /***************************************************** | 
 | 302 | * RX | 
 | 303 | ******************************************************/ | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 304 | void iwl_bg_rx_replenish(struct work_struct *data); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 305 | void iwl_irq_tasklet(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 306 | void iwlagn_rx_replenish(struct iwl_trans *trans); | 
 | 307 | void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 308 | 			struct iwl_rx_queue *q); | 
 | 309 |  | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 310 | /***************************************************** | 
| Emmanuel Grumbach | 1a361cd | 2011-07-11 07:44:57 -0700 | [diff] [blame] | 311 | * ICT | 
 | 312 | ******************************************************/ | 
| Emmanuel Grumbach | ed6a380 | 2012-01-02 16:10:08 +0200 | [diff] [blame] | 313 | void iwl_reset_ict(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 314 | void iwl_disable_ict(struct iwl_trans *trans); | 
 | 315 | int iwl_alloc_isr_ict(struct iwl_trans *trans); | 
 | 316 | void iwl_free_isr_ict(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 1a361cd | 2011-07-11 07:44:57 -0700 | [diff] [blame] | 317 | irqreturn_t iwl_isr_ict(int irq, void *data); | 
 | 318 |  | 
| Emmanuel Grumbach | 1a361cd | 2011-07-11 07:44:57 -0700 | [diff] [blame] | 319 | /***************************************************** | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 320 | * TX / HCMD | 
 | 321 | ******************************************************/ | 
| Emmanuel Grumbach | fd65693 | 2011-08-25 23:11:19 -0700 | [diff] [blame] | 322 | void iwl_txq_update_write_ptr(struct iwl_trans *trans, | 
 | 323 | 			struct iwl_tx_queue *txq); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 324 | int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 325 | 				 struct iwl_tx_queue *txq, | 
 | 326 | 				 dma_addr_t addr, u16 len, u8 reset); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 327 | int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id); | 
 | 328 | int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); | 
| Emmanuel Grumbach | 3e10cae | 2011-09-06 09:31:18 -0700 | [diff] [blame] | 329 | void iwl_tx_cmd_complete(struct iwl_trans *trans, | 
| Johannes Berg | 48a2d66 | 2012-03-05 11:24:39 -0800 | [diff] [blame] | 330 | 			 struct iwl_rx_cmd_buffer *rxb, int handler_status); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 331 | void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 332 | 					   struct iwl_tx_queue *txq, | 
 | 333 | 					   u16 byte_cnt); | 
| Emmanuel Grumbach | 7f01d56 | 2011-08-25 23:11:27 -0700 | [diff] [blame] | 334 | int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, | 
| Emmanuel Grumbach | bc23773 | 2011-11-21 13:25:31 +0200 | [diff] [blame] | 335 | 				  int sta_id, int tid); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 336 | void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index); | 
| Emmanuel Grumbach | c91bd12 | 2011-08-25 23:11:28 -0700 | [diff] [blame] | 337 | void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 338 | 			     struct iwl_tx_queue *txq, | 
 | 339 | 			     int tx_fifo_id, int scd_retry); | 
| Emmanuel Grumbach | 3c69b59 | 2011-11-21 13:25:31 +0200 | [diff] [blame] | 340 | int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, int sta_id, int tid); | 
| Emmanuel Grumbach | c91bd12 | 2011-08-25 23:11:28 -0700 | [diff] [blame] | 341 | void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, | 
 | 342 | 				 enum iwl_rxon_context_id ctx, | 
| Emmanuel Grumbach | 822e8b2 | 2011-11-21 13:25:31 +0200 | [diff] [blame] | 343 | 				 int sta_id, int tid, int frame_limit, u16 ssn); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 344 | void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, | 
| Emmanuel Grumbach | 39644e9 | 2011-09-15 11:46:29 -0700 | [diff] [blame] | 345 | 	int index, enum dma_data_direction dma_dir); | 
| Emmanuel Grumbach | 464021f | 2011-08-25 23:11:26 -0700 | [diff] [blame] | 346 | int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, | 
 | 347 | 			 struct sk_buff_head *skbs); | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 348 | int iwl_queue_space(const struct iwl_queue *q); | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 349 |  | 
| Emmanuel Grumbach | 7ff9470 | 2011-08-25 23:10:54 -0700 | [diff] [blame] | 350 | /***************************************************** | 
 | 351 | * Error handling | 
 | 352 | ******************************************************/ | 
| Emmanuel Grumbach | 6bb7884 | 2011-08-25 23:11:09 -0700 | [diff] [blame] | 353 | int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, | 
 | 354 | 			    char **buf, bool display); | 
| Emmanuel Grumbach | 16db88b | 2011-08-25 23:11:08 -0700 | [diff] [blame] | 355 | int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display); | 
 | 356 | void iwl_dump_csr(struct iwl_trans *trans); | 
 | 357 |  | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 358 | /***************************************************** | 
 | 359 | * Helpers | 
 | 360 | ******************************************************/ | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 361 | static inline void iwl_disable_interrupts(struct iwl_trans *trans) | 
 | 362 | { | 
| Don Fry | 8362640 | 2012-03-07 09:52:37 -0800 | [diff] [blame] | 363 | 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 
 | 364 | 	clear_bit(STATUS_INT_ENABLED, &trans_pcie->status); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 365 |  | 
 | 366 | 	/* disable interrupts from uCode/NIC to host */ | 
| Emmanuel Grumbach | 1042db2 | 2012-01-03 16:56:15 +0200 | [diff] [blame] | 367 | 	iwl_write32(trans, CSR_INT_MASK, 0x00000000); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 368 |  | 
 | 369 | 	/* acknowledge/clear/reset any interrupts still pending | 
 | 370 | 	 * from uCode or flow handler (Rx/Tx DMA) */ | 
| Emmanuel Grumbach | 1042db2 | 2012-01-03 16:56:15 +0200 | [diff] [blame] | 371 | 	iwl_write32(trans, CSR_INT, 0xffffffff); | 
 | 372 | 	iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 373 | 	IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); | 
 | 374 | } | 
 | 375 |  | 
 | 376 | static inline void iwl_enable_interrupts(struct iwl_trans *trans) | 
 | 377 | { | 
| Don Fry | 8362640 | 2012-03-07 09:52:37 -0800 | [diff] [blame] | 378 | 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 379 |  | 
 | 380 | 	IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); | 
| Don Fry | 8362640 | 2012-03-07 09:52:37 -0800 | [diff] [blame] | 381 | 	set_bit(STATUS_INT_ENABLED, &trans_pcie->status); | 
| Emmanuel Grumbach | 1042db2 | 2012-01-03 16:56:15 +0200 | [diff] [blame] | 382 | 	iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 383 | } | 
 | 384 |  | 
| Stanislaw Gruszka | 8722c89 | 2012-03-07 09:52:28 -0800 | [diff] [blame] | 385 | static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) | 
 | 386 | { | 
 | 387 | 	IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); | 
 | 388 | 	iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); | 
 | 389 | } | 
 | 390 |  | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 391 | /* | 
 | 392 |  * we have 8 bits used like this: | 
 | 393 |  * | 
 | 394 |  * 7 6 5 4 3 2 1 0 | 
 | 395 |  * | | | | | | | | | 
 | 396 |  * | | | | | | +-+-------- AC queue (0-3) | 
 | 397 |  * | | | | | | | 
 | 398 |  * | +-+-+-+-+------------ HW queue ID | 
 | 399 |  * | | 
 | 400 |  * +---------------------- unused | 
 | 401 |  */ | 
 | 402 | static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) | 
 | 403 | { | 
 | 404 | 	BUG_ON(ac > 3);   /* only have 2 bits */ | 
 | 405 | 	BUG_ON(hwq > 31); /* only use 5 bits */ | 
 | 406 |  | 
 | 407 | 	txq->swq_id = (hwq << 2) | ac; | 
 | 408 | } | 
 | 409 |  | 
| Emmanuel Grumbach | 1daf04b | 2011-11-17 16:05:10 -0800 | [diff] [blame] | 410 | static inline u8 iwl_get_queue_ac(struct iwl_tx_queue *txq) | 
 | 411 | { | 
 | 412 | 	return txq->swq_id & 0x3; | 
 | 413 | } | 
 | 414 |  | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 415 | static inline void iwl_wake_queue(struct iwl_trans *trans, | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 416 | 				  struct iwl_tx_queue *txq) | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 417 | { | 
 | 418 | 	u8 queue = txq->swq_id; | 
 | 419 | 	u8 ac = queue & 3; | 
 | 420 | 	u8 hwq = (queue >> 2) & 0x1f; | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 421 | 	struct iwl_trans_pcie *trans_pcie = | 
 | 422 | 		IWL_TRANS_GET_PCIE_TRANS(trans); | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 423 |  | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 424 | 	if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) { | 
 | 425 | 		if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) { | 
| Emmanuel Grumbach | 02e3835 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 426 | 			iwl_op_mode_queue_not_full(trans->op_mode, ac); | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 427 | 			IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d", | 
 | 428 | 					    hwq, ac); | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 429 | 		} else { | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 430 | 			IWL_DEBUG_TX_QUEUES(trans, | 
 | 431 | 				"Don't wake hwq %d ac %d stop count %d", | 
 | 432 | 				hwq, ac, | 
 | 433 | 				atomic_read(&trans_pcie->queue_stop_count[ac])); | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 434 | 		} | 
 | 435 | 	} | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 436 | } | 
 | 437 |  | 
 | 438 | static inline void iwl_stop_queue(struct iwl_trans *trans, | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 439 | 				  struct iwl_tx_queue *txq) | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 440 | { | 
 | 441 | 	u8 queue = txq->swq_id; | 
 | 442 | 	u8 ac = queue & 3; | 
 | 443 | 	u8 hwq = (queue >> 2) & 0x1f; | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 444 | 	struct iwl_trans_pcie *trans_pcie = | 
 | 445 | 		IWL_TRANS_GET_PCIE_TRANS(trans); | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 446 |  | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 447 | 	if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) { | 
 | 448 | 		if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) { | 
| Emmanuel Grumbach | 02e3835 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 449 | 			iwl_op_mode_queue_full(trans->op_mode, ac); | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 450 | 			IWL_DEBUG_TX_QUEUES(trans, | 
 | 451 | 				"Stop hwq %d ac %d stop count %d", | 
 | 452 | 				hwq, ac, | 
 | 453 | 				atomic_read(&trans_pcie->queue_stop_count[ac])); | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 454 | 		} else { | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 455 | 			IWL_DEBUG_TX_QUEUES(trans, | 
 | 456 | 				"Don't stop hwq %d ac %d stop count %d", | 
 | 457 | 				hwq, ac, | 
 | 458 | 				atomic_read(&trans_pcie->queue_stop_count[ac])); | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 459 | 		} | 
 | 460 | 	} else { | 
| Johannes Berg | bada991 | 2012-03-07 09:52:39 -0800 | [diff] [blame] | 461 | 		IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped", | 
 | 462 | 				    hwq); | 
| Emmanuel Grumbach | 81a3de1 | 2011-11-10 06:55:24 -0800 | [diff] [blame] | 463 | 	} | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 464 | } | 
 | 465 |  | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 466 | static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie, | 
 | 467 | 					int txq_id) | 
 | 468 | { | 
 | 469 | 	set_bit(txq_id, &trans_pcie->txq_ctx_active_msk); | 
 | 470 | } | 
 | 471 |  | 
 | 472 | static inline void iwl_txq_ctx_deactivate(struct iwl_trans_pcie *trans_pcie, | 
 | 473 | 					  int txq_id) | 
 | 474 | { | 
 | 475 | 	clear_bit(txq_id, &trans_pcie->txq_ctx_active_msk); | 
 | 476 | } | 
 | 477 |  | 
 | 478 | static inline int iwl_queue_used(const struct iwl_queue *q, int i) | 
 | 479 | { | 
 | 480 | 	return q->write_ptr >= q->read_ptr ? | 
 | 481 | 		(i >= q->read_ptr && i < q->write_ptr) : | 
 | 482 | 		!(i < q->read_ptr && i >= q->write_ptr); | 
 | 483 | } | 
 | 484 |  | 
 | 485 | static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) | 
 | 486 | { | 
 | 487 | 	return index & (q->n_window - 1); | 
 | 488 | } | 
 | 489 |  | 
| Emmanuel Grumbach | 7a10e3e | 2011-09-06 09:31:21 -0700 | [diff] [blame] | 490 | #define IWL_TX_FIFO_BK		0	/* shared */ | 
 | 491 | #define IWL_TX_FIFO_BE		1 | 
 | 492 | #define IWL_TX_FIFO_VI		2	/* shared */ | 
 | 493 | #define IWL_TX_FIFO_VO		3 | 
 | 494 | #define IWL_TX_FIFO_BK_IPAN	IWL_TX_FIFO_BK | 
 | 495 | #define IWL_TX_FIFO_BE_IPAN	4 | 
 | 496 | #define IWL_TX_FIFO_VI_IPAN	IWL_TX_FIFO_VI | 
 | 497 | #define IWL_TX_FIFO_VO_IPAN	5 | 
 | 498 | /* re-uses the VO FIFO, uCode will properly flush/schedule */ | 
 | 499 | #define IWL_TX_FIFO_AUX		5 | 
 | 500 | #define IWL_TX_FIFO_UNUSED	-1 | 
 | 501 |  | 
 | 502 | /* AUX (TX during scan dwell) queue */ | 
 | 503 | #define IWL_AUX_QUEUE		10 | 
 | 504 |  | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 505 | #endif /* __iwl_trans_int_pcie_h__ */ |