Merge branches 'x86-fixes-for-linus', 'sched-fixes-for-linus', 'timers-fixes-for...
[pandora-kernel.git] / drivers / net / wireless / iwmc3200wifi / hal.c
1 /*
2  * Intel Wireless Multicomm 3200 WiFi driver
3  *
4  * Copyright (C) 2009 Intel Corporation. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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
15  *     distribution.
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.
19  *
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.
31  *
32  *
33  * Intel Corporation <ilw@linux.intel.com>
34  * Samuel Ortiz <samuel.ortiz@intel.com>
35  * Zhu Yi <yi.zhu@intel.com>
36  *
37  */
38
39 /*
40  * Hardware Abstraction Layer for iwm.
41  *
42  * This file mostly defines an abstraction API for
43  * sending various commands to the target.
44  *
45  * We have 2 types of commands: wifi and non-wifi ones.
46  *
47  * - wifi commands:
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 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 laid out:
61  *    ------------------------
62  *   | iwm_udma_out_wifi_hdr  |
63  *    ------------------------
64  *   | SW meta_data (32 bits) |
65  *    ------------------------
66  *   | iwm_dev_cmd_hdr        |
67  *    ------------------------
68  *   | payload                |
69  *   | ....                   |
70  *
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 laid out:
76  *    ---------------------------
77  *   | iwm_udma_out_nonwifi_hdr  |
78  *    ---------------------------
79  *   | payload                   |
80  *   | ....                      |
81
82  *
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]).
88  *
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.
98  */
99 #include <linux/kernel.h>
100 #include <linux/netdevice.h>
101 #include <linux/slab.h>
102
103 #include "iwm.h"
104 #include "bus.h"
105 #include "hal.h"
106 #include "umac.h"
107 #include "debug.h"
108 #include "trace.h"
109
110 static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
111                                 struct iwm_nonwifi_cmd *cmd,
112                                 struct iwm_udma_nonwifi_cmd *udma_cmd)
113 {
114         INIT_LIST_HEAD(&cmd->pending);
115
116         spin_lock(&iwm->cmd_lock);
117
118         cmd->resp_received = 0;
119
120         cmd->seq_num = iwm->nonwifi_seq_num;
121         udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
122
123         iwm->nonwifi_seq_num++;
124         iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
125
126         if (udma_cmd->resp)
127                 list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd);
128
129         spin_unlock(&iwm->cmd_lock);
130
131         cmd->buf.start = cmd->buf.payload;
132         cmd->buf.len = 0;
133
134         memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
135
136         return cmd->seq_num;
137 }
138
139 u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
140 {
141         u16 seq_num = iwm->wifi_seq_num;
142
143         iwm->wifi_seq_num++;
144         iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX;
145
146         return seq_num;
147 }
148
149 static void iwm_wifi_cmd_init(struct iwm_priv *iwm,
150                               struct iwm_wifi_cmd *cmd,
151                               struct iwm_udma_wifi_cmd *udma_cmd,
152                               struct iwm_umac_cmd *umac_cmd,
153                               struct iwm_lmac_cmd *lmac_cmd,
154                               u16 payload_size)
155 {
156         INIT_LIST_HEAD(&cmd->pending);
157
158         spin_lock(&iwm->cmd_lock);
159
160         cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm);
161         umac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
162
163         if (umac_cmd->resp)
164                 list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd);
165
166         spin_unlock(&iwm->cmd_lock);
167
168         cmd->buf.start = cmd->buf.payload;
169         cmd->buf.len = 0;
170
171         if (lmac_cmd) {
172                 cmd->buf.start -= sizeof(struct iwm_lmac_hdr);
173
174                 lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
175                 lmac_cmd->count = cpu_to_le16(payload_size);
176
177                 memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd));
178
179                 umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr));
180         } else
181                 umac_cmd->count = 0;
182
183         umac_cmd->count = cpu_to_le16(payload_size +
184                                       le16_to_cpu(umac_cmd->count));
185         udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) +
186                                       le16_to_cpu(umac_cmd->count));
187
188         memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
189         memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd));
190 }
191
192 void iwm_cmd_flush(struct iwm_priv *iwm)
193 {
194         struct iwm_wifi_cmd *wcmd, *wnext;
195         struct iwm_nonwifi_cmd *nwcmd, *nwnext;
196
197         list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) {
198                 list_del(&wcmd->pending);
199                 kfree(wcmd);
200         }
201
202         list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd,
203                                  pending) {
204                 list_del(&nwcmd->pending);
205                 kfree(nwcmd);
206         }
207 }
208
209 struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
210 {
211         struct iwm_wifi_cmd *cmd;
212
213         list_for_each_entry(cmd, &iwm->wifi_pending_cmd, pending)
214                 if (cmd->seq_num == seq_num) {
215                         list_del(&cmd->pending);
216                         return cmd;
217                 }
218
219         return NULL;
220 }
221
222 struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm,
223                                                     u8 seq_num, u8 cmd_opcode)
224 {
225         struct iwm_nonwifi_cmd *cmd;
226
227         list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending)
228                 if ((cmd->seq_num == seq_num) &&
229                     (cmd->udma_cmd.opcode == cmd_opcode) &&
230                     (cmd->resp_received)) {
231                         list_del(&cmd->pending);
232                         return cmd;
233                 }
234
235         return NULL;
236 }
237
238 static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm,
239                                        struct iwm_udma_out_nonwifi_hdr *hdr,
240                                        struct iwm_udma_nonwifi_cmd *cmd)
241 {
242         memset(hdr, 0, sizeof(*hdr));
243
244         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode);
245         SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp);
246         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1);
247         SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW,
248                   cmd->handle_by_hw);
249         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
250         SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM,
251                   le16_to_cpu(cmd->seq_num));
252
253         hdr->addr = cmd->addr;
254         hdr->op1_sz = cmd->op1_sz;
255         hdr->op2 = cmd->op2;
256 }
257
258 static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm,
259                                      struct iwm_nonwifi_cmd *cmd)
260 {
261         struct iwm_udma_out_nonwifi_hdr *udma_hdr;
262         struct iwm_nonwifi_cmd_buff *buf;
263         struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd;
264
265         buf = &cmd->buf;
266
267         buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr);
268         buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr);
269
270         udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start);
271
272         iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd);
273
274         IWM_DBG_CMD(iwm, DBG,
275                     "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, "
276                     "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, "
277                     "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp,
278                     udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr,
279                     udma_cmd->op1_sz, udma_cmd->op2);
280
281         trace_iwm_tx_nonwifi_cmd(iwm, udma_hdr);
282         return iwm_bus_send_chunk(iwm, buf->start, buf->len);
283 }
284
285 void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop)
286 {
287         struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf;
288
289         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop);
290 }
291
292 void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
293                              struct iwm_udma_out_wifi_hdr *hdr,
294                              struct iwm_udma_wifi_cmd *cmd)
295 {
296         memset(hdr, 0, sizeof(*hdr));
297
298         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI);
299         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop);
300         SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
301
302         SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT,
303                   le16_to_cpu(cmd->count));
304         SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group);
305         SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid);
306         SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset);
307 }
308
309 void iwm_build_umac_hdr(struct iwm_priv *iwm,
310                         struct iwm_umac_fw_cmd_hdr *hdr,
311                         struct iwm_umac_cmd *cmd)
312 {
313         memset(hdr, 0, sizeof(*hdr));
314
315         SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT,
316                   le16_to_cpu(cmd->count));
317         SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color);
318         SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp);
319
320         hdr->cmd.cmd = cmd->id;
321         hdr->cmd.seq_num = cmd->seq_num;
322 }
323
324 static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm,
325                                   struct iwm_wifi_cmd *cmd)
326 {
327         struct iwm_umac_wifi_out_hdr *umac_hdr;
328         struct iwm_wifi_cmd_buff *buf;
329         struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd;
330         struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd;
331         int ret;
332
333         buf = &cmd->buf;
334
335         buf->start -= sizeof(struct iwm_umac_wifi_out_hdr);
336         buf->len += sizeof(struct iwm_umac_wifi_out_hdr);
337
338         umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start);
339
340         iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd);
341         iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd);
342
343         IWM_DBG_CMD(iwm, DBG,
344                     "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, "
345                     "eop = 0x%x, count = 0x%x, credit_group = 0x%x, "
346                     "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n",
347                     UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id,
348                     udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group,
349                     udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num);
350
351         if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH)
352                 IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n",
353                             cmd->lmac_cmd.id);
354
355         ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len);
356
357         /* We keep sending UMAC reset regardless of the command credits.
358          * The UMAC is supposed to be reset anyway and the Tx credits are
359          * reinitialized afterwards. If we are lucky, the reset could
360          * still be done even though we have run out of credits for the
361          * command pool at this moment.*/
362         if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) {
363                 IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n",
364                            umac_cmd->id);
365                 return ret;
366         }
367
368         trace_iwm_tx_wifi_cmd(iwm, umac_hdr);
369         return iwm_bus_send_chunk(iwm, buf->start, buf->len);
370 }
371
372 /* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */
373 int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
374                             struct iwm_udma_nonwifi_cmd *udma_cmd,
375                             const void *payload)
376 {
377         struct iwm_nonwifi_cmd *cmd;
378         int ret, seq_num;
379
380         cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
381         if (!cmd) {
382                 IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n");
383                 return -ENOMEM;
384         }
385
386         seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
387
388         if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
389             cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
390                 cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz);
391                 memcpy(&cmd->buf.payload, payload, cmd->buf.len);
392         }
393
394         ret = iwm_send_udma_nonwifi_cmd(iwm, cmd);
395
396         if (!udma_cmd->resp)
397                 kfree(cmd);
398
399         if (ret < 0)
400                 return ret;
401
402         return seq_num;
403 }
404
405 static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
406                                struct iwm_lmac_cmd *cmd)
407 {
408         memset(hdr, 0, sizeof(*hdr));
409
410         hdr->id = cmd->id;
411         hdr->flags = 0; /* Is this ever used? */
412         hdr->seq_num = cmd->seq_num;
413 }
414
415 /*
416  * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
417  * Sending command to the LMAC is equivalent to sending a
418  * regular UMAC command with the LMAC passthrough or the LMAC
419  * wrapper UMAC command IDs.
420  */
421 int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
422                           struct iwm_udma_wifi_cmd *udma_cmd,
423                           struct iwm_umac_cmd *umac_cmd,
424                           struct iwm_lmac_cmd *lmac_cmd,
425                           const void *payload, u16 payload_size)
426 {
427         struct iwm_wifi_cmd *cmd;
428         struct iwm_lmac_hdr *hdr;
429         int lmac_hdr_len = 0;
430         int ret;
431
432         cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL);
433         if (!cmd) {
434                 IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n");
435                 return -ENOMEM;
436         }
437
438         iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size);
439
440         if (lmac_cmd) {
441                 hdr = (struct iwm_lmac_hdr *)(cmd->buf.start);
442
443                 iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd);
444                 lmac_hdr_len = sizeof(struct iwm_lmac_hdr);
445         }
446
447         memcpy(cmd->buf.payload, payload, payload_size);
448         cmd->buf.len = le16_to_cpu(umac_cmd->count);
449
450         ret = iwm_send_udma_wifi_cmd(iwm, cmd);
451
452         /* We free the cmd if we're not expecting any response */
453         if (!umac_cmd->resp)
454                 kfree(cmd);
455         return ret;
456 }
457
458 /*
459  * iwm_hal_send_umac_cmd(): This is a special case for
460  * iwm_hal_send_host_cmd() to send direct UMAC cmd (without
461  * LMAC involved).
462  */
463 int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
464                           struct iwm_udma_wifi_cmd *udma_cmd,
465                           struct iwm_umac_cmd *umac_cmd,
466                           const void *payload, u16 payload_size)
467 {
468         return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL,
469                                      payload, payload_size);
470 }