aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/sdio-fw.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-05-07 04:02:39 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-06-11 06:30:25 -0400
commit16820c166d3ad5973d388b5aa70ee7e535386657 (patch)
tree59ccd86e6530bbfc6aac3d55a4952f851c0bc3cc /drivers/net/wimax/i2400m/sdio-fw.c
parent6e053d6c79b3c1c9f6efc6563a811023c41be86a (diff)
wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine
The current SDIO code was working in polling mode for boot-mode (firmware load) mode. This was causing issues on some hardware. Moved all the RX code to use a unified IRQ handler that based on the type of data the device is sending can discriminate and decide which is the right destination. As well, all the reads from the device are made to be at least the block size (256); the driver will ignore the rest when not needed. Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com> Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax/i2400m/sdio-fw.c')
-rw-r--r--drivers/net/wimax/i2400m/sdio-fw.c109
1 files changed, 47 insertions, 62 deletions
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c
index 3487205d8f50..7d6ec0f475f8 100644
--- a/drivers/net/wimax/i2400m/sdio-fw.c
+++ b/drivers/net/wimax/i2400m/sdio-fw.c
@@ -46,17 +46,24 @@
46 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 46 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
47 * - SDIO rehash for changes in the bus-driver model 47 * - SDIO rehash for changes in the bus-driver model
48 * 48 *
49 * Dirk Brandewie <dirk.j.brandewie@intel.com>
50 * - Make it IRQ based, not polling
51 *
49 * THE PROCEDURE 52 * THE PROCEDURE
50 * 53 *
51 * See fw.c for the generic description of this procedure. 54 * See fw.c for the generic description of this procedure.
52 * 55 *
53 * This file implements only the SDIO specifics. It boils down to how 56 * This file implements only the SDIO specifics. It boils down to how
54 * to send a command and waiting for an acknowledgement from the 57 * to send a command and waiting for an acknowledgement from the
55 * device. We do polled reads. 58 * device.
59 *
60 * All this code is sequential -- all i2400ms_bus_bm_*() functions are
61 * executed in the same thread, except i2400ms_bm_irq() [on its own by
62 * the SDIO driver]. This makes it possible to avoid locking.
56 * 63 *
57 * COMMAND EXECUTION 64 * COMMAND EXECUTION
58 * 65 *
59 * THe generic firmware upload code will call i2400m_bus_bm_cmd_send() 66 * The generic firmware upload code will call i2400m_bus_bm_cmd_send()
60 * to send commands. 67 * to send commands.
61 * 68 *
62 * The SDIO devices expects things in 256 byte blocks, so it will pad 69 * The SDIO devices expects things in 256 byte blocks, so it will pad
@@ -64,12 +71,15 @@
64 * 71 *
65 * ACK RECEPTION 72 * ACK RECEPTION
66 * 73 *
67 * This works in polling mode -- the fw loader says when to wait for 74 * This works in IRQ mode -- the fw loader says when to wait for data
68 * data and for that it calls i2400ms_bus_bm_wait_for_ack(). 75 * and for that it calls i2400ms_bus_bm_wait_for_ack().
69 * 76 *
70 * This will poll the device for data until it is received. We need to 77 * This checks if there is any data available (RX size > 0); if not,
71 * receive at least as much bytes as where asked for (although it'll 78 * waits for the IRQ handler to notify about it. Once there is data,
72 * always be a multiple of 256 bytes). 79 * it is read and passed to the caller. Doing it this way we don't
80 * need much coordination/locking, and it makes it much more difficult
81 * for an interrupt to be lost and the wait_for_ack() function getting
82 * stuck even when data is pending.
73 */ 83 */
74#include <linux/mmc/sdio_func.h> 84#include <linux/mmc/sdio_func.h>
75#include "i2400m-sdio.h" 85#include "i2400m-sdio.h"
@@ -78,6 +88,7 @@
78#define D_SUBMODULE fw 88#define D_SUBMODULE fw
79#include "sdio-debug-levels.h" 89#include "sdio-debug-levels.h"
80 90
91
81/* 92/*
82 * Send a boot-mode command to the SDIO function 93 * Send a boot-mode command to the SDIO function
83 * 94 *
@@ -139,7 +150,7 @@ error_too_big:
139 150
140 151
141/* 152/*
142 * Read an ack from the device's boot-mode (polling) 153 * Read an ack from the device's boot-mode
143 * 154 *
144 * @i2400m: 155 * @i2400m:
145 * @_ack: pointer to where to store the read data 156 * @_ack: pointer to where to store the read data
@@ -150,75 +161,49 @@ error_too_big:
150 * The ACK for a BM command is always at least sizeof(*ack) bytes, so 161 * 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 162 * check for that. We don't need to check for device reboots
152 * 163 *
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 */ 164 */
157ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, 165ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
158 struct i2400m_bootrom_header *ack, 166 struct i2400m_bootrom_header *ack,
159 size_t ack_size) 167 size_t ack_size)
160{ 168{
161 int result; 169 ssize_t result;
162 ssize_t rx_size;
163 u64 timeout;
164 struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); 170 struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
165 struct sdio_func *func = i2400ms->func; 171 struct sdio_func *func = i2400ms->func;
166 struct device *dev = &func->dev; 172 struct device *dev = &func->dev;
173 int size;
167 174
168 BUG_ON(sizeof(*ack) > ack_size); 175 BUG_ON(sizeof(*ack) > ack_size);
169 176
170 d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", 177 d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
171 i2400m, ack, ack_size); 178 i2400m, ack, ack_size);
172 179
173 timeout = get_jiffies_64() + 2 * HZ; 180 spin_lock(&i2400m->rx_lock);
174 sdio_claim_host(func); 181 i2400ms->bm_ack_size = -EINPROGRESS;
175 while (1) { 182 spin_unlock(&i2400m->rx_lock);
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 183
182 /* Find the RX size, check if it fits or not -- it if 184 result = wait_event_timeout(i2400ms->bm_wfa_wq,
183 * doesn't fit, fail, as we have no way to dispose of 185 i2400ms->bm_ack_size != -EINPROGRESS,
184 * the extra data. */ 186 2 * HZ);
185 rx_size = __i2400ms_rx_get_size(i2400ms); 187 if (result == 0) {
186 if (rx_size < 0) 188 result = -ETIMEDOUT;
187 goto error_rx_get_size; 189 dev_err(dev, "BM: error waiting for an ack\n");
188 result = -ENOSPC; /* Check it fits */ 190 goto error_timeout;
189 if (rx_size < sizeof(*ack)) { 191 }
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 192
202 /* Read it */ 193 spin_lock(&i2400m->rx_lock);
203 result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf, 194 result = i2400ms->bm_ack_size;
204 I2400MS_DATA_ADDR, rx_size); 195 BUG_ON(result == -EINPROGRESS);
205 if (result == -ETIMEDOUT || result == -ETIME) 196 if (result < 0) /* so we exit when rx_release() is called */
206 continue; 197 dev_err(dev, "BM: %s failed: %zd\n", __func__, result);
207 if (result < 0) { 198 else {
208 dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n", 199 size = min(ack_size, i2400ms->bm_ack_size);
209 rx_size, result); 200 memcpy(ack, i2400m->bm_ack_buf, size);
210 goto error_read;
211 } else
212 break;
213 } 201 }
214 rx_size = min((ssize_t)ack_size, rx_size); 202 i2400ms->bm_ack_size = -EINPROGRESS;
215 memcpy(ack, i2400m->bm_ack_buf, rx_size); 203 spin_unlock(&i2400m->rx_lock);
216error_read: 204
217error_too_small: 205error_timeout:
218error_rx_get_size: 206 d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n",
219error_timedout: 207 i2400m, ack, ack_size, result);
220 sdio_release_host(func); 208 return result;
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} 209}