| Emmanuel Grumbach | c85eb61 | 2011-06-14 10:13:24 +0300 | [diff] [blame] | 1 | /****************************************************************************** | 
|  | 2 | * | 
|  | 3 | * This file is provided under a dual BSD/GPLv2 license.  When using or | 
|  | 4 | * redistributing this file, you may do so under either license. | 
|  | 5 | * | 
|  | 6 | * GPL LICENSE SUMMARY | 
|  | 7 | * | 
| Wey-Yi Guy | 4e31826 | 2011-12-27 11:21:32 -0800 | [diff] [blame] | 8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | 
| Emmanuel Grumbach | c85eb61 | 2011-06-14 10:13:24 +0300 | [diff] [blame] | 9 | * | 
|  | 10 | * This program is free software; you can redistribute it and/or modify | 
|  | 11 | * it under the terms of version 2 of the GNU General Public License as | 
|  | 12 | * published by the Free Software Foundation. | 
|  | 13 | * | 
|  | 14 | * This program is distributed in the hope that it will be useful, but | 
|  | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 17 | * General Public License for more details. | 
|  | 18 | * | 
|  | 19 | * You should have received a copy of the GNU General Public License | 
|  | 20 | * along with this program; if not, write to the Free Software | 
|  | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 
|  | 22 | * USA | 
|  | 23 | * | 
|  | 24 | * The full GNU General Public License is included in this distribution | 
|  | 25 | * in the file called LICENSE.GPL. | 
|  | 26 | * | 
|  | 27 | * Contact Information: | 
|  | 28 | *  Intel Linux Wireless <ilw@linux.intel.com> | 
|  | 29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
|  | 30 | * | 
|  | 31 | * BSD LICENSE | 
|  | 32 | * | 
| Wey-Yi Guy | 4e31826 | 2011-12-27 11:21:32 -0800 | [diff] [blame] | 33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | 
| Emmanuel Grumbach | c85eb61 | 2011-06-14 10:13:24 +0300 | [diff] [blame] | 34 | * All rights reserved. | 
|  | 35 | * | 
|  | 36 | * Redistribution and use in source and binary forms, with or without | 
|  | 37 | * modification, are permitted provided that the following conditions | 
|  | 38 | * are met: | 
|  | 39 | * | 
|  | 40 | *  * Redistributions of source code must retain the above copyright | 
|  | 41 | *    notice, this list of conditions and the following disclaimer. | 
|  | 42 | *  * Redistributions in binary form must reproduce the above copyright | 
|  | 43 | *    notice, this list of conditions and the following disclaimer in | 
|  | 44 | *    the documentation and/or other materials provided with the | 
|  | 45 | *    distribution. | 
|  | 46 | *  * Neither the name Intel Corporation nor the names of its | 
|  | 47 | *    contributors may be used to endorse or promote products derived | 
|  | 48 | *    from this software without specific prior written permission. | 
|  | 49 | * | 
|  | 50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | 51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | 52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | 53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | 54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | 55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | 56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | 57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | 58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | 61 | * | 
|  | 62 | *****************************************************************************/ | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 63 | #ifndef __iwl_trans_h__ | 
|  | 64 | #define __iwl_trans_h__ | 
| Emmanuel Grumbach | 253a634 | 2011-07-11 07:39:46 -0700 | [diff] [blame] | 65 |  | 
| Emmanuel Grumbach | e679378 | 2012-02-16 09:47:01 +0200 | [diff] [blame] | 66 | #include <linux/ieee80211.h> | 
| Johannes Berg | 930dfd5 | 2012-03-05 11:24:43 -0800 | [diff] [blame] | 67 | #include <linux/mm.h> /* for page_address */ | 
| Emmanuel Grumbach | a72b8b0 | 2011-08-25 23:11:13 -0700 | [diff] [blame] | 68 |  | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 69 | #include "iwl-debug.h" | 
| Johannes Berg | 6238b00 | 2012-04-02 15:04:33 +0200 | [diff] [blame] | 70 | #include "iwl-config.h" | 
|  | 71 | #include "iwl-fw.h" | 
| Emmanuel Grumbach | 87e5666 | 2011-08-25 23:10:50 -0700 | [diff] [blame] | 72 |  | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 73 | /** | 
|  | 74 | * DOC: Transport layer - what is it ? | 
|  | 75 | * | 
|  | 76 | * The tranport layer is the layer that deals with the HW directly. It provides | 
|  | 77 | * an abstraction of the underlying HW to the upper layer. The transport layer | 
|  | 78 | * doesn't provide any policy, algorithm or anything of this kind, but only | 
|  | 79 | * mechanisms to make the HW do something.It is not completely stateless but | 
|  | 80 | * close to it. | 
|  | 81 | * We will have an implementation for each different supported bus. | 
|  | 82 | */ | 
|  | 83 |  | 
|  | 84 | /** | 
|  | 85 | * DOC: Life cycle of the transport layer | 
|  | 86 | * | 
|  | 87 | * The transport layer has a very precise life cycle. | 
|  | 88 | * | 
|  | 89 | *	1) A helper function is called during the module initialization and | 
|  | 90 | *	   registers the bus driver's ops with the transport's alloc function. | 
|  | 91 | *	2) Bus's probe calls to the transport layer's allocation functions. | 
|  | 92 | *	   Of course this function is bus specific. | 
|  | 93 | *	3) This allocation functions will spawn the upper layer which will | 
|  | 94 | *	   register mac80211. | 
|  | 95 | * | 
|  | 96 | *	4) At some point (i.e. mac80211's start call), the op_mode will call | 
|  | 97 | *	   the following sequence: | 
|  | 98 | *	   start_hw | 
|  | 99 | *	   start_fw | 
|  | 100 | * | 
|  | 101 | *	5) Then when finished (or reset): | 
|  | 102 | *	   stop_fw (a.k.a. stop device for the moment) | 
|  | 103 | *	   stop_hw | 
|  | 104 | * | 
|  | 105 | *	6) Eventually, the free function will be called. | 
|  | 106 | */ | 
|  | 107 |  | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 108 | /** | 
|  | 109 | * DOC: Host command section | 
|  | 110 | * | 
|  | 111 | * A host command is a commaned issued by the upper layer to the fw. There are | 
|  | 112 | * several versions of fw that have several APIs. The transport layer is | 
|  | 113 | * completely agnostic to these differences. | 
|  | 114 | * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), | 
|  | 115 | */ | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 116 | #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) | 
|  | 117 | #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) | 
|  | 118 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) | 
| Johannes Berg | f8d7c1a | 2012-03-06 13:31:02 -0800 | [diff] [blame] | 119 | #define SEQ_TO_QUEUE(s)	(((s) >> 8) & 0x1f) | 
|  | 120 | #define QUEUE_TO_SEQ(q)	(((q) & 0x1f) << 8) | 
|  | 121 | #define SEQ_TO_INDEX(s)	((s) & 0xff) | 
|  | 122 | #define INDEX_TO_SEQ(i)	((i) & 0xff) | 
|  | 123 | #define SEQ_RX_FRAME	cpu_to_le16(0x8000) | 
|  | 124 |  | 
|  | 125 | /** | 
|  | 126 | * struct iwl_cmd_header | 
|  | 127 | * | 
|  | 128 | * This header format appears in the beginning of each command sent from the | 
|  | 129 | * driver, and each response/notification received from uCode. | 
|  | 130 | */ | 
|  | 131 | struct iwl_cmd_header { | 
|  | 132 | u8 cmd;		/* Command ID:  REPLY_RXON, etc. */ | 
|  | 133 | u8 flags;	/* 0:5 reserved, 6 abort, 7 internal */ | 
|  | 134 | /* | 
|  | 135 | * The driver sets up the sequence number to values of its choosing. | 
|  | 136 | * uCode does not use this value, but passes it back to the driver | 
|  | 137 | * when sending the response to each driver-originated command, so | 
|  | 138 | * the driver can match the response to the command.  Since the values | 
|  | 139 | * don't get used by uCode, the driver may set up an arbitrary format. | 
|  | 140 | * | 
|  | 141 | * There is one exception:  uCode sets bit 15 when it originates | 
|  | 142 | * the response/notification, i.e. when the response/notification | 
|  | 143 | * is not a direct response to a command sent by the driver.  For | 
|  | 144 | * example, uCode issues REPLY_RX when it sends a received frame | 
|  | 145 | * to the driver; it is not a direct response to any driver command. | 
|  | 146 | * | 
|  | 147 | * The Linux driver uses the following format: | 
|  | 148 | * | 
|  | 149 | *  0:7		tfd index - position within TX queue | 
|  | 150 | *  8:12	TX queue id | 
|  | 151 | *  13:14	reserved | 
|  | 152 | *  15		unsolicited RX or uCode-originated notification | 
|  | 153 | */ | 
|  | 154 | __le16 sequence; | 
|  | 155 | } __packed; | 
|  | 156 |  | 
| Johannes Berg | c08ce20 | 2012-05-16 22:54:26 +0200 | [diff] [blame] | 157 | /* iwl_cmd_header flags value */ | 
|  | 158 | #define IWL_CMD_FAILED_MSK 0x40 | 
|  | 159 |  | 
| Johannes Berg | f8d7c1a | 2012-03-06 13:31:02 -0800 | [diff] [blame] | 160 |  | 
|  | 161 | #define FH_RSCSR_FRAME_SIZE_MSK		0x00003FFF	/* bits 0-13 */ | 
| Johannes Berg | 0c19744 | 2012-03-15 13:26:43 -0700 | [diff] [blame] | 162 | #define FH_RSCSR_FRAME_INVALID		0x55550000 | 
|  | 163 | #define FH_RSCSR_FRAME_ALIGN		0x40 | 
| Johannes Berg | f8d7c1a | 2012-03-06 13:31:02 -0800 | [diff] [blame] | 164 |  | 
|  | 165 | struct iwl_rx_packet { | 
|  | 166 | /* | 
|  | 167 | * The first 4 bytes of the RX frame header contain both the RX frame | 
|  | 168 | * size and some flags. | 
|  | 169 | * Bit fields: | 
|  | 170 | * 31:    flag flush RB request | 
|  | 171 | * 30:    flag ignore TC (terminal counter) request | 
|  | 172 | * 29:    flag fast IRQ request | 
|  | 173 | * 28-14: Reserved | 
|  | 174 | * 13-00: RX frame size | 
|  | 175 | */ | 
|  | 176 | __le32 len_n_flags; | 
|  | 177 | struct iwl_cmd_header hdr; | 
|  | 178 | u8 data[]; | 
|  | 179 | } __packed; | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 180 |  | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 181 | /** | 
|  | 182 | * enum CMD_MODE - how to send the host commands ? | 
|  | 183 | * | 
|  | 184 | * @CMD_SYNC: The caller will be stalled until the fw responds to the command | 
|  | 185 | * @CMD_ASYNC: Return right away and don't want for the response | 
|  | 186 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the | 
| Emmanuel Grumbach | 9679142 | 2012-07-24 01:58:32 +0300 | [diff] [blame] | 187 | *	response. The caller needs to call iwl_free_resp when done. | 
|  | 188 | * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the | 
|  | 189 | *	response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be | 
|  | 190 | *	copied. The pointer passed to the response handler is in the transport | 
|  | 191 | *	ownership and don't need to be freed by the op_mode. This also means | 
|  | 192 | *	that the pointer is invalidated after the op_mode's handler returns. | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 193 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. | 
|  | 194 | */ | 
|  | 195 | enum CMD_MODE { | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 196 | CMD_SYNC = 0, | 
|  | 197 | CMD_ASYNC = BIT(0), | 
|  | 198 | CMD_WANT_SKB = BIT(1), | 
| Emmanuel Grumbach | 9679142 | 2012-07-24 01:58:32 +0300 | [diff] [blame] | 199 | CMD_WANT_HCMD = BIT(2), | 
|  | 200 | CMD_ON_DEMAND = BIT(3), | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 201 | }; | 
|  | 202 |  | 
|  | 203 | #define DEF_CMD_PAYLOAD_SIZE 320 | 
|  | 204 |  | 
|  | 205 | /** | 
|  | 206 | * struct iwl_device_cmd | 
|  | 207 | * | 
|  | 208 | * For allocation of the command and tx queues, this establishes the overall | 
|  | 209 | * size of the largest command we send to uCode, except for commands that | 
|  | 210 | * aren't fully copied and use other TFD space. | 
|  | 211 | */ | 
|  | 212 | struct iwl_device_cmd { | 
|  | 213 | struct iwl_cmd_header hdr;	/* uCode API */ | 
| Emmanuel Grumbach | 132f98c | 2011-09-20 15:37:24 -0700 | [diff] [blame] | 214 | u8 payload[DEF_CMD_PAYLOAD_SIZE]; | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 215 | } __packed; | 
|  | 216 |  | 
|  | 217 | #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) | 
|  | 218 |  | 
|  | 219 | #define IWL_MAX_CMD_TFDS	2 | 
|  | 220 |  | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 221 | /** | 
|  | 222 | * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command | 
|  | 223 | * | 
|  | 224 | * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's | 
|  | 225 | *	ring. The transport layer doesn't map the command's buffer to DMA, but | 
|  | 226 | *	rather copies it to an previously allocated DMA buffer. This flag tells | 
|  | 227 | *	the transport layer not to copy the command, but to map the existing | 
|  | 228 | *	buffer. This can save memcpy and is worth with very big comamnds. | 
|  | 229 | */ | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 230 | enum iwl_hcmd_dataflag { | 
|  | 231 | IWL_HCMD_DFL_NOCOPY	= BIT(0), | 
|  | 232 | }; | 
|  | 233 |  | 
|  | 234 | /** | 
|  | 235 | * struct iwl_host_cmd - Host command to the uCode | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 236 | * | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 237 | * @data: array of chunks that composes the data of the host command | 
| Johannes Berg | 65b94a4 | 2012-03-05 11:24:38 -0800 | [diff] [blame] | 238 | * @resp_pkt: response packet, if %CMD_WANT_SKB was set | 
|  | 239 | * @_rx_page_order: (internally used to free response packet) | 
|  | 240 | * @_rx_page_addr: (internally used to free response packet) | 
| Emmanuel Grumbach | 247c61d | 2011-09-20 15:37:23 -0700 | [diff] [blame] | 241 | * @handler_status: return value of the handler of the command | 
|  | 242 | *	(put in setup_rx_handlers) - valid for SYNC mode only | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 243 | * @flags: can be CMD_* | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 244 | * @len: array of the lenths of the chunks in data | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 245 | * @dataflags: IWL_HCMD_DFL_* | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 246 | * @id: id of the host command | 
|  | 247 | */ | 
|  | 248 | struct iwl_host_cmd { | 
|  | 249 | const void *data[IWL_MAX_CMD_TFDS]; | 
| Johannes Berg | 65b94a4 | 2012-03-05 11:24:38 -0800 | [diff] [blame] | 250 | struct iwl_rx_packet *resp_pkt; | 
|  | 251 | unsigned long _rx_page_addr; | 
|  | 252 | u32 _rx_page_order; | 
| Emmanuel Grumbach | 247c61d | 2011-09-20 15:37:23 -0700 | [diff] [blame] | 253 | int handler_status; | 
|  | 254 |  | 
| Emmanuel Grumbach | 522376d | 2011-09-06 09:31:19 -0700 | [diff] [blame] | 255 | u32 flags; | 
|  | 256 | u16 len[IWL_MAX_CMD_TFDS]; | 
|  | 257 | u8 dataflags[IWL_MAX_CMD_TFDS]; | 
|  | 258 | u8 id; | 
|  | 259 | }; | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 260 |  | 
| Johannes Berg | 65b94a4 | 2012-03-05 11:24:38 -0800 | [diff] [blame] | 261 | static inline void iwl_free_resp(struct iwl_host_cmd *cmd) | 
|  | 262 | { | 
|  | 263 | free_pages(cmd->_rx_page_addr, cmd->_rx_page_order); | 
|  | 264 | } | 
|  | 265 |  | 
| Johannes Berg | 930dfd5 | 2012-03-05 11:24:43 -0800 | [diff] [blame] | 266 | struct iwl_rx_cmd_buffer { | 
|  | 267 | struct page *_page; | 
| Johannes Berg | 0c19744 | 2012-03-15 13:26:43 -0700 | [diff] [blame] | 268 | int _offset; | 
|  | 269 | bool _page_stolen; | 
| Eric Dumazet | ed90542 | 2012-03-24 00:29:46 -0400 | [diff] [blame] | 270 | unsigned int truesize; | 
| Johannes Berg | 930dfd5 | 2012-03-05 11:24:43 -0800 | [diff] [blame] | 271 | }; | 
|  | 272 |  | 
|  | 273 | static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r) | 
|  | 274 | { | 
| Johannes Berg | 0c19744 | 2012-03-15 13:26:43 -0700 | [diff] [blame] | 275 | return (void *)((unsigned long)page_address(r->_page) + r->_offset); | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | static inline int rxb_offset(struct iwl_rx_cmd_buffer *r) | 
|  | 279 | { | 
|  | 280 | return r->_offset; | 
| Johannes Berg | 930dfd5 | 2012-03-05 11:24:43 -0800 | [diff] [blame] | 281 | } | 
|  | 282 |  | 
|  | 283 | static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) | 
|  | 284 | { | 
| Johannes Berg | 0c19744 | 2012-03-15 13:26:43 -0700 | [diff] [blame] | 285 | r->_page_stolen = true; | 
|  | 286 | get_page(r->_page); | 
|  | 287 | return r->_page; | 
| Johannes Berg | 930dfd5 | 2012-03-05 11:24:43 -0800 | [diff] [blame] | 288 | } | 
|  | 289 |  | 
| Johannes Berg | d663ee7 | 2012-03-10 13:00:07 -0800 | [diff] [blame] | 290 | #define MAX_NO_RECLAIM_CMDS	6 | 
|  | 291 |  | 
| Gregory Greenman | ff110c8 | 2012-05-16 22:54:24 +0200 | [diff] [blame] | 292 | #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) | 
|  | 293 |  | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 294 | /* | 
|  | 295 | * Maximum number of HW queues the transport layer | 
|  | 296 | * currently supports | 
|  | 297 | */ | 
|  | 298 | #define IWL_MAX_HW_QUEUES		32 | 
| Emmanuel Grumbach | b04db9a | 2012-06-21 11:53:44 +0300 | [diff] [blame] | 299 | #define IWL_INVALID_STATION	255 | 
|  | 300 | #define IWL_MAX_TID_COUNT	8 | 
|  | 301 | #define IWL_FRAME_LIMIT	64 | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 302 |  | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 303 | /** | 
| Meenakshi Venkataraman | 92d743a | 2012-03-07 09:52:35 -0800 | [diff] [blame] | 304 | * struct iwl_trans_config - transport configuration | 
|  | 305 | * | 
|  | 306 | * @op_mode: pointer to the upper layer. | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 307 | * @cmd_queue: the index of the command queue. | 
|  | 308 | *	Must be set before start_fw. | 
| Emmanuel Grumbach | b04db9a | 2012-06-21 11:53:44 +0300 | [diff] [blame] | 309 | * @cmd_fifo: the fifo for host commands | 
| Johannes Berg | d663ee7 | 2012-03-10 13:00:07 -0800 | [diff] [blame] | 310 | * @no_reclaim_cmds: Some devices erroneously don't set the | 
|  | 311 | *	SEQ_RX_FRAME bit on some notifications, this is the | 
|  | 312 | *	list of such notifications to filter. Max length is | 
|  | 313 | *	%MAX_NO_RECLAIM_CMDS. | 
|  | 314 | * @n_no_reclaim_cmds: # of commands in list | 
| Johannes Berg | b2cf410 | 2012-04-09 17:46:51 -0700 | [diff] [blame] | 315 | * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs, | 
|  | 316 | *	if unset 4k will be the RX buffer size | 
| Johannes Berg | 7c5ba4a | 2012-04-09 17:46:54 -0700 | [diff] [blame] | 317 | * @queue_watchdog_timeout: time (in ms) after which queues | 
|  | 318 | *	are considered stuck and will trigger device restart | 
| Johannes Berg | d9fb646 | 2012-03-26 08:23:39 -0700 | [diff] [blame] | 319 | * @command_names: array of command names, must be 256 entries | 
|  | 320 | *	(one for each command); for debugging only | 
| Meenakshi Venkataraman | 92d743a | 2012-03-07 09:52:35 -0800 | [diff] [blame] | 321 | */ | 
|  | 322 | struct iwl_trans_config { | 
|  | 323 | struct iwl_op_mode *op_mode; | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 324 |  | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 325 | u8 cmd_queue; | 
| Emmanuel Grumbach | b04db9a | 2012-06-21 11:53:44 +0300 | [diff] [blame] | 326 | u8 cmd_fifo; | 
| Johannes Berg | d663ee7 | 2012-03-10 13:00:07 -0800 | [diff] [blame] | 327 | const u8 *no_reclaim_cmds; | 
|  | 328 | int n_no_reclaim_cmds; | 
| Johannes Berg | b2cf410 | 2012-04-09 17:46:51 -0700 | [diff] [blame] | 329 |  | 
|  | 330 | bool rx_buf_size_8k; | 
| Johannes Berg | 7c5ba4a | 2012-04-09 17:46:54 -0700 | [diff] [blame] | 331 | unsigned int queue_watchdog_timeout; | 
| Johannes Berg | d9fb646 | 2012-03-26 08:23:39 -0700 | [diff] [blame] | 332 | const char **command_names; | 
| Meenakshi Venkataraman | 92d743a | 2012-03-07 09:52:35 -0800 | [diff] [blame] | 333 | }; | 
|  | 334 |  | 
| Emmanuel Grumbach | 87ce05a | 2012-03-26 09:03:18 -0700 | [diff] [blame] | 335 | struct iwl_trans; | 
|  | 336 |  | 
| Meenakshi Venkataraman | 92d743a | 2012-03-07 09:52:35 -0800 | [diff] [blame] | 337 | /** | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 338 | * struct iwl_trans_ops - transport specific operations | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 339 | * | 
|  | 340 | * All the handlers MUST be implemented | 
|  | 341 | * | 
| Emmanuel Grumbach | 57a1dc8 | 2012-01-08 13:22:16 +0200 | [diff] [blame] | 342 | * @start_hw: starts the HW- from that point on, the HW can send interrupts | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 343 | *	May sleep | 
| Emmanuel Grumbach | cc56feb | 2012-01-08 13:37:59 +0200 | [diff] [blame] | 344 | * @stop_hw: stops the HW- from that point on, the HW will be in low power but | 
| Emmanuel Grumbach | 218733c | 2012-03-31 08:28:38 -0700 | [diff] [blame] | 345 | *	will still issue interrupt if the HW RF kill is triggered unless | 
|  | 346 | *	op_mode_leaving is true. | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 347 | *	May sleep | 
| Emmanuel Grumbach | cf61429 | 2012-01-08 16:33:58 +0200 | [diff] [blame] | 348 | * @start_fw: allocates and inits all the resources for the transport | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 349 | *	layer. Also kick a fw image. | 
|  | 350 | *	May sleep | 
| Emmanuel Grumbach | ed6a380 | 2012-01-02 16:10:08 +0200 | [diff] [blame] | 351 | * @fw_alive: called when the fw sends alive notification | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 352 | *	May sleep | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 353 | * @stop_device:stops the whole device (embedded CPU put to reset) | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 354 | *	May sleep | 
| Johannes Berg | 2dd4f9f | 2012-03-05 11:24:35 -0800 | [diff] [blame] | 355 | * @wowlan_suspend: put the device into the correct mode for WoWLAN during | 
|  | 356 | *	suspend. This is optional, if not implemented WoWLAN will not be | 
|  | 357 | *	supported. This callback may sleep. | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 358 | * @send_cmd:send a host command | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 359 | *	May sleep only if CMD_SYNC is set | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 360 | * @tx: send an skb | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 361 | *	Must be atomic | 
| Emmanuel Grumbach | a0eaad7 | 2011-08-25 23:11:00 -0700 | [diff] [blame] | 362 | * @reclaim: free packet until ssn. Returns a list of freed packets. | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 363 | *	Must be atomic | 
| Emmanuel Grumbach | b04db9a | 2012-06-21 11:53:44 +0300 | [diff] [blame] | 364 | * @txq_enable: setup a queue. To setup an AC queue, use the | 
|  | 365 | *	iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before | 
|  | 366 | *	this one. The op_mode must not configure the HCMD queue. May sleep. | 
| Emmanuel Grumbach | d0624be | 2012-05-29 13:07:30 +0300 | [diff] [blame] | 367 | * @txq_disable: de-configure a Tx queue to send AMPDUs | 
| Johannes Berg | b0b4619 | 2012-03-07 09:52:17 -0800 | [diff] [blame] | 368 | *	Must be atomic | 
| Emmanuel Grumbach | 5f178cd | 2011-08-25 23:11:29 -0700 | [diff] [blame] | 369 | * @wait_tx_queue_empty: wait until all tx queues are empty | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 370 | *	May sleep | 
| Emmanuel Grumbach | 87e5666 | 2011-08-25 23:10:50 -0700 | [diff] [blame] | 371 | * @dbgfs_register: add the dbgfs files under this directory. Files will be | 
|  | 372 | *	automatically deleted. | 
| Emmanuel Grumbach | 57210f7 | 2011-08-25 23:10:52 -0700 | [diff] [blame] | 373 | * @suspend: stop the device unless WoWLAN is configured | 
|  | 374 | * @resume: resume activity of the device | 
| Emmanuel Grumbach | 0390549 | 2012-01-03 13:48:07 +0200 | [diff] [blame] | 375 | * @write8: write a u8 to a register at offset ofs from the BAR | 
|  | 376 | * @write32: write a u32 to a register at offset ofs from the BAR | 
|  | 377 | * @read32: read a u32 register at offset ofs from the BAR | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 378 | * @configure: configure parameters required by the transport layer from | 
| Emmanuel Grumbach | 3dc420b | 2012-03-07 09:52:41 -0800 | [diff] [blame] | 379 | *	the op_mode. May be called several times before start_fw, can't be | 
|  | 380 | *	called after that. | 
| Don Fry | 47107e8 | 2012-03-15 13:27:06 -0700 | [diff] [blame] | 381 | * @set_pmi: set the power pmi state | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 382 | */ | 
|  | 383 | struct iwl_trans_ops { | 
|  | 384 |  | 
| Emmanuel Grumbach | 57a1dc8 | 2012-01-08 13:22:16 +0200 | [diff] [blame] | 385 | int (*start_hw)(struct iwl_trans *iwl_trans); | 
| Emmanuel Grumbach | 218733c | 2012-03-31 08:28:38 -0700 | [diff] [blame] | 386 | void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); | 
| Johannes Berg | 0692fe4 | 2012-03-06 13:30:37 -0800 | [diff] [blame] | 387 | int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); | 
| Emmanuel Grumbach | ed6a380 | 2012-01-02 16:10:08 +0200 | [diff] [blame] | 388 | void (*fw_alive)(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 389 | void (*stop_device)(struct iwl_trans *trans); | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 390 |  | 
| Johannes Berg | 2dd4f9f | 2012-03-05 11:24:35 -0800 | [diff] [blame] | 391 | void (*wowlan_suspend)(struct iwl_trans *trans); | 
|  | 392 |  | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 393 | int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 394 |  | 
| Emmanuel Grumbach | e13c0c5 | 2011-08-25 23:11:24 -0700 | [diff] [blame] | 395 | int (*tx)(struct iwl_trans *trans, struct sk_buff *skb, | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 396 | struct iwl_device_cmd *dev_cmd, int queue); | 
|  | 397 | void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, | 
|  | 398 | struct sk_buff_head *skbs); | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 399 |  | 
| Emmanuel Grumbach | 4beaf6c | 2012-05-29 11:29:10 +0300 | [diff] [blame] | 400 | void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo, | 
|  | 401 | int sta_id, int tid, int frame_limit, u16 ssn); | 
| Emmanuel Grumbach | d0624be | 2012-05-29 13:07:30 +0300 | [diff] [blame] | 402 | void (*txq_disable)(struct iwl_trans *trans, int queue); | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 403 |  | 
| Emmanuel Grumbach | 87e5666 | 2011-08-25 23:10:50 -0700 | [diff] [blame] | 404 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); | 
| Emmanuel Grumbach | 5f178cd | 2011-08-25 23:11:29 -0700 | [diff] [blame] | 405 | int (*wait_tx_queue_empty)(struct iwl_trans *trans); | 
| Johannes Berg | c01a404 | 2011-09-15 11:46:45 -0700 | [diff] [blame] | 406 | #ifdef CONFIG_PM_SLEEP | 
| Emmanuel Grumbach | 57210f7 | 2011-08-25 23:10:52 -0700 | [diff] [blame] | 407 | int (*suspend)(struct iwl_trans *trans); | 
|  | 408 | int (*resume)(struct iwl_trans *trans); | 
| Johannes Berg | c01a404 | 2011-09-15 11:46:45 -0700 | [diff] [blame] | 409 | #endif | 
| Emmanuel Grumbach | 0390549 | 2012-01-03 13:48:07 +0200 | [diff] [blame] | 410 | void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); | 
|  | 411 | void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); | 
|  | 412 | u32 (*read32)(struct iwl_trans *trans, u32 ofs); | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 413 | void (*configure)(struct iwl_trans *trans, | 
|  | 414 | const struct iwl_trans_config *trans_cfg); | 
| Don Fry | 47107e8 | 2012-03-15 13:27:06 -0700 | [diff] [blame] | 415 | void (*set_pmi)(struct iwl_trans *trans, bool state); | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 416 | }; | 
|  | 417 |  | 
| Emmanuel Grumbach | 6fbfae8 | 2011-08-25 23:10:49 -0700 | [diff] [blame] | 418 | /** | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 419 | * enum iwl_trans_state - state of the transport layer | 
|  | 420 | * | 
|  | 421 | * @IWL_TRANS_NO_FW: no fw has sent an alive response | 
|  | 422 | * @IWL_TRANS_FW_ALIVE: a fw has sent an alive response | 
|  | 423 | */ | 
|  | 424 | enum iwl_trans_state { | 
|  | 425 | IWL_TRANS_NO_FW = 0, | 
|  | 426 | IWL_TRANS_FW_ALIVE	= 1, | 
|  | 427 | }; | 
|  | 428 |  | 
|  | 429 | /** | 
| Emmanuel Grumbach | 6fbfae8 | 2011-08-25 23:10:49 -0700 | [diff] [blame] | 430 | * struct iwl_trans - transport common data | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 431 | * | 
| Emmanuel Grumbach | 6fbfae8 | 2011-08-25 23:10:49 -0700 | [diff] [blame] | 432 | * @ops - pointer to iwl_trans_ops | 
| Emmanuel Grumbach | ed277c9 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 433 | * @op_mode - pointer to the op_mode | 
| Emmanuel Grumbach | 035f7ff | 2012-03-26 08:57:01 -0700 | [diff] [blame] | 434 | * @cfg - pointer to the configuration | 
| Emmanuel Grumbach | 1042db2 | 2012-01-03 16:56:15 +0200 | [diff] [blame] | 435 | * @reg_lock - protect hw register access | 
| Emmanuel Grumbach | a42a184 | 2012-02-02 14:33:08 -0800 | [diff] [blame] | 436 | * @dev - pointer to struct device * that represents the device | 
| Emmanuel Grumbach | 99673ee | 2012-01-08 21:19:45 +0200 | [diff] [blame] | 437 | * @hw_id: a u32 with the ID of the device / subdevice. | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 438 | *	Set during transport allocation. | 
| Emmanuel Grumbach | 9ca8596 | 2012-01-08 21:19:45 +0200 | [diff] [blame] | 439 | * @hw_id_str: a string with info about HW ID. Set during transport allocation. | 
| Emmanuel Grumbach | f6d0e9b | 2012-01-08 21:19:45 +0200 | [diff] [blame] | 440 | * @pm_support: set to true in start_hw if link pm is supported | 
| Meenakshi Venkataraman | 69a10b2 | 2012-03-10 13:00:09 -0800 | [diff] [blame] | 441 | * @wait_command_queue: the wait_queue for SYNC host commands | 
| Emmanuel Grumbach | 59c647b | 2012-05-24 19:24:34 +0300 | [diff] [blame] | 442 | * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. | 
|  | 443 | *	The user should use iwl_trans_{alloc,free}_tx_cmd. | 
|  | 444 | * @dev_cmd_headroom: room needed for the transport's private use before the | 
|  | 445 | *	device_cmd for Tx - for internal use only | 
|  | 446 | *	The user should use iwl_trans_{alloc,free}_tx_cmd. | 
| Emmanuel Grumbach | 6fbfae8 | 2011-08-25 23:10:49 -0700 | [diff] [blame] | 447 | */ | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 448 | struct iwl_trans { | 
|  | 449 | const struct iwl_trans_ops *ops; | 
| Emmanuel Grumbach | ed277c9 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 450 | struct iwl_op_mode *op_mode; | 
| Emmanuel Grumbach | 035f7ff | 2012-03-26 08:57:01 -0700 | [diff] [blame] | 451 | const struct iwl_cfg *cfg; | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 452 | enum iwl_trans_state state; | 
| Emmanuel Grumbach | 1042db2 | 2012-01-03 16:56:15 +0200 | [diff] [blame] | 453 | spinlock_t reg_lock; | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 454 |  | 
| Emmanuel Grumbach | a42a184 | 2012-02-02 14:33:08 -0800 | [diff] [blame] | 455 | struct device *dev; | 
| Emmanuel Grumbach | 08079a4 | 2012-01-09 16:23:00 +0200 | [diff] [blame] | 456 | u32 hw_rev; | 
| Emmanuel Grumbach | 99673ee | 2012-01-08 21:19:45 +0200 | [diff] [blame] | 457 | u32 hw_id; | 
| Emmanuel Grumbach | 9ca8596 | 2012-01-08 21:19:45 +0200 | [diff] [blame] | 458 | char hw_id_str[52]; | 
| Emmanuel Grumbach | a42a184 | 2012-02-02 14:33:08 -0800 | [diff] [blame] | 459 |  | 
| Emmanuel Grumbach | f6d0e9b | 2012-01-08 21:19:45 +0200 | [diff] [blame] | 460 | bool pm_support; | 
| Don Fry | 97b52cf | 2011-11-10 06:55:27 -0800 | [diff] [blame] | 461 |  | 
| Meenakshi Venkataraman | 69a10b2 | 2012-03-10 13:00:09 -0800 | [diff] [blame] | 462 | wait_queue_head_t wait_command_queue; | 
|  | 463 |  | 
| Emmanuel Grumbach | 59c647b | 2012-05-24 19:24:34 +0300 | [diff] [blame] | 464 | /* The following fields are internal only */ | 
|  | 465 | struct kmem_cache *dev_cmd_pool; | 
|  | 466 | size_t dev_cmd_headroom; | 
| Johannes Berg | 3ec4588 | 2012-07-12 13:56:28 +0200 | [diff] [blame] | 467 | char dev_cmd_pool_name[50]; | 
| Emmanuel Grumbach | 59c647b | 2012-05-24 19:24:34 +0300 | [diff] [blame] | 468 |  | 
| Meenakshi Venkataraman | 9da987a | 2012-07-16 18:43:56 -0700 | [diff] [blame] | 469 | struct dentry *dbgfs_dir; | 
|  | 470 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 471 | /* pointer to trans specific struct */ | 
|  | 472 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 
| Emmanuel Grumbach | cbe6ab4 | 2012-02-15 09:25:06 +0200 | [diff] [blame] | 473 | char trans_specific[0] __aligned(sizeof(void *)); | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 474 | }; | 
|  | 475 |  | 
| Emmanuel Grumbach | ed277c9 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 476 | static inline void iwl_trans_configure(struct iwl_trans *trans, | 
| Meenakshi Venkataraman | 92d743a | 2012-03-07 09:52:35 -0800 | [diff] [blame] | 477 | const struct iwl_trans_config *trans_cfg) | 
| Emmanuel Grumbach | ed277c9 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 478 | { | 
|  | 479 | /* | 
|  | 480 | * only set the op_mode for the moment. Later on, this function will do | 
|  | 481 | * more | 
|  | 482 | */ | 
| Meenakshi Venkataraman | 92d743a | 2012-03-07 09:52:35 -0800 | [diff] [blame] | 483 | trans->op_mode = trans_cfg->op_mode; | 
| Meenakshi Venkataraman | c6f600f | 2012-03-08 11:29:12 -0800 | [diff] [blame] | 484 |  | 
|  | 485 | trans->ops->configure(trans, trans_cfg); | 
| Emmanuel Grumbach | ed277c9 | 2012-02-09 16:08:15 +0200 | [diff] [blame] | 486 | } | 
|  | 487 |  | 
| Emmanuel Grumbach | 57a1dc8 | 2012-01-08 13:22:16 +0200 | [diff] [blame] | 488 | static inline int iwl_trans_start_hw(struct iwl_trans *trans) | 
| Emmanuel Grumbach | bdfbf09 | 2011-07-08 08:46:16 -0700 | [diff] [blame] | 489 | { | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 490 | might_sleep(); | 
|  | 491 |  | 
| Emmanuel Grumbach | 57a1dc8 | 2012-01-08 13:22:16 +0200 | [diff] [blame] | 492 | return trans->ops->start_hw(trans); | 
| Emmanuel Grumbach | bdfbf09 | 2011-07-08 08:46:16 -0700 | [diff] [blame] | 493 | } | 
|  | 494 |  | 
| Emmanuel Grumbach | 218733c | 2012-03-31 08:28:38 -0700 | [diff] [blame] | 495 | static inline void iwl_trans_stop_hw(struct iwl_trans *trans, | 
|  | 496 | bool op_mode_leaving) | 
| Emmanuel Grumbach | cc56feb | 2012-01-08 13:37:59 +0200 | [diff] [blame] | 497 | { | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 498 | might_sleep(); | 
|  | 499 |  | 
| Emmanuel Grumbach | 218733c | 2012-03-31 08:28:38 -0700 | [diff] [blame] | 500 | trans->ops->stop_hw(trans, op_mode_leaving); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 501 |  | 
|  | 502 | trans->state = IWL_TRANS_NO_FW; | 
| Emmanuel Grumbach | cc56feb | 2012-01-08 13:37:59 +0200 | [diff] [blame] | 503 | } | 
|  | 504 |  | 
| Emmanuel Grumbach | ed6a380 | 2012-01-02 16:10:08 +0200 | [diff] [blame] | 505 | static inline void iwl_trans_fw_alive(struct iwl_trans *trans) | 
|  | 506 | { | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 507 | might_sleep(); | 
|  | 508 |  | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 509 | trans->state = IWL_TRANS_FW_ALIVE; | 
| Emmanuel Grumbach | b04db9a | 2012-06-21 11:53:44 +0300 | [diff] [blame] | 510 |  | 
|  | 511 | trans->ops->fw_alive(trans); | 
| Emmanuel Grumbach | ed6a380 | 2012-01-02 16:10:08 +0200 | [diff] [blame] | 512 | } | 
|  | 513 |  | 
| Johannes Berg | 0692fe4 | 2012-03-06 13:30:37 -0800 | [diff] [blame] | 514 | static inline int iwl_trans_start_fw(struct iwl_trans *trans, | 
|  | 515 | const struct fw_img *fw) | 
| Emmanuel Grumbach | 0286cee | 2011-07-10 15:39:57 +0300 | [diff] [blame] | 516 | { | 
| Emmanuel Grumbach | cf61429 | 2012-01-08 16:33:58 +0200 | [diff] [blame] | 517 | might_sleep(); | 
|  | 518 |  | 
|  | 519 | return trans->ops->start_fw(trans, fw); | 
| Emmanuel Grumbach | 0286cee | 2011-07-10 15:39:57 +0300 | [diff] [blame] | 520 | } | 
|  | 521 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 522 | static inline void iwl_trans_stop_device(struct iwl_trans *trans) | 
| Emmanuel Grumbach | b3c2ce1 | 2011-07-07 15:50:10 +0300 | [diff] [blame] | 523 | { | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 524 | might_sleep(); | 
|  | 525 |  | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 526 | trans->ops->stop_device(trans); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 527 |  | 
|  | 528 | trans->state = IWL_TRANS_NO_FW; | 
| Emmanuel Grumbach | b3c2ce1 | 2011-07-07 15:50:10 +0300 | [diff] [blame] | 529 | } | 
|  | 530 |  | 
| Johannes Berg | 2dd4f9f | 2012-03-05 11:24:35 -0800 | [diff] [blame] | 531 | static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans) | 
|  | 532 | { | 
|  | 533 | might_sleep(); | 
|  | 534 | trans->ops->wowlan_suspend(trans); | 
|  | 535 | } | 
|  | 536 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 537 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 
| Emmanuel Grumbach | bdfbf09 | 2011-07-08 08:46:16 -0700 | [diff] [blame] | 538 | struct iwl_host_cmd *cmd) | 
|  | 539 | { | 
| Johannes Berg | f0d120a | 2012-03-10 13:00:08 -0800 | [diff] [blame] | 540 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 
|  | 541 | "%s bad state = %d", __func__, trans->state); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 542 |  | 
| Emmanuel Grumbach | 6d8f6ee | 2011-08-25 23:11:06 -0700 | [diff] [blame] | 543 | return trans->ops->send_cmd(trans, cmd); | 
| Emmanuel Grumbach | bdfbf09 | 2011-07-08 08:46:16 -0700 | [diff] [blame] | 544 | } | 
|  | 545 |  | 
| Emmanuel Grumbach | 59c647b | 2012-05-24 19:24:34 +0300 | [diff] [blame] | 546 | static inline struct iwl_device_cmd * | 
|  | 547 | iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) | 
|  | 548 | { | 
|  | 549 | u8 *dev_cmd_ptr = kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); | 
|  | 550 |  | 
|  | 551 | if (unlikely(dev_cmd_ptr == NULL)) | 
|  | 552 | return NULL; | 
|  | 553 |  | 
|  | 554 | return (struct iwl_device_cmd *) | 
|  | 555 | (dev_cmd_ptr + trans->dev_cmd_headroom); | 
|  | 556 | } | 
|  | 557 |  | 
|  | 558 | static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, | 
|  | 559 | struct iwl_device_cmd *dev_cmd) | 
|  | 560 | { | 
|  | 561 | u8 *dev_cmd_ptr = (u8 *)dev_cmd - trans->dev_cmd_headroom; | 
|  | 562 |  | 
|  | 563 | kmem_cache_free(trans->dev_cmd_pool, dev_cmd_ptr); | 
|  | 564 | } | 
|  | 565 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 566 | static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 567 | struct iwl_device_cmd *dev_cmd, int queue) | 
| Emmanuel Grumbach | a0eaad7 | 2011-08-25 23:11:00 -0700 | [diff] [blame] | 568 | { | 
| Johannes Berg | f0d120a | 2012-03-10 13:00:08 -0800 | [diff] [blame] | 569 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 
|  | 570 | "%s bad state = %d", __func__, trans->state); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 571 |  | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 572 | return trans->ops->tx(trans, skb, dev_cmd, queue); | 
| Emmanuel Grumbach | a0eaad7 | 2011-08-25 23:11:00 -0700 | [diff] [blame] | 573 | } | 
|  | 574 |  | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 575 | static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, | 
|  | 576 | int ssn, struct sk_buff_head *skbs) | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 577 | { | 
| Johannes Berg | f0d120a | 2012-03-10 13:00:08 -0800 | [diff] [blame] | 578 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 
|  | 579 | "%s bad state = %d", __func__, trans->state); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 580 |  | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 581 | trans->ops->reclaim(trans, queue, ssn, skbs); | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 582 | } | 
|  | 583 |  | 
| Emmanuel Grumbach | d0624be | 2012-05-29 13:07:30 +0300 | [diff] [blame] | 584 | static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue) | 
| Emmanuel Grumbach | 288712a | 2011-08-25 23:11:25 -0700 | [diff] [blame] | 585 | { | 
| Johannes Berg | f0d120a | 2012-03-10 13:00:08 -0800 | [diff] [blame] | 586 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 
|  | 587 | "%s bad state = %d", __func__, trans->state); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 588 |  | 
| Emmanuel Grumbach | d0624be | 2012-05-29 13:07:30 +0300 | [diff] [blame] | 589 | trans->ops->txq_disable(trans, queue); | 
| Emmanuel Grumbach | 288712a | 2011-08-25 23:11:25 -0700 | [diff] [blame] | 590 | } | 
|  | 591 |  | 
| Emmanuel Grumbach | 4beaf6c | 2012-05-29 11:29:10 +0300 | [diff] [blame] | 592 | static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, | 
|  | 593 | int fifo, int sta_id, int tid, | 
|  | 594 | int frame_limit, u16 ssn) | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 595 | { | 
| Emmanuel Grumbach | 6039618 | 2012-02-06 16:41:58 +0200 | [diff] [blame] | 596 | might_sleep(); | 
|  | 597 |  | 
| Johannes Berg | f0d120a | 2012-03-10 13:00:08 -0800 | [diff] [blame] | 598 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 
|  | 599 | "%s bad state = %d", __func__, trans->state); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 600 |  | 
| Emmanuel Grumbach | 4beaf6c | 2012-05-29 11:29:10 +0300 | [diff] [blame] | 601 | trans->ops->txq_enable(trans, queue, fifo, sta_id, tid, | 
| Johannes Berg | 9eae88f | 2012-03-15 13:26:52 -0700 | [diff] [blame] | 602 | frame_limit, ssn); | 
| Emmanuel Grumbach | 48d42c4 | 2011-07-10 10:47:01 +0300 | [diff] [blame] | 603 | } | 
|  | 604 |  | 
| Emmanuel Grumbach | b04db9a | 2012-06-21 11:53:44 +0300 | [diff] [blame] | 605 | static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, | 
|  | 606 | int fifo) | 
|  | 607 | { | 
|  | 608 | iwl_trans_txq_enable(trans, queue, fifo, IWL_INVALID_STATION, | 
|  | 609 | IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); | 
|  | 610 | } | 
|  | 611 |  | 
| Emmanuel Grumbach | 5f178cd | 2011-08-25 23:11:29 -0700 | [diff] [blame] | 612 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) | 
|  | 613 | { | 
| Johannes Berg | f0d120a | 2012-03-10 13:00:08 -0800 | [diff] [blame] | 614 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 
|  | 615 | "%s bad state = %d", __func__, trans->state); | 
| Emmanuel Grumbach | 69655eb | 2012-02-06 14:30:54 +0200 | [diff] [blame] | 616 |  | 
| Emmanuel Grumbach | 5f178cd | 2011-08-25 23:11:29 -0700 | [diff] [blame] | 617 | return trans->ops->wait_tx_queue_empty(trans); | 
|  | 618 | } | 
|  | 619 |  | 
| Emmanuel Grumbach | 87e5666 | 2011-08-25 23:10:50 -0700 | [diff] [blame] | 620 | static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, | 
|  | 621 | struct dentry *dir) | 
|  | 622 | { | 
|  | 623 | return trans->ops->dbgfs_register(trans, dir); | 
|  | 624 | } | 
|  | 625 |  | 
| Johannes Berg | c01a404 | 2011-09-15 11:46:45 -0700 | [diff] [blame] | 626 | #ifdef CONFIG_PM_SLEEP | 
| Emmanuel Grumbach | 57210f7 | 2011-08-25 23:10:52 -0700 | [diff] [blame] | 627 | static inline int iwl_trans_suspend(struct iwl_trans *trans) | 
|  | 628 | { | 
|  | 629 | return trans->ops->suspend(trans); | 
|  | 630 | } | 
|  | 631 |  | 
|  | 632 | static inline int iwl_trans_resume(struct iwl_trans *trans) | 
|  | 633 | { | 
|  | 634 | return trans->ops->resume(trans); | 
|  | 635 | } | 
| Johannes Berg | c01a404 | 2011-09-15 11:46:45 -0700 | [diff] [blame] | 636 | #endif | 
| Emmanuel Grumbach | 57210f7 | 2011-08-25 23:10:52 -0700 | [diff] [blame] | 637 |  | 
| Emmanuel Grumbach | 0390549 | 2012-01-03 13:48:07 +0200 | [diff] [blame] | 638 | static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) | 
|  | 639 | { | 
|  | 640 | trans->ops->write8(trans, ofs, val); | 
|  | 641 | } | 
|  | 642 |  | 
|  | 643 | static inline void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) | 
|  | 644 | { | 
|  | 645 | trans->ops->write32(trans, ofs, val); | 
|  | 646 | } | 
|  | 647 |  | 
|  | 648 | static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) | 
|  | 649 | { | 
|  | 650 | return trans->ops->read32(trans, ofs); | 
|  | 651 | } | 
|  | 652 |  | 
| Don Fry | 47107e8 | 2012-03-15 13:27:06 -0700 | [diff] [blame] | 653 | static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) | 
|  | 654 | { | 
|  | 655 | trans->ops->set_pmi(trans, state); | 
|  | 656 | } | 
|  | 657 |  | 
| Emmanuel Grumbach | e6bb4c9 | 2011-08-25 23:10:48 -0700 | [diff] [blame] | 658 | /***************************************************** | 
| Johannes Berg | d1ff525 | 2012-04-12 06:24:30 -0700 | [diff] [blame] | 659 | * driver (transport) register/unregister functions | 
| Emmanuel Grumbach | b52e7ea | 2012-02-02 14:16:59 -0800 | [diff] [blame] | 660 | ******************************************************/ | 
| Emmanuel Grumbach | 36a7922 | 2012-02-27 13:53:32 -0800 | [diff] [blame] | 661 | int __must_check iwl_pci_register_driver(void); | 
|  | 662 | void iwl_pci_unregister_driver(void); | 
| Emmanuel Grumbach | b52e7ea | 2012-02-02 14:16:59 -0800 | [diff] [blame] | 663 |  | 
| Emmanuel Grumbach | 41c5054 | 2011-07-11 08:51:04 +0300 | [diff] [blame] | 664 | #endif /* __iwl_trans_h__ */ |