2 * Intel Wireless Multicomm 3200 WiFi driver
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
40 * Hardware Abstraction Layer for iwm.
42 * This file mostly defines an abstraction API for
43 * sending various commands to the target.
45 * We have 2 types of commands: wifi and non-wifi ones.
48 * They are used for sending LMAC and UMAC commands,
49 * and thus are the most commonly used ones.
50 * There are 2 different wifi command types, the regular
51 * one and the LMAC one. The former is used to send
52 * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h)
53 * while the latter is used for sending commands to the
54 * LMAC. If you look at LMAC commands you'll se that they
55 * are actually regular iwlwifi target commands encapsulated
56 * into a special UMAC command called UMAC passthrough.
57 * This is due to the fact the the host talks exclusively
58 * to the UMAC and so there needs to be a special UMAC
59 * command for talking to the LMAC.
60 * This is how a wifi command is layed out:
61 * ------------------------
62 * | iwm_udma_out_wifi_hdr |
63 * ------------------------
64 * | SW meta_data (32 bits) |
65 * ------------------------
67 * ------------------------
71 * - non-wifi, or general commands:
72 * Those commands are handled by the device's bootrom,
73 * and are typically sent when the UMAC and the LMAC
74 * are not yet available.
75 * * This is how a non-wifi command is layed out:
76 * ---------------------------
77 * | iwm_udma_out_nonwifi_hdr |
78 * ---------------------------
83 * All the commands start with a UDMA header, which is
84 * basically a 32 bits field. The 4 LSB there define
85 * an opcode that allows the target to differentiate
86 * between wifi (opcode is 0xf) and non-wifi commands
87 * (opcode is [0..0xe]).
89 * When a command (wifi or non-wifi) is supposed to receive
90 * an answer, we queue the command buffer. When we do receive
91 * a command response from the UMAC, we go through the list
92 * of pending command, and pass both the command and the answer
93 * to the rx handler. Each command is sent with a unique
94 * sequence id, and the answer is sent with the same one. This
95 * is how we're supposed to match an answer with its command.
96 * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi()
97 * for the implementation details.
99 #include <linux/kernel.h>
100 #include <linux/netdevice.h>
108 static void iwm_nonwifi_cmd_init(struct iwm_priv
*iwm
,
109 struct iwm_nonwifi_cmd
*cmd
,
110 struct iwm_udma_nonwifi_cmd
*udma_cmd
)
112 INIT_LIST_HEAD(&cmd
->pending
);
114 spin_lock(&iwm
->cmd_lock
);
116 cmd
->resp_received
= 0;
118 cmd
->seq_num
= iwm
->nonwifi_seq_num
;
119 udma_cmd
->seq_num
= cpu_to_le16(cmd
->seq_num
);
121 cmd
->seq_num
= iwm
->nonwifi_seq_num
++;
122 iwm
->nonwifi_seq_num
%= UMAC_NONWIFI_SEQ_NUM_MAX
;
125 list_add_tail(&cmd
->pending
, &iwm
->nonwifi_pending_cmd
);
127 spin_unlock(&iwm
->cmd_lock
);
129 cmd
->buf
.start
= cmd
->buf
.payload
;
132 memcpy(&cmd
->udma_cmd
, udma_cmd
, sizeof(*udma_cmd
));
135 u16
iwm_alloc_wifi_cmd_seq(struct iwm_priv
*iwm
)
137 u16 seq_num
= iwm
->wifi_seq_num
;
140 iwm
->wifi_seq_num
%= UMAC_WIFI_SEQ_NUM_MAX
;
145 static void iwm_wifi_cmd_init(struct iwm_priv
*iwm
,
146 struct iwm_wifi_cmd
*cmd
,
147 struct iwm_udma_wifi_cmd
*udma_cmd
,
148 struct iwm_umac_cmd
*umac_cmd
,
149 struct iwm_lmac_cmd
*lmac_cmd
,
152 INIT_LIST_HEAD(&cmd
->pending
);
154 spin_lock(&iwm
->cmd_lock
);
156 cmd
->seq_num
= iwm_alloc_wifi_cmd_seq(iwm
);
157 umac_cmd
->seq_num
= cpu_to_le16(cmd
->seq_num
);
160 list_add_tail(&cmd
->pending
, &iwm
->wifi_pending_cmd
);
162 spin_unlock(&iwm
->cmd_lock
);
164 cmd
->buf
.start
= cmd
->buf
.payload
;
168 cmd
->buf
.start
-= sizeof(struct iwm_lmac_hdr
);
170 lmac_cmd
->seq_num
= cpu_to_le16(cmd
->seq_num
);
171 lmac_cmd
->count
= cpu_to_le16(payload_size
);
173 memcpy(&cmd
->lmac_cmd
, lmac_cmd
, sizeof(*lmac_cmd
));
175 umac_cmd
->count
= cpu_to_le16(sizeof(struct iwm_lmac_hdr
));
179 umac_cmd
->count
= cpu_to_le16(payload_size
+
180 le16_to_cpu(umac_cmd
->count
));
181 udma_cmd
->count
= cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr
) +
182 le16_to_cpu(umac_cmd
->count
));
184 memcpy(&cmd
->udma_cmd
, udma_cmd
, sizeof(*udma_cmd
));
185 memcpy(&cmd
->umac_cmd
, umac_cmd
, sizeof(*umac_cmd
));
188 void iwm_cmd_flush(struct iwm_priv
*iwm
)
190 struct iwm_wifi_cmd
*wcmd
, *wnext
;
191 struct iwm_nonwifi_cmd
*nwcmd
, *nwnext
;
193 list_for_each_entry_safe(wcmd
, wnext
, &iwm
->wifi_pending_cmd
, pending
) {
194 list_del(&wcmd
->pending
);
198 list_for_each_entry_safe(nwcmd
, nwnext
, &iwm
->nonwifi_pending_cmd
,
200 list_del(&nwcmd
->pending
);
205 struct iwm_wifi_cmd
*iwm_get_pending_wifi_cmd(struct iwm_priv
*iwm
, u16 seq_num
)
207 struct iwm_wifi_cmd
*cmd
, *next
;
209 list_for_each_entry_safe(cmd
, next
, &iwm
->wifi_pending_cmd
, pending
)
210 if (cmd
->seq_num
== seq_num
) {
211 list_del(&cmd
->pending
);
218 struct iwm_nonwifi_cmd
*
219 iwm_get_pending_nonwifi_cmd(struct iwm_priv
*iwm
, u8 seq_num
, u8 cmd_opcode
)
221 struct iwm_nonwifi_cmd
*cmd
, *next
;
223 list_for_each_entry_safe(cmd
, next
, &iwm
->nonwifi_pending_cmd
, pending
)
224 if ((cmd
->seq_num
== seq_num
) &&
225 (cmd
->udma_cmd
.opcode
== cmd_opcode
) &&
226 (cmd
->resp_received
)) {
227 list_del(&cmd
->pending
);
234 static void iwm_build_udma_nonwifi_hdr(struct iwm_priv
*iwm
,
235 struct iwm_udma_out_nonwifi_hdr
*hdr
,
236 struct iwm_udma_nonwifi_cmd
*cmd
)
238 memset(hdr
, 0, sizeof(*hdr
));
240 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_OPCODE
, cmd
->opcode
);
241 SET_VAL32(hdr
->cmd
, UDMA_HDI_OUT_NW_CMD_RESP
, cmd
->resp
);
242 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_EOT
, 1);
243 SET_VAL32(hdr
->cmd
, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW
,
245 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_SIGNATURE
, UMAC_HDI_OUT_SIGNATURE
);
246 SET_VAL32(hdr
->cmd
, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM
,
247 le16_to_cpu(cmd
->seq_num
));
249 hdr
->addr
= cmd
->addr
;
250 hdr
->op1_sz
= cmd
->op1_sz
;
254 static int iwm_send_udma_nonwifi_cmd(struct iwm_priv
*iwm
,
255 struct iwm_nonwifi_cmd
*cmd
)
257 struct iwm_udma_out_nonwifi_hdr
*udma_hdr
;
258 struct iwm_nonwifi_cmd_buff
*buf
;
259 struct iwm_udma_nonwifi_cmd
*udma_cmd
= &cmd
->udma_cmd
;
263 buf
->start
-= sizeof(struct iwm_umac_nonwifi_out_hdr
);
264 buf
->len
+= sizeof(struct iwm_umac_nonwifi_out_hdr
);
266 udma_hdr
= (struct iwm_udma_out_nonwifi_hdr
*)(buf
->start
);
268 iwm_build_udma_nonwifi_hdr(iwm
, udma_hdr
, udma_cmd
);
270 IWM_DBG_CMD(iwm
, DBG
,
271 "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, "
272 "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, "
273 "op2 = 0x%x\n", udma_cmd
->opcode
, udma_cmd
->resp
,
274 udma_cmd
->handle_by_hw
, cmd
->seq_num
, udma_cmd
->addr
,
275 udma_cmd
->op1_sz
, udma_cmd
->op2
);
277 return iwm_bus_send_chunk(iwm
, buf
->start
, buf
->len
);
280 void iwm_udma_wifi_hdr_set_eop(struct iwm_priv
*iwm
, u8
*buf
, u8 eop
)
282 struct iwm_udma_out_wifi_hdr
*hdr
= (struct iwm_udma_out_wifi_hdr
*)buf
;
284 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_EOT
, eop
);
287 void iwm_build_udma_wifi_hdr(struct iwm_priv
*iwm
,
288 struct iwm_udma_out_wifi_hdr
*hdr
,
289 struct iwm_udma_wifi_cmd
*cmd
)
291 memset(hdr
, 0, sizeof(*hdr
));
293 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_OPCODE
, UMAC_HDI_OUT_OPCODE_WIFI
);
294 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_EOT
, cmd
->eop
);
295 SET_VAL32(hdr
->cmd
, UMAC_HDI_OUT_CMD_SIGNATURE
, UMAC_HDI_OUT_SIGNATURE
);
297 SET_VAL32(hdr
->meta_data
, UMAC_HDI_OUT_BYTE_COUNT
,
298 le16_to_cpu(cmd
->count
));
299 SET_VAL32(hdr
->meta_data
, UMAC_HDI_OUT_CREDIT_GRP
, cmd
->credit_group
);
300 SET_VAL32(hdr
->meta_data
, UMAC_HDI_OUT_RATID
, cmd
->ra_tid
);
301 SET_VAL32(hdr
->meta_data
, UMAC_HDI_OUT_LMAC_OFFSET
, cmd
->lmac_offset
);
304 void iwm_build_umac_hdr(struct iwm_priv
*iwm
,
305 struct iwm_umac_fw_cmd_hdr
*hdr
,
306 struct iwm_umac_cmd
*cmd
)
308 memset(hdr
, 0, sizeof(*hdr
));
310 SET_VAL32(hdr
->meta_data
, UMAC_FW_CMD_BYTE_COUNT
,
311 le16_to_cpu(cmd
->count
));
312 SET_VAL32(hdr
->meta_data
, UMAC_FW_CMD_TX_STA_COLOR
, cmd
->color
);
313 SET_VAL8(hdr
->cmd
.flags
, UMAC_DEV_CMD_FLAGS_RESP_REQ
, cmd
->resp
);
315 hdr
->cmd
.cmd
= cmd
->id
;
316 hdr
->cmd
.seq_num
= cmd
->seq_num
;
319 static int iwm_send_udma_wifi_cmd(struct iwm_priv
*iwm
,
320 struct iwm_wifi_cmd
*cmd
)
322 struct iwm_umac_wifi_out_hdr
*umac_hdr
;
323 struct iwm_wifi_cmd_buff
*buf
;
324 struct iwm_udma_wifi_cmd
*udma_cmd
= &cmd
->udma_cmd
;
325 struct iwm_umac_cmd
*umac_cmd
= &cmd
->umac_cmd
;
330 buf
->start
-= sizeof(struct iwm_umac_wifi_out_hdr
);
331 buf
->len
+= sizeof(struct iwm_umac_wifi_out_hdr
);
333 umac_hdr
= (struct iwm_umac_wifi_out_hdr
*)(buf
->start
);
335 iwm_build_udma_wifi_hdr(iwm
, &umac_hdr
->hw_hdr
, udma_cmd
);
336 iwm_build_umac_hdr(iwm
, &umac_hdr
->sw_hdr
, umac_cmd
);
338 IWM_DBG_CMD(iwm
, DBG
,
339 "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, "
340 "eop = 0x%x, count = 0x%x, credit_group = 0x%x, "
341 "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n",
342 UMAC_HDI_OUT_OPCODE_WIFI
, umac_cmd
->id
,
343 udma_cmd
->eop
, udma_cmd
->count
, udma_cmd
->credit_group
,
344 udma_cmd
->ra_tid
, udma_cmd
->lmac_offset
, cmd
->seq_num
);
346 if (umac_cmd
->id
== UMAC_CMD_OPCODE_WIFI_PASS_THROUGH
)
347 IWM_DBG_CMD(iwm
, DBG
, "\tLMAC opcode: 0x%x\n",
350 ret
= iwm_tx_credit_alloc(iwm
, udma_cmd
->credit_group
, buf
->len
);
352 /* We keep sending UMAC reset regardless of the command credits.
353 * The UMAC is supposed to be reset anyway and the Tx credits are
354 * reinitialized afterwards. If we are lucky, the reset could
355 * still be done even though we have run out of credits for the
356 * command pool at this moment.*/
357 if (ret
&& (umac_cmd
->id
!= UMAC_CMD_OPCODE_RESET
)) {
358 IWM_DBG_TX(iwm
, DBG
, "Failed to alloc tx credit for cmd %d\n",
363 return iwm_bus_send_chunk(iwm
, buf
->start
, buf
->len
);
366 /* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */
367 int iwm_hal_send_target_cmd(struct iwm_priv
*iwm
,
368 struct iwm_udma_nonwifi_cmd
*udma_cmd
,
371 struct iwm_nonwifi_cmd
*cmd
;
374 cmd
= kzalloc(sizeof(struct iwm_nonwifi_cmd
), GFP_KERNEL
);
376 IWM_ERR(iwm
, "Couldn't alloc memory for hal cmd\n");
380 iwm_nonwifi_cmd_init(iwm
, cmd
, udma_cmd
);
382 if (cmd
->udma_cmd
.opcode
== UMAC_HDI_OUT_OPCODE_WRITE
||
383 cmd
->udma_cmd
.opcode
== UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT
) {
384 cmd
->buf
.len
= le32_to_cpu(cmd
->udma_cmd
.op1_sz
);
385 memcpy(&cmd
->buf
.payload
, payload
, cmd
->buf
.len
);
388 ret
= iwm_send_udma_nonwifi_cmd(iwm
, cmd
);
399 static void iwm_build_lmac_hdr(struct iwm_priv
*iwm
, struct iwm_lmac_hdr
*hdr
,
400 struct iwm_lmac_cmd
*cmd
)
402 memset(hdr
, 0, sizeof(*hdr
));
405 hdr
->flags
= 0; /* Is this ever used? */
406 hdr
->seq_num
= cmd
->seq_num
;
410 * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
411 * Sending command to the LMAC is equivalent to sending a
412 * regular UMAC command with the LMAC passtrough or the LMAC
413 * wrapper UMAC command IDs.
415 int iwm_hal_send_host_cmd(struct iwm_priv
*iwm
,
416 struct iwm_udma_wifi_cmd
*udma_cmd
,
417 struct iwm_umac_cmd
*umac_cmd
,
418 struct iwm_lmac_cmd
*lmac_cmd
,
419 const void *payload
, u16 payload_size
)
421 struct iwm_wifi_cmd
*cmd
;
422 struct iwm_lmac_hdr
*hdr
;
423 int lmac_hdr_len
= 0;
426 cmd
= kzalloc(sizeof(struct iwm_wifi_cmd
), GFP_KERNEL
);
428 IWM_ERR(iwm
, "Couldn't alloc memory for wifi hal cmd\n");
432 iwm_wifi_cmd_init(iwm
, cmd
, udma_cmd
, umac_cmd
, lmac_cmd
, payload_size
);
435 hdr
= (struct iwm_lmac_hdr
*)(cmd
->buf
.start
);
437 iwm_build_lmac_hdr(iwm
, hdr
, &cmd
->lmac_cmd
);
438 lmac_hdr_len
= sizeof(struct iwm_lmac_hdr
);
441 memcpy(cmd
->buf
.payload
, payload
, payload_size
);
442 cmd
->buf
.len
= le16_to_cpu(umac_cmd
->count
);
444 ret
= iwm_send_udma_wifi_cmd(iwm
, cmd
);
446 /* We free the cmd if we're not expecting any response */
453 * iwm_hal_send_umac_cmd(): This is a special case for
454 * iwm_hal_send_host_cmd() to send direct UMAC cmd (without
457 int iwm_hal_send_umac_cmd(struct iwm_priv
*iwm
,
458 struct iwm_udma_wifi_cmd
*udma_cmd
,
459 struct iwm_umac_cmd
*umac_cmd
,
460 const void *payload
, u16 payload_size
)
462 return iwm_hal_send_host_cmd(iwm
, udma_cmd
, umac_cmd
, NULL
,
463 payload
, payload_size
);