| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 1 | /****************************************************************************** | 
|  | 2 | * | 
|  | 3 | * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. | 
|  | 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> | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 35 | #include <linux/pci.h> | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 36 |  | 
| Emmanuel Grumbach | dda61a4 | 2011-08-25 23:11:11 -0700 | [diff] [blame] | 37 | #include "iwl-fh.h" | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 38 | #include "iwl-csr.h" | 
|  | 39 | #include "iwl-shared.h" | 
|  | 40 | #include "iwl-trans.h" | 
|  | 41 | #include "iwl-debug.h" | 
|  | 42 | #include "iwl-io.h" | 
|  | 43 |  | 
|  | 44 | struct iwl_tx_queue; | 
|  | 45 | struct iwl_queue; | 
|  | 46 | struct iwl_host_cmd; | 
| Emmanuel Grumbach | dda61a4 | 2011-08-25 23:11:11 -0700 | [diff] [blame] | 47 |  | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 48 | /*This file includes the declaration that are internal to the | 
|  | 49 | * trans_pcie layer */ | 
|  | 50 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 51 | /** | 
| Emmanuel Grumbach | 1f7b617 | 2011-08-25 23:10:59 -0700 | [diff] [blame] | 52 | * struct isr_statistics - interrupt statistics | 
|  | 53 | * | 
|  | 54 | */ | 
|  | 55 | struct isr_statistics { | 
|  | 56 | u32 hw; | 
|  | 57 | u32 sw; | 
|  | 58 | u32 err_code; | 
|  | 59 | u32 sch; | 
|  | 60 | u32 alive; | 
|  | 61 | u32 rfkill; | 
|  | 62 | u32 ctkill; | 
|  | 63 | u32 wakeup; | 
|  | 64 | u32 rx; | 
|  | 65 | u32 tx; | 
|  | 66 | u32 unhandled; | 
|  | 67 | }; | 
|  | 68 |  | 
|  | 69 | /** | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 70 | * struct iwl_rx_queue - Rx queue | 
|  | 71 | * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) | 
|  | 72 | * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) | 
|  | 73 | * @pool: | 
|  | 74 | * @queue: | 
|  | 75 | * @read: Shared index to newest available Rx buffer | 
|  | 76 | * @write: Shared index to oldest written Rx packet | 
|  | 77 | * @free_count: Number of pre-allocated buffers in rx_free | 
|  | 78 | * @write_actual: | 
|  | 79 | * @rx_free: list of free SKBs for use | 
|  | 80 | * @rx_used: List of Rx buffers with no SKB | 
|  | 81 | * @need_update: flag to indicate we need to update read/write index | 
|  | 82 | * @rb_stts: driver's pointer to receive buffer status | 
|  | 83 | * @rb_stts_dma: bus address of receive buffer status | 
|  | 84 | * @lock: | 
|  | 85 | * | 
|  | 86 | * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers | 
|  | 87 | */ | 
|  | 88 | struct iwl_rx_queue { | 
|  | 89 | __le32 *bd; | 
|  | 90 | dma_addr_t bd_dma; | 
|  | 91 | struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; | 
|  | 92 | struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; | 
|  | 93 | u32 read; | 
|  | 94 | u32 write; | 
|  | 95 | u32 free_count; | 
|  | 96 | u32 write_actual; | 
|  | 97 | struct list_head rx_free; | 
|  | 98 | struct list_head rx_used; | 
|  | 99 | int need_update; | 
|  | 100 | struct iwl_rb_status *rb_stts; | 
|  | 101 | dma_addr_t rb_stts_dma; | 
|  | 102 | spinlock_t lock; | 
|  | 103 | }; | 
|  | 104 |  | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 105 | struct iwl_dma_ptr { | 
|  | 106 | dma_addr_t dma; | 
|  | 107 | void *addr; | 
|  | 108 | size_t size; | 
|  | 109 | }; | 
|  | 110 |  | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 111 | /* | 
|  | 112 | * This queue number is required for proper operation | 
|  | 113 | * because the ucode will stop/start the scheduler as | 
|  | 114 | * required. | 
|  | 115 | */ | 
|  | 116 | #define IWL_IPAN_MCAST_QUEUE		8 | 
|  | 117 |  | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 118 | struct iwl_cmd_meta { | 
|  | 119 | /* only for SYNC commands, iff the reply skb is wanted */ | 
|  | 120 | struct iwl_host_cmd *source; | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 121 |  | 
|  | 122 | u32 flags; | 
|  | 123 |  | 
|  | 124 | DEFINE_DMA_UNMAP_ADDR(mapping); | 
|  | 125 | DEFINE_DMA_UNMAP_LEN(len); | 
|  | 126 | }; | 
|  | 127 |  | 
|  | 128 | /* | 
|  | 129 | * Generic queue structure | 
|  | 130 | * | 
|  | 131 | * Contains common data for Rx and Tx queues. | 
|  | 132 | * | 
|  | 133 | * Note the difference between n_bd and n_window: the hardware | 
|  | 134 | * always assumes 256 descriptors, so n_bd is always 256 (unless | 
|  | 135 | * there might be HW changes in the future). For the normal TX | 
|  | 136 | * queues, n_window, which is the size of the software queue data | 
|  | 137 | * is also 256; however, for the command queue, n_window is only | 
|  | 138 | * 32 since we don't need so many commands pending. Since the HW | 
|  | 139 | * still uses 256 BDs for DMA though, n_bd stays 256. As a result, | 
|  | 140 | * the software buffers (in the variables @meta, @txb in struct | 
|  | 141 | * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds | 
|  | 142 | * in the same struct) have 256. | 
|  | 143 | * This means that we end up with the following: | 
|  | 144 | *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 | | 
|  | 145 | *  SW entries:           | 0      | ... | 31          | | 
|  | 146 | * where N is a number between 0 and 7. This means that the SW | 
|  | 147 | * data is a window overlayed over the HW queue. | 
|  | 148 | */ | 
|  | 149 | struct iwl_queue { | 
|  | 150 | int n_bd;              /* number of BDs in this queue */ | 
|  | 151 | int write_ptr;       /* 1-st empty entry (index) host_w*/ | 
|  | 152 | int read_ptr;         /* last used entry (index) host_r*/ | 
|  | 153 | /* use for monitoring and recovering the stuck queue */ | 
|  | 154 | dma_addr_t dma_addr;   /* physical addr for BD's */ | 
|  | 155 | int n_window;	       /* safe queue window */ | 
|  | 156 | u32 id; | 
|  | 157 | int low_mark;	       /* low watermark, resume queue if free | 
|  | 158 | * space more than this */ | 
|  | 159 | int high_mark;         /* high watermark, stop queue if free | 
|  | 160 | * space less than this */ | 
|  | 161 | }; | 
|  | 162 |  | 
|  | 163 | /** | 
|  | 164 | * struct iwl_tx_queue - Tx Queue for DMA | 
|  | 165 | * @q: generic Rx/Tx queue descriptor | 
|  | 166 | * @bd: base of circular buffer of TFDs | 
|  | 167 | * @cmd: array of command/TX buffer pointers | 
|  | 168 | * @meta: array of meta data for each command/tx buffer | 
|  | 169 | * @dma_addr_cmd: physical address of cmd/tx buffer array | 
|  | 170 | * @txb: array of per-TFD driver data | 
|  | 171 | * @time_stamp: time (in jiffies) of last read_ptr change | 
|  | 172 | * @need_update: indicates need to update read/write index | 
|  | 173 | * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled | 
|  | 174 | * @sta_id: valid if sched_retry is set | 
|  | 175 | * @tid: valid if sched_retry is set | 
|  | 176 | * | 
|  | 177 | * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame | 
|  | 178 | * descriptors) and required locking structures. | 
|  | 179 | */ | 
|  | 180 | #define TFD_TX_CMD_SLOTS 256 | 
|  | 181 | #define TFD_CMD_SLOTS 32 | 
|  | 182 |  | 
|  | 183 | struct iwl_tx_queue { | 
|  | 184 | struct iwl_queue q; | 
|  | 185 | struct iwl_tfd *tfds; | 
|  | 186 | struct iwl_device_cmd **cmd; | 
|  | 187 | struct iwl_cmd_meta *meta; | 
|  | 188 | struct sk_buff **skbs; | 
|  | 189 | unsigned long time_stamp; | 
|  | 190 | u8 need_update; | 
|  | 191 | u8 sched_retry; | 
|  | 192 | u8 active; | 
|  | 193 | u8 swq_id; | 
|  | 194 |  | 
|  | 195 | u16 sta_id; | 
|  | 196 | u16 tid; | 
|  | 197 | }; | 
|  | 198 |  | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 199 | /** | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 200 | * struct iwl_trans_pcie - PCIe transport specific data | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 201 | * @rxq: all the RX queue data | 
|  | 202 | * @rx_replenish: work that will be called when buffers need to be allocated | 
|  | 203 | * @trans: pointer to the generic transport area | 
| Emmanuel Grumbach | 105183b | 2011-08-25 23:11:02 -0700 | [diff] [blame] | 204 | * @scd_base_addr: scheduler sram base address in SRAM | 
|  | 205 | * @scd_bc_tbls: pointer to the byte count table of the scheduler | 
| Emmanuel Grumbach | 9d6b2cb | 2011-08-25 23:11:12 -0700 | [diff] [blame] | 206 | * @kw: keep warm address | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 207 | * @ac_to_fifo: to what fifo is a specifc AC mapped ? | 
|  | 208 | * @ac_to_queue: to what tx queue  is a specifc AC mapped ? | 
|  | 209 | * @mcast_queue: | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 210 | * @txq: Tx DMA processing queues | 
|  | 211 | * @txq_ctx_active_msk: what queue is active | 
|  | 212 | * queue_stopped: tracks what queue is stopped | 
|  | 213 | * queue_stop_count: tracks what SW queue is stopped | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 214 | */ | 
|  | 215 | struct iwl_trans_pcie { | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 216 | struct iwl_rx_queue rxq; | 
|  | 217 | struct work_struct rx_replenish; | 
|  | 218 | struct iwl_trans *trans; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 219 |  | 
|  | 220 | /* INT ICT Table */ | 
|  | 221 | __le32 *ict_tbl; | 
|  | 222 | void *ict_tbl_vir; | 
|  | 223 | dma_addr_t ict_tbl_dma; | 
|  | 224 | dma_addr_t aligned_ict_tbl_dma; | 
|  | 225 | int ict_index; | 
|  | 226 | u32 inta; | 
|  | 227 | bool use_ict; | 
|  | 228 | struct tasklet_struct irq_tasklet; | 
| Emmanuel Grumbach | 1f7b617 | 2011-08-25 23:10:59 -0700 | [diff] [blame] | 229 | struct isr_statistics isr_stats; | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 230 |  | 
|  | 231 | u32 inta_mask; | 
| Emmanuel Grumbach | 105183b | 2011-08-25 23:11:02 -0700 | [diff] [blame] | 232 | u32 scd_base_addr; | 
|  | 233 | struct iwl_dma_ptr scd_bc_tbls; | 
| Emmanuel Grumbach | 9d6b2cb | 2011-08-25 23:11:12 -0700 | [diff] [blame] | 234 | struct iwl_dma_ptr kw; | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 235 |  | 
|  | 236 | const u8 *ac_to_fifo[NUM_IWL_RXON_CTX]; | 
|  | 237 | const u8 *ac_to_queue[NUM_IWL_RXON_CTX]; | 
|  | 238 | u8 mcast_queue[NUM_IWL_RXON_CTX]; | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 239 |  | 
|  | 240 | struct iwl_tx_queue *txq; | 
|  | 241 | unsigned long txq_ctx_active_msk; | 
|  | 242 | #define IWL_MAX_HW_QUEUES	32 | 
|  | 243 | unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; | 
|  | 244 | atomic_t queue_stop_count[4]; | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 245 | }; | 
|  | 246 |  | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 247 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ | 
|  | 248 | ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) | 
|  | 249 |  | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 250 | /***************************************************** | 
|  | 251 | * RX | 
|  | 252 | ******************************************************/ | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 253 | void iwl_bg_rx_replenish(struct work_struct *data); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 254 | void iwl_irq_tasklet(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 5a878bf | 2011-08-25 23:10:51 -0700 | [diff] [blame] | 255 | void iwlagn_rx_replenish(struct iwl_trans *trans); | 
|  | 256 | void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 257 | struct iwl_rx_queue *q); | 
|  | 258 |  | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 259 | /***************************************************** | 
| Emmanuel Grumbach | 1a361cd | 2011-07-11 07:44:57 -0700 | [diff] [blame] | 260 | * ICT | 
|  | 261 | ******************************************************/ | 
| Emmanuel Grumbach | 6bb7884 | 2011-08-25 23:11:09 -0700 | [diff] [blame] | 262 | int iwl_reset_ict(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 263 | void iwl_disable_ict(struct iwl_trans *trans); | 
|  | 264 | int iwl_alloc_isr_ict(struct iwl_trans *trans); | 
|  | 265 | void iwl_free_isr_ict(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 1a361cd | 2011-07-11 07:44:57 -0700 | [diff] [blame] | 266 | irqreturn_t iwl_isr_ict(int irq, void *data); | 
|  | 267 |  | 
| Emmanuel Grumbach | 1a361cd | 2011-07-11 07:44:57 -0700 | [diff] [blame] | 268 | /***************************************************** | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 269 | * TX / HCMD | 
|  | 270 | ******************************************************/ | 
| Emmanuel Grumbach | fd65693 | 2011-08-25 23:11:19 -0700 | [diff] [blame] | 271 | void iwl_txq_update_write_ptr(struct iwl_trans *trans, | 
|  | 272 | struct iwl_tx_queue *txq); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 273 | int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 274 | struct iwl_tx_queue *txq, | 
|  | 275 | dma_addr_t addr, u16 len, u8 reset); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 276 | int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id); | 
|  | 277 | 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] | 278 | void iwl_tx_cmd_complete(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 247c61d | 2011-09-20 15:37:23 -0700 | [diff] [blame] | 279 | struct iwl_rx_mem_buffer *rxb, int handler_status); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 280 | void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 281 | struct iwl_tx_queue *txq, | 
|  | 282 | u16 byte_cnt); | 
| Emmanuel Grumbach | 7f01d56 | 2011-08-25 23:11:27 -0700 | [diff] [blame] | 283 | void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id); | 
|  | 284 | int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, | 
|  | 285 | enum iwl_rxon_context_id ctx, int sta_id, | 
|  | 286 | int tid); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 287 | 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] | 288 | void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 289 | struct iwl_tx_queue *txq, | 
|  | 290 | int tx_fifo_id, int scd_retry); | 
| Emmanuel Grumbach | 288712a | 2011-08-25 23:11:25 -0700 | [diff] [blame] | 291 | int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, | 
|  | 292 | enum iwl_rxon_context_id ctx, int sta_id, | 
|  | 293 | int tid, u16 *ssn); | 
| Emmanuel Grumbach | c91bd12 | 2011-08-25 23:11:28 -0700 | [diff] [blame] | 294 | void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, | 
|  | 295 | enum iwl_rxon_context_id ctx, | 
|  | 296 | int sta_id, int tid, int frame_limit); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 297 | 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] | 298 | int index, enum dma_data_direction dma_dir); | 
| Emmanuel Grumbach | 464021f | 2011-08-25 23:11:26 -0700 | [diff] [blame] | 299 | int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, | 
|  | 300 | struct sk_buff_head *skbs); | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 301 | int iwl_queue_space(const struct iwl_queue *q); | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 302 |  | 
| Emmanuel Grumbach | 7ff9470 | 2011-08-25 23:10:54 -0700 | [diff] [blame] | 303 | /***************************************************** | 
|  | 304 | * Error handling | 
|  | 305 | ******************************************************/ | 
| Emmanuel Grumbach | 6bb7884 | 2011-08-25 23:11:09 -0700 | [diff] [blame] | 306 | int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, | 
|  | 307 | char **buf, bool display); | 
| Emmanuel Grumbach | 16db88b | 2011-08-25 23:11:08 -0700 | [diff] [blame] | 308 | int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display); | 
|  | 309 | void iwl_dump_csr(struct iwl_trans *trans); | 
|  | 310 |  | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 311 | /***************************************************** | 
|  | 312 | * Helpers | 
|  | 313 | ******************************************************/ | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 314 | static inline void iwl_disable_interrupts(struct iwl_trans *trans) | 
|  | 315 | { | 
|  | 316 | clear_bit(STATUS_INT_ENABLED, &trans->shrd->status); | 
|  | 317 |  | 
|  | 318 | /* disable interrupts from uCode/NIC to host */ | 
| Emmanuel Grumbach | 83ed901 | 2011-08-25 23:11:14 -0700 | [diff] [blame] | 319 | iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 320 |  | 
|  | 321 | /* acknowledge/clear/reset any interrupts still pending | 
|  | 322 | * from uCode or flow handler (Rx/Tx DMA) */ | 
| Emmanuel Grumbach | 83ed901 | 2011-08-25 23:11:14 -0700 | [diff] [blame] | 323 | iwl_write32(bus(trans), CSR_INT, 0xffffffff); | 
|  | 324 | iwl_write32(bus(trans), CSR_FH_INT_STATUS, 0xffffffff); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 325 | IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); | 
|  | 326 | } | 
|  | 327 |  | 
|  | 328 | static inline void iwl_enable_interrupts(struct iwl_trans *trans) | 
|  | 329 | { | 
|  | 330 | struct iwl_trans_pcie *trans_pcie = | 
|  | 331 | IWL_TRANS_GET_PCIE_TRANS(trans); | 
|  | 332 |  | 
|  | 333 | IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); | 
|  | 334 | set_bit(STATUS_INT_ENABLED, &trans->shrd->status); | 
| Emmanuel Grumbach | 83ed901 | 2011-08-25 23:11:14 -0700 | [diff] [blame] | 335 | iwl_write32(bus(trans), CSR_INT_MASK, trans_pcie->inta_mask); | 
| Emmanuel Grumbach | 0c32576 | 2011-08-25 23:10:53 -0700 | [diff] [blame] | 336 | } | 
|  | 337 |  | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 338 | /* | 
|  | 339 | * we have 8 bits used like this: | 
|  | 340 | * | 
|  | 341 | * 7 6 5 4 3 2 1 0 | 
|  | 342 | * | | | | | | | | | 
|  | 343 | * | | | | | | +-+-------- AC queue (0-3) | 
|  | 344 | * | | | | | | | 
|  | 345 | * | +-+-+-+-+------------ HW queue ID | 
|  | 346 | * | | 
|  | 347 | * +---------------------- unused | 
|  | 348 | */ | 
|  | 349 | static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) | 
|  | 350 | { | 
|  | 351 | BUG_ON(ac > 3);   /* only have 2 bits */ | 
|  | 352 | BUG_ON(hwq > 31); /* only use 5 bits */ | 
|  | 353 |  | 
|  | 354 | txq->swq_id = (hwq << 2) | ac; | 
|  | 355 | } | 
|  | 356 |  | 
|  | 357 | static inline void iwl_wake_queue(struct iwl_trans *trans, | 
|  | 358 | struct iwl_tx_queue *txq) | 
|  | 359 | { | 
|  | 360 | u8 queue = txq->swq_id; | 
|  | 361 | u8 ac = queue & 3; | 
|  | 362 | u8 hwq = (queue >> 2) & 0x1f; | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 363 | struct iwl_trans_pcie *trans_pcie = | 
|  | 364 | IWL_TRANS_GET_PCIE_TRANS(trans); | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 365 |  | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 366 | if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) | 
|  | 367 | if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) | 
| Emmanuel Grumbach | 859cfb0 | 2011-09-15 11:46:31 -0700 | [diff] [blame] | 368 | iwl_wake_sw_queue(priv(trans), ac); | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 369 | } | 
|  | 370 |  | 
|  | 371 | static inline void iwl_stop_queue(struct iwl_trans *trans, | 
|  | 372 | struct iwl_tx_queue *txq) | 
|  | 373 | { | 
|  | 374 | u8 queue = txq->swq_id; | 
|  | 375 | u8 ac = queue & 3; | 
|  | 376 | u8 hwq = (queue >> 2) & 0x1f; | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 377 | struct iwl_trans_pcie *trans_pcie = | 
|  | 378 | IWL_TRANS_GET_PCIE_TRANS(trans); | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 379 |  | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 380 | if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) | 
|  | 381 | if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) | 
| Emmanuel Grumbach | 859cfb0 | 2011-09-15 11:46:31 -0700 | [diff] [blame] | 382 | iwl_stop_sw_queue(priv(trans), ac); | 
| Emmanuel Grumbach | e20d4341 | 2011-08-25 23:11:31 -0700 | [diff] [blame] | 383 | } | 
|  | 384 |  | 
|  | 385 | #ifdef ieee80211_stop_queue | 
|  | 386 | #undef ieee80211_stop_queue | 
|  | 387 | #endif | 
|  | 388 |  | 
|  | 389 | #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue | 
|  | 390 |  | 
|  | 391 | #ifdef ieee80211_wake_queue | 
|  | 392 | #undef ieee80211_wake_queue | 
|  | 393 | #endif | 
|  | 394 |  | 
|  | 395 | #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue | 
|  | 396 |  | 
| Emmanuel Grumbach | 8ad71be | 2011-08-25 23:11:32 -0700 | [diff] [blame] | 397 | static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie, | 
|  | 398 | int txq_id) | 
|  | 399 | { | 
|  | 400 | set_bit(txq_id, &trans_pcie->txq_ctx_active_msk); | 
|  | 401 | } | 
|  | 402 |  | 
|  | 403 | static inline void iwl_txq_ctx_deactivate(struct iwl_trans_pcie *trans_pcie, | 
|  | 404 | int txq_id) | 
|  | 405 | { | 
|  | 406 | clear_bit(txq_id, &trans_pcie->txq_ctx_active_msk); | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 | static inline int iwl_queue_used(const struct iwl_queue *q, int i) | 
|  | 410 | { | 
|  | 411 | return q->write_ptr >= q->read_ptr ? | 
|  | 412 | (i >= q->read_ptr && i < q->write_ptr) : | 
|  | 413 | !(i < q->read_ptr && i >= q->write_ptr); | 
|  | 414 | } | 
|  | 415 |  | 
|  | 416 | static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) | 
|  | 417 | { | 
|  | 418 | return index & (q->n_window - 1); | 
|  | 419 | } | 
|  | 420 |  | 
| Emmanuel Grumbach | 7a10e3e | 2011-09-06 09:31:21 -0700 | [diff] [blame] | 421 | #define IWL_TX_FIFO_BK		0	/* shared */ | 
|  | 422 | #define IWL_TX_FIFO_BE		1 | 
|  | 423 | #define IWL_TX_FIFO_VI		2	/* shared */ | 
|  | 424 | #define IWL_TX_FIFO_VO		3 | 
|  | 425 | #define IWL_TX_FIFO_BK_IPAN	IWL_TX_FIFO_BK | 
|  | 426 | #define IWL_TX_FIFO_BE_IPAN	4 | 
|  | 427 | #define IWL_TX_FIFO_VI_IPAN	IWL_TX_FIFO_VI | 
|  | 428 | #define IWL_TX_FIFO_VO_IPAN	5 | 
|  | 429 | /* re-uses the VO FIFO, uCode will properly flush/schedule */ | 
|  | 430 | #define IWL_TX_FIFO_AUX		5 | 
|  | 431 | #define IWL_TX_FIFO_UNUSED	-1 | 
|  | 432 |  | 
|  | 433 | /* AUX (TX during scan dwell) queue */ | 
|  | 434 | #define IWL_AUX_QUEUE		10 | 
|  | 435 |  | 
| Emmanuel Grumbach | ab697a9 | 2011-07-11 07:35:34 -0700 | [diff] [blame] | 436 | #endif /* __iwl_trans_int_pcie_h__ */ |