Merge branch 'topic/asoc' into for-linus
[linux-2.6] / drivers / net / wimax / i2400m / sdio-fw.c
1 /*
2  * Intel Wireless WiMAX Connection 2400m
3  * Firmware uploader's SDIO specifics
4  *
5  *
6  * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in
16  *     the documentation and/or other materials provided with the
17  *     distribution.
18  *   * Neither the name of Intel Corporation nor the names of its
19  *     contributors may be used to endorse or promote products derived
20  *     from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  *
35  * Intel Corporation <linux-wimax@intel.com>
36  * Yanir Lubetkin <yanirx.lubetkin@intel.com>
37  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
38  *  - Initial implementation
39  *
40  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
41  *  - Bus generic/specific split for USB
42  *
43  * Dirk Brandewie <dirk.j.brandewie@intel.com>
44  *  - Initial implementation for SDIO
45  *
46  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
47  *  - SDIO rehash for changes in the bus-driver model
48  *
49  * THE PROCEDURE
50  *
51  * See fw.c for the generic description of this procedure.
52  *
53  * This file implements only the SDIO specifics. It boils down to how
54  * to send a command and waiting for an acknowledgement from the
55  * device. We do polled reads.
56  *
57  * COMMAND EXECUTION
58  *
59  * THe generic firmware upload code will call i2400m_bus_bm_cmd_send()
60  * to send commands.
61  *
62  * The SDIO devices expects things in 256 byte blocks, so it will pad
63  * it, compute the checksum (if needed) and pass it to SDIO.
64  *
65  * ACK RECEPTION
66  *
67  * This works in polling mode -- the fw loader says when to wait for
68  * data and for that it calls i2400ms_bus_bm_wait_for_ack().
69  *
70  * This will poll the device for data until it is received. We need to
71  * receive at least as much bytes as where asked for (although it'll
72  * always be a multiple of 256 bytes).
73  */
74 #include <linux/mmc/sdio_func.h>
75 #include "i2400m-sdio.h"
76
77
78 #define D_SUBMODULE fw
79 #include "sdio-debug-levels.h"
80
81 /*
82  * Send a boot-mode command to the SDIO function
83  *
84  * We use a bounce buffer (i2400m->bm_cmd_buf) because we need to
85  * touch the header if the RAW flag is not set.
86  *
87  * @flags: pass thru from i2400m_bm_cmd()
88  * @return: cmd_size if ok, < 0 errno code on error.
89  *
90  * Note the command is padded to the SDIO block size for the device.
91  */
92 ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
93                                 const struct i2400m_bootrom_header *_cmd,
94                                 size_t cmd_size, int flags)
95 {
96         ssize_t result;
97         struct device *dev = i2400m_dev(i2400m);
98         struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
99         int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
100         struct i2400m_bootrom_header *cmd;
101         /* SDIO restriction */
102         size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE);
103
104         d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n",
105                   i2400m, _cmd, cmd_size);
106         result = -E2BIG;
107         if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
108                 goto error_too_big;
109
110         memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size);     /* Prep command */
111         cmd = i2400m->bm_cmd_buf;
112         if (cmd_size_a > cmd_size)                      /* Zero pad space */
113                 memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
114         if ((flags & I2400M_BM_CMD_RAW) == 0) {
115                 if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
116                         dev_warn(dev, "SW BUG: response_required == 0\n");
117                 i2400m_bm_cmd_prepare(cmd);
118         }
119         d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n",
120                  opcode, cmd_size, cmd_size_a);
121         d_dump(5, dev, cmd, cmd_size);
122
123         sdio_claim_host(i2400ms->func);                 /* Send & check */
124         result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR,
125                                   i2400m->bm_cmd_buf, cmd_size_a);
126         sdio_release_host(i2400ms->func);
127         if (result < 0) {
128                 dev_err(dev, "BM cmd %d: cannot send: %ld\n",
129                         opcode, (long) result);
130                 goto error_cmd_send;
131         }
132         result = cmd_size;
133 error_cmd_send:
134 error_too_big:
135         d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n",
136                 i2400m, _cmd, cmd_size, (int) result);
137         return result;
138 }
139
140
141 /*
142  * Read an ack from the device's boot-mode (polling)
143  *
144  * @i2400m:
145  * @_ack: pointer to where to store the read data
146  * @ack_size: how many bytes we should read
147  *
148  * Returns: < 0 errno code on error; otherwise, amount of received bytes.
149  *
150  * The ACK for a BM command is always at least sizeof(*ack) bytes, so
151  * check for that. We don't need to check for device reboots
152  *
153  * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout;
154  *     this way we have control over it...there is no way that I know
155  *     of setting an SDIO transaction timeout.
156  */
157 ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
158                                     struct i2400m_bootrom_header *ack,
159                                     size_t ack_size)
160 {
161         int result;
162         ssize_t rx_size;
163         u64 timeout;
164         struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
165         struct sdio_func *func = i2400ms->func;
166         struct device *dev = &func->dev;
167
168         BUG_ON(sizeof(*ack) > ack_size);
169
170         d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
171                   i2400m, ack, ack_size);
172
173         timeout = get_jiffies_64() + 2 * HZ;
174         sdio_claim_host(func);
175         while (1) {
176                 if (time_after64(get_jiffies_64(), timeout)) {
177                         rx_size = -ETIMEDOUT;
178                         dev_err(dev, "timeout waiting for ack data\n");
179                         goto error_timedout;
180                 }
181
182                 /* Find the RX size, check if it fits or not -- it if
183                  * doesn't fit, fail, as we have no way to dispose of
184                  * the extra data. */
185                 rx_size = __i2400ms_rx_get_size(i2400ms);
186                 if (rx_size < 0)
187                         goto error_rx_get_size;
188                 result = -ENOSPC;               /* Check it fits */
189                 if (rx_size < sizeof(*ack)) {
190                         rx_size = -EIO;
191                         dev_err(dev, "HW BUG? received is too small (%zu vs "
192                                 "%zu needed)\n", sizeof(*ack), rx_size);
193                         goto error_too_small;
194                 }
195                 if (rx_size > I2400M_BM_ACK_BUF_SIZE) {
196                         dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs "
197                                 "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE,
198                                 rx_size);
199                         goto error_too_small;
200                 }
201
202                 /* Read it */
203                 result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf,
204                                             I2400MS_DATA_ADDR, rx_size);
205                 if (result == -ETIMEDOUT || result == -ETIME)
206                         continue;
207                 if (result < 0) {
208                         dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n",
209                                 rx_size, result);
210                         goto error_read;
211                 } else
212                         break;
213         }
214         rx_size = min((ssize_t)ack_size, rx_size);
215         memcpy(ack, i2400m->bm_ack_buf, rx_size);
216 error_read:
217 error_too_small:
218 error_rx_get_size:
219 error_timedout:
220         sdio_release_host(func);
221         d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n",
222                 i2400m, ack, ack_size, (long) rx_size);
223         return rx_size;
224 }